DevSquad

Der DevSquad ist ein wöchentlicher Termin an dem sich unser Team über spannende neue Technologien, Tricks, Kniffe und Überraschungen im Entwicklungsalltag austauscht.

Wir sammeln diese Themen in einem Gitlab Repository und haben sie hier für euch aufbereitet damit ihr auch etwas davon habt.

MonsterMash- Open Source Animationstool (Computergrafik)

"We present a new framework for sketch-based modeling and animation of 3D organic shapes that can work entirely in an intuitive 2D domain, enabling a playful, casual experience. Unlike previous sketch-based tools, our approach does not require a tedious part-based multi-view workflow with the explicit specification of an animation rig. Instead, we combine 3D inflation with a novel rigidity-preserving, layered deformation model, ARAP-L, to produce a smooth 3D mesh that is immediately ready for animation." Hauptsächlich mit C++ gebaut. https://dcgi.fel.cvut.cz/home/sykorad/monster_mash Gibt eine Übersicht über das Tool sowie den Code und das dazugehörige Abstract etc. monstermash.zone ist die Demo des Tools im Browser.

Valerie Schramm - 7.4.2021
Tool

Chain of Responsibility

The chain of responsibility pattern contains two main building blocks. Command objects and a series of processing objects that can be responsible for reacting to a command object. Examples are the servlet filter in Spring or HttpInterceptors in Angular. Both consist of a chain of processing objects that pass a command object, e.g. a request from a client, through it. If a processing object feels responsible for reacting to that command it can do so. Afterwards the command object is passed to the next processing object down the chain. In a strict implementation according to the GoF only one processing object should be responsible for a certain command object, however, in most cases this rule is softened.

image

import java.util.Arrays;
import java.util.EnumSet;
import java.util.function.Consumer;

@FunctionalInterface
public interface Logger {
    public enum LogLevel {
        INFO, DEBUG, WARNING, ERROR, FUNCTIONAL_MESSAGE, FUNCTIONAL_ERROR;

        public static LogLevel[] all() {
            return values();
        }
    }

    abstract void message(String msg, LogLevel severity);

    default Logger appendNext(Logger nextLogger) {
        return (msg, severity) -> {
            message(msg, severity);
            nextLogger.message(msg, severity);
        };
    }

    static Logger writeLogger(LogLevel[] levels, Consumer<String> stringConsumer) {
        EnumSet<LogLevel> set = EnumSet.copyOf(Arrays.asList(levels));
        return (msg, severity) -> {
            if (set.contains(severity)) {
                stringConsumer.accept(msg);
            }
        };
    }

    static Logger consoleLogger(LogLevel... levels) {
        return writeLogger(levels, msg -> System.err.println("Writing to console: " + msg));
    }

    static Logger emailLogger(LogLevel... levels) {
        return writeLogger(levels, msg -> System.err.println("Sending via email: " + msg));
    }

    static Logger fileLogger(LogLevel... levels) {
        return writeLogger(levels, msg -> System.err.println("Writing to Log File: " + msg));
    }

    public static void main(String[] args) {
        // Build an immutable chain of responsibility
        Logger logger = consoleLogger(LogLevel.all())
                .appendNext(emailLogger(LogLevel.FUNCTIONAL_MESSAGE, LogLevel.FUNCTIONAL_ERROR))
                .appendNext(fileLogger(LogLevel.WARNING, LogLevel.ERROR));

        // Handled by consoleLogger since the console has a LogLevel of all
        logger.message("Entering function ProcessOrder().", LogLevel.DEBUG);
        logger.message("Order record retrieved.", LogLevel.INFO);

        // Handled by consoleLogger and emailLogger since emailLogger implements Functional_Error & Functional_Message
        logger.message("Unable to Process Order ORD1 Dated D1 For Customer C1.", LogLevel.FUNCTIONAL_ERROR);
        logger.message("Order Dispatched.", LogLevel.FUNCTIONAL_MESSAGE);

        // Handled by consoleLogger and fileLogger since fileLogger implements Warning & Error
        logger.message("Customer Address details missing in Branch DataBase.", LogLevel.WARNING);
        logger.message("Customer Address details missing in Organization DataBase.", LogLevel.ERROR);
    }
}
Sven Röttering - 7.4.2021
Design Patterns

Singleton

The Singleton pattern describes the practice of restricting the instantiation of a class to one "single" instance. This is useful when exactly one object is needed to coordinate actions across the system.

public class Singleton {
  private static Singleton instance;
  
  private Singleton () {}

  public static Singleton getInstance () {
    if (Singleton.instance == null) {
      Singleton.instance = new Singleton ();
    }
    return Singleton.instance;
  }

}
Sven Röttering - 7.4.2021
Design Patterns

Flux pattern

Most frontend frameworks/libraries like Angular, React and Vue use a component based approach. This is great when it comes to reusability and flexibility. In larger apps this can, however, lead to new problems. One of them is a confusing and unstructured data flow. Since components are layed out in a tree structure propagating data changes to other components requires to traverse the tree up to the closest common parent and then down to the destination component again. If you have many destination components and many source components this can become a chaos pretty quickly. The following image demonstrates this and also shows why the flux pattern can be a good solution to this problem:

component_change_propagation

The flux pattern introduces a single source of truth called Store or State where all components receive their data from. There are other concepts in the above mentioned frameworks such as services (via DI) in Angular and hooks or mixins in React and Vue and in many scenarios they suffice. The flux pattern goes a step further and decouples querying data from performing updates.

Flux-pattern

The basic pattern consists of four parts. A Store which acts as single source of truth storing the application's data much like a database. The second part is of course the View which querys or subscribes to data changes in a reading fashion. Updates to the stored data can be achieved by dispatching actions, the third part of the pattern. Actions are just simple command objects (see Command Pattern). They can contain a payload instructing the fourth and last part of the pattern the Reducer how to update certain parts of the Store. Reducers are simple functions that receive dispatched actions and perform updates on the store. This way the View is completely decoupled from data handling in the background.

It is possible to use the pattern only in complex parts of an application, however, it is advisable to fully commit to the pattern if you choose to use it. Otherwise it will lead to much greater data flow chaos.

You don't need to implement the pattern yourself. There are many implementations for each frontend technology out there:

Sources: https://blog.codecentric.de/en/2017/12/developing-modern-offline-apps-reactjs-redux-electron-part-3-reactjs-redux-basics/

Sven Röttering - 29.3.2021
Design Patterns

Smartphone Notifications via Rest API

https://pushover.net/

await fetch(`https://api.pushover.net/1/messages.json?token=xxx&user=xxx&title="SCHNAPPER ALERT!"&message="${ availableItemTitle }"`, {
        method: 'POST',
    }).then(
        () => {
            myLog('sent notification successfully')
        }, error => {
            myLog('unable to send notification due to' + error)

        }
    )
Simon Jakubowski - 24.3.2021

Cypress & Network Stubbing

Mithilfe von Cypress testen wir die Erfüllung von User Stories. Manchmal testen wir dabei konkret, ob bestimmte Calls wie erwartet durchlaufen. Wir können aber auch Antworten abfangen, verändern oder komplett simulieren. So können wir z.B. Fehlerfälle durchlaufen und prüfen, ob die UI wie gewünscht reagiert.

Zuvor: cy.server & cy.route

cy.server()
   .route({ method: 'GET', url: 'api/crm/*' }).as('excelDownload')
   [...]
   .get('button[type="submit"]').should('be.visible').click()
   .wait('@excelDownload').its('url').should('include', 'api/crm/excel?tool=CORNSEED&tenant=de')
   .get('@excelDownload').its('status').should('equal', 200);

Jetzt: cy.intercept

cy
   .intercept('GET', 'api/crm/*').as('excelDownload')
   [...]
cy.intercept(url, routeHandler?)
cy.intercept(method, url, routeHandler?)
cy.intercept(routeMatcher, routeHandler?)

Keine Methode gegeben? Dann hören wir auf alles. Der RouteMatcher sorgt für mehr Flexibilität: Vielleicht wollen wir ja nach bestimmten Headern oder Auth Credentials filtern.


Es werden mehrere Calls mit selber Methode + Endpunkt erwartet? Die Prüfung könnte so aussehen:

cy.get('@excelDownload.all').should('have.length', 2)
   .then((xhrs) => {
     // xhrs as array of network call objects
     expect(xhrs[0], 'first request status').to.have.property('status', 201)
     expect(xhrs[1], 'second request status').to.have.property('status', 201)
   })

Oder lieber einzeln prüfen? Dann so:

cy.get('@excelDownload.1').should((xhr1) => {
    expect(xhr1, 'first request').to.have.property('status', 201)
  })
  .get('@excelDownload.2').its('response.status').should('equal', 500)

Wir brauchen für den Testfall andere Beispieldaten?

Calls an den gegebenen Endpunkt können eine vordefinierte Antwort erhalten. Statische Objekte oder strings (z.B. 'success') können als Body mitgegeben werden. Oder ein Fixture:

cy.intercept('/users.json', { fixture: 'testUsers' })

Mehr in der Cypress Dokumentation📖

Kerstin Paduch - 24.3.2021
Testing

TypeScript static inheritance Quiz

Following Situation:

abstract class Animal {
  static makeNoise = () => "Wild Animal Noises";

  constructor() {
    console.log(Animal.makeNoise());
  }
}

class Dog extends Animal {
  static makeNoise = () => "Wild Dog Noises";
}

class Cat extends Animal {
  static makeNoise = () => "Wild Cat Noises";
}

new Cat();
new Dog();

What will be logged?

Antwort 2x `Wild Animal Noises`

Okay, now we want the function to log the child classes makeNoise function result, how can we do it?

Antwort
    const child = this.constructor as typeof Animal;

    console.log(child.makeNoise());

We had to use this when working with ngxs, where selectors are static functions. We had an Abstract State that we extended with different child states so there was no way to call the right function without using this method.

Play with the example here: https://codesandbox.io/s/loving-ellis-kivbb?file=/src/index.ts

Lucas Meurer - 24.3.2021

Debug NodeJS with Intellij

  1. Click the green arrow in the package.json
  2. Select Debug
  3. ???
  4. Profit

Bildschirmaufnahme-2021-02-02-um

Lucas Meurer - 21.3.2021

Block, Element, Modifier (BEM)

Quellen:

http://getbem.com/introduction/

https://sparkbox.com/foundry/bem_by_example


Youtube:

https://www.youtube.com/results?search_query=bam+css


Was ist das, Warum sollte man das nutzen oder was gibt es noch?

BEM ist ein Teil von CSS. Es ist nicht , was man installiert oder einen Library. Das ist etwas ,was man damit, seine css Classes nennt.

BLOCK: Das definiert jeweilige Elemente auf eine Seite. so wie:

  • Logo
  • search
  • Navigation
  • Button
  • Input

Element: Ein Teil eines Blocks, der keine eigenständige Bedeutung hat und semantisch mit seinem Block verbunden ist.

  • Einzelne Punkte in Navigation
  • Einzelne Elemente bei einem Formular

Modifier: Eine Markierung an einem Block oder Element. Verwenden Sie diese, um Aussehen oder Verhalten zu ändern.

  • Farbe
  • Große der schrift

Beispiele:

.block{}

.block--modifier{}

.block__element{}

.block__element--modifier{}


[block]__[element]--[modifier]


Jan Sauer - 17.3.2021
CSS

Lottie

Lottie is a library that renders After Effects animations in real time. It was originally developed by Airbnb and is now open source. https://airbnb.design/lottie/

Example animations

An animation like this is very difficult to develop in CSS/JS and/or natively for iOS/Android. But it is very easy to use tools like After Effects. This is especially good for artists, because they don't have to learn to code. The plugin Bodymovin - Lottie is needed for this.

The animation is exported in SVG/JSON format and is therefore particularly small compared to a video. In addition, it can normally be scaled as desired.

Lottie also offers an api with which animations can be controlled. For example, a burger menu can have an animation for opening and closing. With one click, the animation is started and then pauses at frame X. A second click allows the animation to continue.

Comparison

Comparison

Interesting article

Animation in the League of Legends Client

Adrian Görisch - 10.3.2021
AnimationSVG

Mirroring Gitlab Repositories

We sometimes have the requirement to mirror a git repository to another location. Gitlab supports this in all tiers. Simply go to Settings -> Repository and expand the Mirror section. Enter the URL of the target git repository and choose if you want to push or pull code to or from the target repository. Gitlab also needs either an SSH key or a password to access the target repository. You can also choose to only sync protected branches. Regarding to how we work that would mean only the master branch is synced. More details can be found in the Official Documentation.

Sven Röttering - 10.3.2021
Gitnewcubator

Template String Quiz

Frage 1

Was wird gelogged?

let ne = (wcu) => (ba) => (tor) => `ne${wcu}${ba}${tor}`

console.log(ne('wcu')`ba``tor`);
  1. Uncaught SyntaxError: Unexpected string
  2. (wcu) => (ba) => (tor) => `ne${wcu}${ba}${tor}`bator
  3. newcubator
  4. netorbawcu
  5. Uncaught TypeError: "ba" is not a function
Antwort und Frage 2

Richtige Antwort: 3.

ne ist hier eine Template Tag funktion. Diese sieht man sonst häufig z.B. im Zusammenhang mit graphql queries. Als ersten parameter bekommt sie den text des nachfolgenden template strings übergeben. Dies lässt sich auch verschachteln, sodass man mehrere template strings ohne syntax error direkt hintereinander schreiben kann. Ob das verschachteln außerhalb eines Quiz sinn macht wage ich zu bezweifeln.

Frage 2

Nur eines der Folgenden Statements logged wirklich "\n". Welches?

  1. console.log(`\n`);
  2. console.log(String.raw`\n`);
  3. console.log(String.raw(`\n`));
Antwort
  1. Ist richtig. 1. loggt eine leere Zeile und 3. wirft einen Fehler: TypeError: Cannot convert undefined or null to object

Mit der String.raw funktion kann man in einem Template String die Escapes ignorieren. Dies funktioniert aber nur wenn man sie als template tag funktion aufruft, da dabei als parameter ein object mit {raw: "text"} übergeben wird.

Mehr über die Template Tag funktionen kann man hier lesen: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#tagged_templates

Lucas Meurer - 10.3.2021
JavaScriptQuiz

Angular - Funktionsaufrufe in Templates vermeiden

  • Standardmäßig führt Angular jedes Mal, wenn sich etwas in der Anwendung ändert, eine ChangeDetection für alle Komponenten durch, d.h. es wird geprüft, ob sich der Wert von Template-Ausdrücken geändert hat.
  • Wenn die Komplexität der Komponente wächst, dauert die Prüfung länger, aber durch ChangeDetectionStrategy.OnPush sagen wir Angular, dass es nur prüfen soll, ob sich die Referenzen geändert haben, anstatt nach den Werten jeder Eigenschaft zu suchen.
  • OnPush-ChangeDetectionStrategy hilft, die Anzahl der Änderungszyklen zu reduzieren.

Beispiel: https://gist.github.com/RahmiTufanoglu/917a1f1c015e2602ecda028ae723d0a4

  • Um festzustellen, ob formatName() neu gerendert werden muss, muss Angular die formatName()-Funktion ausgeführt haben, um zu prüfen, ob sich der Rückgabewert geändert hat.
  • Da Angular nicht vorhersagen kann, ob sich der Rückgabewert von formatName() geändert hat, muss es die Funktion bei jeder Änderungserkennung ausführen.
  • Wenn also die Änderungserkennung 100 Mal läuft, wird die Funktion auch 100 Mal aufgerufen, auch wenn sich ihr Rückgabewert nie ändert.
  • Problematisch wird es bei großen Komponenten. Template-Rendering nimmt Zeit in Anspruch und die Leistung wird beeinträchtigt.
Rahmi Tufanoglu - 9.3.2021

Ping Attribute in a tags

The ping attribute can be included in <a> tag to automatically send a POST request to the provided URL(s) whenever the link is clicked.

<!-- on clicking ping would be sent to https://usefulangle.com/track -->
<a href="https://usefulangle.com/post/288/html-output-tag" ping="https://usefulangle.com/track">Click here</a>

Multiple Pings, separated with whitespace

<!-- on clicking ping would be sent to https://usefulangle.com/track -->
<a href="https://usefulangle.com/post/288/html-output-tag" ping="https://usefulangle.com/track http://someserver.com/notify">Click here</a>

What is a Ping?

  • Ping is basically a HTTP POST request.
  • Request body of this POST request just contains the string PING.
  • Request does not wait for a response from the server.

By using the ping attribute, browser automatically sends a HTTP request upon a click. No custom code is required. The request will be sent even if the user has disabled Javascript.

Umut Tufanoglu - 3.3.2021

Java15

Text Blocks (JEP 368)

private static final String request = """
            {
            "name": "field are 0.05ha",
            "geometry": {
                "type": "Polygon",
                "coordinates": [[
                    [ 9.78480577468872, 52.151607969506735],
                    [ 9.785256385803223, 52.151607969506735],
                    [ 9.785256385803223, 52.151779125539825],
                    [ 9.78480577468872, 52.151779125539825],
                    [ 9.78480577468872, 52.151607969506735]
                ]]
            },
            "farmId": "23328c83-857a-4aba-8949-bae2e3447c86",
            "country": "DE",
            "areaSquareMeters": 586,
            "creatingTool": "DRYMATTER",
            "activeTools": ["FIELD_MANAGEMENT", "VARIABLE_RATE_SOWING"]
        }
        """;
String aaName = "Pat Q. Smith";

String bbName = """
                Pat Q. Smith""";

aaName.equals(bbName) // true
// ORIGINAL
String message = "'The time has come,' the Walrus said,\n" +
                 "'To talk of many things:\n" +
                 "Of shoes -- and ships -- and sealing-wax --\n" +
                 "Of cabbages -- and kings --\n" +
                 "And why the sea is boiling hot --\n" +
                 "And whether pigs have wings.'\n";

// BETTER
String message = """
    'The time has come,' the Walrus said,
    'To talk of many things:
    Of shoes -- and ships -- and sealing-wax --
    Of cabbages -- and kings --
    And why the sea is boiling hot --
    And whether pigs have wings.'
    """;

Switch Expressions (JEP 361)

switch (month) {
          case JANUARY, FEBRUARY, MARCH -> System.out.println("First Quarter");//no break needed
          case APRIL, MAY, JUNE -> System.out.println("Second Quarter");
          case JULY, AUGUST, SEPTEMBER -> System.out.println("Third Quarter");
          case OCTOBER, NOVEMBER, DECEMBER -> System.out.println("Forth Quarter");
          default -> System.out.println("Unknown Quarter");
      }
// using single expressions
String quarter = switch (month) {
          case JANUARY, FEBRUARY, MARCH -> "First Quarter"; //must be a single returning value
          case APRIL, MAY, JUNE -> "Second Quarter";
          case JULY, AUGUST, SEPTEMBER -> "Third Quarter";
          case OCTOBER, NOVEMBER, DECEMBER -> "Forth Quarter";
          default -> "Unknown Quarter";
      };
//using multiple expressions
String result = switch (month) {
          case JANUARY,
                  FEBRUARY,
                  MARCH -> {
              //multiple statements can be used here
              yield "First Quarter";
          }
          case APRIL, MAY, JUNE -> {
              //multiple statements can be used here
              yield "Second Quarter";
          }
          case JULY, AUGUST, SEPTEMBER -> "Third Quarter";
          case OCTOBER, NOVEMBER, DECEMBER -> {
              //multiple statements can be used here
              yield "Forth Quarter";
          }
          default -> "Unknown Quarter";
      };

Records (JEP 384) (PREVIEW Feature)

public record FieldValidateAreaInput(
    Tenant tenant,
    String externalId,

    int fieldAreaSize,
    Set<CultiventTool> cultiventTools
) { 
    public String someLogic() {
        return "test";
    }
}

...

input.fieldAreaSize()
input.cultiventTools()
input.someLogic()

Helpful NullPointerExceptions (JEP 358)

Caused by: java.lang.NullPointerException: Cannot invoke "String.toLowerCase()" because "test" is null
	at com.kws.cultivent.fieldservice.domain.field.validatefieldarea.FieldValidateArea.handle(FieldValidateArea.java:58)
	at org.codehaus.groovy.vmplugin.v7.IndyInterface.selectMethod(IndyInterface.java:234)
	at com.kws.cultivent.fieldservice.domain.field.validatefieldarea.FieldValidateAreaTest.should return when the fieldArea is valid(FieldValidateAreaTest.groovy:35)
Jan Sauer - 3.3.2021
Java

What would the JavaScript error say?

var numbers = [1, 2, 3, 4, 5];
numbers.length = 3;

Answer: In JS it is possible to set the length of a array. => numbers = [1, 2, 3]

Jan Sauer - 3.3.2021
JavaScriptQuiz

l10n i18n a11y

  • Internationalization (i18n)
  • Localization (l10n)
  • Globalization (g11n)
  • Localizability (l12y)
  • Accessibility (a11y)
Jan Sauer - 3.3.2021

OpenStreetMap (OSM)

Reason for this topic: Maps Einträge für Hannover

Data format

Editors

Maps

Download

License

Jan Sauer - 17.2.2021

Facade

Fassade

  • einer der GoF-Design-Pattern
  • ist die Middleware zwischen den Subsystemen und dem Client
  • eine Fassade übergibt wichtige Funktionalitäten der der Software an die jeweiligen Subsysteme, um den Umgang mit den verschiedenen Teilkomponenten eines Programms so einfach wie möglich zu gestalten

Vorteile:

  • der Code ist einfacher zu verwenden, zu verstehen und zu testen
  • sauberer Code, da der Client keine komplexe Schnittstelle verwendet und das System flexibler und wiederverwendbar ist

facade

class Lights {
  turnOn() {
    console.log('Lights on.');
  }

  turnOff() {
    console.log('Lights off.');
  }

  dim() {
    console.log('Lights dimmed.');
  }
}
/*************************************/
class Heating {
  turnOn() {
    console.log('Heating on.');
  }

  turnOff() {
    console.log('Heating off.');
  }
}
/*************************************/
class TV {
     turnOn() {
        console.log('TV on.');
    }

    turnOff() {
        console.log('TV off.');
    }
}
/*************************************/
class Facade {
  private lights: Lights;
  private heating: Heating;
  private tv: TV;

  constructor(lights: Lights, heating: Heating, tv: TV) {
    this.lights = lights;
    this.heating = heating;
    this.tv = tv;
  }

  public cozyEvening() {
    this.lights.dim();
    this.heating.turnOn();
    this.tv.turnOn();
  }
}
/*************************************/
const lights = new Lights();
const heating = new Heating();
const tv = new TV();

const facade = new Facade(lights, heating, tv);
facade.cozyEvening();

"Lights dimmed."

"Heating on."

"TV on."

Sven Röttering - 10.2.2021
Design Patterns

State Pattern

Description

The state pattern should deal with 2 major problems:

  • An object should change its behavior when its internal state changes. As an example, we have a player character that should play different animations. Depending on what is happening. Jump, Idle, Run, Attack...
  • State-specific behavior should be defined independently. That is, adding new states should not affect the behavior of existing states.
    • Not much happens in the Idle animation.
    • In the Jump animation, height-controlled frames -> additional calculations should be performed.

In a state, it can also be determined, for example, which state I can execute next.

  • from Idle I can go directly to Jump, Attack, Run
  • From Jump I can go directly to Run, Idle but not Attack.

UML

Code

interface State {
    String open(StateContext context);

    String close(StateContext context);
}

class OpenState implements State {
    @Override
    public String open(StateContext context) {
        return "Is Already Open, so cant open again";
    }

    @Override
    public String close(StateContext context) {
        context.state = new CloseState();
        return "Close";
    }
}

class CloseState implements State {
    @Override
    public String open(StateContext context) {
        context.state = new OpenState();
        return "Open";
    }

    @Override
    public String close(StateContext context) {
        return "Is Already Closed, so cant close again";
    }
}

class StateContext {
    State state = new OpenState();

    void open() {
        System.out.println(state.open(this));
    }

    void close() {
        System.out.println(state.close(this));
    }
}
Sven Röttering - 10.2.2021
Design Patterns

NestJS Logger Quiz

import { Logger } from '@nestjs/common';

Logger.log({ val: NaN });

Was wird geloggt?

1.

[Nest] 61353   - 02/02/2021, 4:44:20 PM   Object:
{
  "val": "NaN"
}
 +110ms

2.

[Nest] 61353   - 02/02/2021, 4:44:20 PM   Object:
{
  "val": Infinity
}
 +110ms

3.

[Nest] 61353   - 02/02/2021, 4:44:20 PM   Object:
{
  "val": null
}
 +110ms

4.

[Nest] 61353   - 02/02/2021, 4:44:20 PM   Object:
{
  "val": NaN
}
 +110ms

5.

[Nest] 61353   - 02/02/2021, 4:44:20 PM   [object Object] +110ms
Antwort Antwort: 3.: null. Der Logger benutzt JSON.stringify und der JSON Standart unterstützt kein NaN und macht deswegen null daraus. Infinity wird übrigens auch zu null.
Lucas Meurer - 10.2.2021

Java Continue Quiz

public class JavaFiddle {
    public static void main(String[] args) {
    
    int y = 0;
    
    for (int i = 0; i < 10; i++) {
      
      try {
    	  y = i;
          throw new RuntimeException();
      } catch (RuntimeException re) {
        
        System.out.println("Continuing for y = " + y);
        continue;
      }
    
    }  
    
    System.out.println(y);
  }
}

a)

Continuing for y = 0
0

b)

Continuing for y = 0
Continuing for y = 1
Continuing for y = 2
...
9

c)

some weird RuntimeException

Lösung: Antwort b ist richtig, da das continue; hier keinen Einfluss auf den Programmablauf hat. Es könnte genauso gut weggelassen oder außerhalb des Catch Block stehen. Für mehr Information, wie man continue nutzt wird hier genauer beschrieben: www.w3schools.com/continue

Simon Jakubowski - 3.2.2021

Get Touch Support in your mobile browser

Using browser events the support for touch events is limit. Swiper JS claims to be most modern touch slider and is used by popuplar companies.

Jörg Herbst - 3.2.2021
JavaScript

Configure npm to not use a save prefix

Beim Installieren von NPM Packages wird per default immer ein Save-Präfix vor die Paketversion geschrieben. Möchte man dies permanent unter binden, kann man in seiner ~/.npmrc Config-Datei den Präfix entfernen, in dem man folgende Zeile hinzufügt

save-prefix=

Um Projektspezifische npm Konfigurationen vorzunehmen, kann man im root-Verzeichnis des Projektes eine .npmrc Datei anlegen und dort die Konfigurationen vornehmen.

https://docs.npmjs.com/cli/v6/configuring-npm/npmrc/
https://docs.npmjs.com/cli/v6/using-npm/config/#save-prefix

Jonathan Zbick - 3.2.2021

Cloudflare Warp

Your Internet service provider can see every site and app you use—even if they’re encrypted. Some providers even sell this data, or use it to target you with ads.

1.1.1.1 with WARP prevents anyone from snooping on you by encrypting more of the traffic leaving your device.

We believe privacy is a right. We won't sell your data, ever.

Fastest DNS Resolver.

https://1.1.1.1/

https://www.dnsperf.com/#!dns-resolvers

Umut Tufanoglu - 27.1.2021
Tool

GitLab 13.8 is out

GitLab 13.8 is out and here are the most interesting changes:

Gitlab Rebase quick action for merge requests

GitLab 13.8 brings the ability to execute the rebase quick action in merge requests, allowing you to quickly invoke the rebase Git utility.

On a merge request comment, type /rebase and click the Comment button. It’s that simple.

https://about.gitlab.com/releases/2021/01/22/gitlab-13-8-released/#rebase-quick-action-for-merge-requests

Click and drag multiline merge request comments

https://about.gitlab.com/releases/2021/01/22/gitlab-13-8-released/#click-and-drag-multiline-merge-request-comments

Pipeline Editor and Visualization

https://about.gitlab.com/releases/2021/01/22/gitlab-13-8-released/#pipeline-editor https://about.gitlab.com/releases/2021/01/22/gitlab-13-8-released/#visualization-of-pipeline-configuration

Jan Sauer - 27.1.2021
GitlabNews

GitLab.com has removed our subscription tier

We are currently having GitLab paid subscription for newcubator on GitLab.com and the self hosted KWSSAAT instance. The Bronze/Starter subscription tier that we are using was discontinued now and is no longer available.

Source: GitLab is moving to a three-tier product subscription model

Jan Sauer - 27.1.2021
GitlabNews

Angular & Tailwind

ohne @apply:

<button class="w-80 bg-green-200 shadow-md">Hello world!</button>

mit @apply:

/* HTML */
<button class="my-button>Hello world!</button>

/* CSS */
.my-button {
 @apply w-80 bg-green-200 shadow-md
}

=> Tailwind Components

Rahmi Tufanoglu - 27.1.2021
AngularCSS

Use main as the default branch

Follow-up for Git main replaces master #41 (closed)

Local default

Starting in Git 2.28, git init will instead look to the value of init.defaultBranch when creating the first branch in a new repository.

$ git config --global init.defaultBranch main

GitLab group wide default

GitLab now supports setting a default branch name for new repositories. Custom initial branch name

Rename existing projects

To change it, you can use the move command in git to copy the entire master branch (and it's history) to a new branch like so:

$ git branch -m master main

We can then push it to our remote repository with:

$ git push -u origin main

Now that the main branch exists on GitLab we can change the settings there as well. In the project go to Settings -> Repository -> Section: Default Branch and select main in the drop down.

Screen_Shot_2021-01-17_at_19.23.07

Changing the default branch setting does not update the protected branches. For this scroll down to Section: Protected Branches. There we can now add our new main branch and remove the protection from master.

Screen_Shot_2021-01-17_at_19.33.43

As a final step we can now go to Repository -> Branches and delete the old master branch and are done.

Unless we hardcoded a reference to the master branch in CI (only: master)!

Proposal

The default branch of the newcubator/devsquad project is already renamed. Give it a try and if no one posts a reason why we shouldn't we will start renaming active newcubator projects after the next devsquad.

Jan Sauer - 20.1.2021
CI/CDGitGitlabnewcubator

Pulling without specifying how to reconcile divergent branches

Since Git 2.27 i get a warning when pulling.

hint: Pulling without specifying how to reconcile divergent branches is
hint: discouraged. You can squelch this message by running one of the following
hint: commands sometime before your next pull:
hint:
hint:   git config pull.rebase false  # merge (the default strategy)
hint:   git config pull.rebase true   # rebase
hint:   git config pull.ff only       # fast-forward only
hint:
hint: You can replace "git config" with "git config --global" to set a default
hint: preference for all repositories. You can also pass --rebase, --no-rebase,
hint: or --ff-only on the command line to override the configured default per
hint: invocation.

When you do a git pull origin master, git pull performs a merge, which often creates a merge commit. Therefore, by default, pulling from the remote is NOT a harmless operation: it can create a new commit sha that didn’t exist before. This behavior can confuse a user, because what feels like it should be a harmless download operation actually changes the commit history in unpredictable ways. https://stackoverflow.com/a/62653400/531592

Recommendation

$ git pull --ff-only

or event better as a global default with

$ git config --global pull.ff only
Jan Sauer - 20.1.2021
Git

Gang of Four Design Patterns

Over 20 years ago the iconic computer science book “Design Patterns: Elements of Reusable Object-Oriented Software” was first published. The four authors of the book: Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, have since been dubbed “The Gang of Four”. In technology circles, you’ll often see this nicknamed shorted to GoF. Even though the GoF Design Patterns book was published over 20 years ago, it still continues to be an Amazon best seller.

The GoF wrote the book in a C++ context but it still remains very relevant to Java programming. C++ and Java are both object-oriented languages. The GoF authors, through their experience in coding large scale enterprise systems using C++, saw common patterns emerge. These design patterns are not unique to C++. The design patterns can be applied in any object oriented language.

As a Java developer using the Spring Framework to develop enterprise class applications, you will encounter the GoF Design Patterns on a daily basis.

The GoF Design Patterns are broken into three categories: Creational Patterns for the creation of objects; Structural Patterns to provide relationship between objects; and finally, Behavioral Patterns to help define how objects interact.

Source: https://springframework.guru/gang-of-four-design-patterns/

Sven Röttering - 20.1.2021
BookDesign Patterns

Difference between current_timestamp, now() and clock_timestamp() in postgresql

There are multiple methods to detect the current time in postgresql. Two of those methods are:

  1. Use the value current_timestamp
  2. Use the function now()
  3. Use the function clock_time()
INSERT INTO person (id, name, created_at) VALUES ('33333333-3333-3333-3333-333333333005', 'Max' , current_timestamp);
INSERT INTO person (id, name, created_at) VALUES ('33333333-3333-3333-3333-333333333005', 'Max' , now());
INSERT INTO person (id, name, created_at) VALUES ('33333333-3333-3333-3333-333333333005', 'Max' , clock_timestamp());

While all of these will insert a timestamp they work a little bit different.

  1. The first is a value defined in Standard SQL, you can find more standard values in the postgresql manual.
  2. The second and third are both postgresql functions The major difference is now() is adding the time at the beginning of the transactions, while, clock_timestamp() insert the time at the execution of the statement.
Jörg Herbst - 20.1.2021
Databases

Remote mob programming with git

Mob programming is a thing these days. But with everybody working from home it might be a little more difficutl. Git handover is a shell script which helps your organising your programming as a mob.

Jörg Herbst - 20.1.2021
Tool

Renovate Service no longer supports Gitlab

The hosted renovate service no longer supports Gitlab as a hosting platform. Apparently Gitlab added per-account api rate limiting that makes running renovate as bot imposible. All mentions of gitlab are already removed from the website. (Source)

We are now running renovate ourselves with Gitlab CI -> https://gitlab.com/newcubator/renovate-runner
Currently without automated onboarding!

Update Stats

In case no one has noticed it yet Renovate added stats about the updated packages. (Example)

En0Dx77XcAAmuv2

Jan Sauer - 20.1.2021
CI/CDNewsnewcubator

Miller's Law

Bzgl. Information Design: Wie stelle ich Informationen in der UI so dar, dass sie möglichst schnell verstanden werden und dem Nutzer zügig bei seinem Anwendungsfall unterstützen?

Magical Number

Miller verfasste 1956 einen Text, der als wissenschaftlicher Artikel bekannt wurde, aber eher eine Rede von ihm zusammenfasst, in der er darüber nachdenkt, inwieweit Menschen eingeschränkt sind, Informationen gleichzeitig zu verarbeiten. Bekannt wurde also ein Limit von sieben (plus minus zwei) Informationen gleichzeitig. Der Psychologe Alan Baddeley führte ab 1986 eine Reihe von Studien durch, die das menschliche Gedächtnis und Informationsverarbeitung erforschten. Andere Studien, unter anderem durchgeführt von Nelson Cowan 2001, ergänzten die Forschungsergebnisse. Die aktuellen Forschungsergebnisse legen die magische Zahl 4 nahe.

Erweiterung durch Gruppierung

Menschen können in ihrem Kurzzeitgedächtnis drei bis vier Dinge gleichzeitig behalten, solange sie nicht abgelenkt sind und ihre Datenverarbeitung nicht gestört wird. Ausgeweitet werden kann die Menge durch Gruppierung. Als Beispiele können die gruppierten Zahlen von Telefonnummern und IBANs dienen. Der Kognitionspsychologe George Mandler bewies dies über eine Studie 1969. Probanden konnten sich alle kategorisierten Einträge merken, wenn sich in einer Kategorie nur ein bis drei Einträge befanden. Bei vier bis sechs Einträgen konnten sich die Probanden 80% merken. Bei 80 Einträgen pro Kategorie konnten sich die Probanden nur noch 20% merken.

millers_law_graph

Weitere Gedächtnisforschung

Im Nature Magazin wurde 2000 der Artikel "Numerical memory span in a chimpanzee" von Tetsuro Matsuzawa und Nobuyuki Kawai veröffentlicht. Hier wurde einer Schimpansin, die die Zahlen von null bis neun kannte, eine Zahlenfolge gezeigt, die sie sich merken und über Displayklick wiedergeben sollte. Bei einer Reihe von vier Zahlen lag ihre Erfolgsquote bei 90%, demnach deutlich höher als bei Zufallserfolgen. Bei fünf Einträgen lag ihre Erfolgsquote bei 65%. Bei einem Test wurde sie bei der Eingabe von benachbarten, sich streitenden Schimpansen für etwa 20 Sekunden abgelenkt. Den Test hat sie dennoch erfolgreich abgeschlossen.

Bildschirmfoto_2021-01-11_um_08.25.30

Zuvorkommendes Design

Kategorisierung vieler Informationen erleichtert die Verarbeitung des vorgegebenen Inhalts. Wenn keine Kategorisierung gegeben ist, erstellt der Mensch selber welche. Er versucht, über visuelle Wege oder über inhaltliche Eigenschaften Gemeinsamkeiten zu finden und die Informationen so zu gruppieren. Nach Möglichkeit sollte man entsprechend ein Design vorgeben, dass den Nutzer die Umsetzung der Gruppierung vorwegnimmt.

Quellen:

Weinschenk: 100 things every designer needs to know about people, S. 52-54, 87-88

Kawai, Matsuzawa: "Numerical memory span in a chimpanzee" in Nature, Vol. 403, No. 6765, S. 39 - 40, 6. Januar 2000. (https://www.researchgate.net/publication/12675224_Numerical_memory_span_in_a_chimpanzee)

Kerstin Paduch - 13.1.2021
UX

Ant Design

Sven Röttering - 13.1.2021

Optimistic UI

Optimistic UI is a UX technique to reduce waiting time for the user resulting in a much smoother and faster app experience. It is mainly used when communicating with APIs which usually takes a certain amount of time. Before the client sends a request it guesses the response and updates the UI in advance. When the server responds as expected the client has nothing to do and the user did not have to wait for the response. In case of errors or unexpected responses the client has to adjust the UI which can be irritating for the user. Thus it is important to know or predict what the server will do to have as few corrections as possible.

Note: Do not use optimistic UI for longer tasks. If the user queues up long tasks data inconsistencies could occur. Also it can be useful for the user to know if a tasks takes longer.

Sven Röttering - 13.1.2021
UX

A good stating point for Mobile Interfaces

Apples Human Interface Guidelines (HIG) are widely known for their quality. We do not develop iPhone Apps but it is still an awesome resource to flick through.

Place buttons where people expect them. In general, buttons people are most likely to tap should be on the right. Cancel buttons should always be on the left. Alert Buttons

Jan Sauer - 16.12.2020
UX

UX Design nach psychologischen Regeln

1. Hick's Law

Je mehr Optionen und je komplexere Optionen dem Nutzer angeboten werden, desto länger seine Reaktionszeit, da desto größer das Cognitive Load. 🧠
Bsp.:

2. Miller's Law

Informationen sollten nach Möglichkeit inhaltlich gebündelt werden, sodass der Nutzer eine vorgruppierte, nachvollziehbare Übersicht erhält. 🗂
Bsp.:

  • IBAN:
    DE41123456789123456789
    vs
    DE41 1234 5678 9123 4567 89
  • komplexe Navigation (Hauptmenü, z.B. https://www.amazon.de/) mit Überthemen (z.B. Bücher) und Unterthemen (z.B. Fachbücher & Hörbücher)
  • Aufbau einer Webseite: Überschrift, Beschreibungstext, Interaktionsbereich

3. Jakob's Law

Mental Models bauen sich bei Nutzern bei täglicher Bearbeitung von Aufgaben auf. Diese Gewohnheiten aus dem Web mit bestimmten Elementen und auch der realen Welt mit wiederholenden Werkzeugen werden zu unterbewussten Erwartungen, die zumindest angestoßen werden sollten, um einen Wiedererkennungswert zu erzeugen.
Bsp.:

  • Iconwahl für Funktionstrigger: 📞 🗑
  • "Natürliche" Scrollrichtung bei Apple-Produkten: Per Drag wird die Webseite nach oben geschoben

Quelle:

https://alistapart.com/article/psychology-of-design

Kerstin Paduch - 16.12.2020
UX

Configure Author and Email for your Git Commits

$ git config --global user.name "FIRST_NAME LAST_NAME"
$ git config --global user.email "MY_NAME@newcubator.com"

Why --global

Order where Git searches for configuration:

  1. Project specific .git/config
  2. User specific $HOME/.gitconfig
  3. System wide /usr/local/etc/gitconfig (On Mac)

Bonus

If you want to get fancy and automate the email and other configurations based on the location of the project directory, you can use Conditional Includes.

Jan Sauer - 9.12.2020
Gitlab

How to store a ranked (sortable) list in a database

A simple idea might be an index column where you store the order from 1 to n but then when changing the order you'd potentially have to change the order for a lot of records.

Jira uses lexorank:

The index column uses chars like aaa, aaf, xxx. Now if you want to sort item xxx between aaa and bbb, you'd assign it the rank aad. If there is no space left like between acd and ace, you'd use acdm. Since you can append as many characters as you want you'll never run out of space.

Jira also uses buckets and an algorithm to rebalance the sorting column, which is explained in detail in the following video: https://www.youtube.com/watch?v=OjQv9xMoFbg

Relevant stackoverflow answer: https://stackoverflow.com/a/49956113

Lucas Meurer - 9.12.2020
Databases

Neo4J Graph Database

Neo4J

https://neo4j.com/

Neo4J is a graph database implemented in Java with ACID compliant transaction management.

Run in docker

docker run -p7474:7474 -p7687:7687 neo4j:latest

Connect to localhost to get a REPL:

http://localhost:7474/

Default username is neo4j, default password is neo4j.

Setting up a default Movies database

:play movie-graph

Concepts

Neo4J uses Nodes and Relationships to model data in graph. Neo4j uses its custom CYPHER Query language to match Nodes and Relationships.

Nodes

Nodes have labels, which distinguish Nodes and are similar to "Tables" in SQL, a Node can have multiple labels and they are the main way to categorize your data. A node can also habe properties, they are the counterpart to "columns" in SQL. However, Neo4j is schemaless, so not every node has to have all properties. In that way, its similar to MongoDB.

CREATE (person:NODE_LABEL {propery: 'value'})

Relationships

What makes Neo4J interesting, is the concept of Relationships. A Node can be connected to an unlimited amount of other Nodes by a directional Relationship. These Relationships can also have labels and properties.

CREATE (g:ProductGroup {name: 'Hochdruckreiniger'})
CREATE (p:Product {name: 'Kärcher Super 3000'})
WITH g,p
CREATE (g)-[r:INCLUDES_PRODUCT]->(p)
RETURN g,p

Bildschirmfoto_2020-12-04_um_10.49.28

Cypher query language

Neo4j does not use SQL, but an SQL-like query language called Cypher. https://neo4j.com/developer/cypher/intro-cypher/

Matching Nodes

Matching any node

MATCH (node) RETURN node

Matching all nodes with a label of NODE_LABEL

MATCH (node:NODE_LABEL) RETURN node

Matching all nodes with a property of name that equals to `Ben``

MATCH (node {name: 'Ben'}) RETURN node

Matching all nodes with the labels LABEL_ONE and LABEL_TWO

MATCH (node:LABEL_ONE:LABEL_TWO) RETURN node

You can also use WHERE clauses similar to SQL, this comes in handy if the queries get more complex.

MATCH (actor:Person)-[:ACTED_IN]-(film:Movie),
     (director:Person)-[:DIRECTED]-(film:Movie) 
WHERE actor.name='Tom Hanks'
RETURN actor.name, film.title, director.name ;

Matching relationships

Relationships are represented by dashes -- and can either be directed -[]-> or undirected -[]-.

You can also filter by labels and properties like with nodes.

MATCH (actor:Person)-[rl:ACTED_IN {roles: ['Agent Smith']}]->(movie:Movie)
RETURN rl, actor, movie

Bildschirmfoto_2020-12-04_um_11.05.29

Integrations and tools

Local development and query REPL

Neo4J has a browser-based REPL and workbench that has a good support for autocompletion, visualizing data and Import/Export of data. You can save your most used queries and manage multiple databases.

Bildschirmfoto_2020-12-04_um_11.09.03

Spring Data Neo4j

Spring Data has a integration for Neo4J that is similar to Spring Data JPA in that it works with defining Entities which are queried by Repositories.

https://docs.spring.io/spring-data/neo4j/docs/current/reference/html/#introduction

@Node("Movie")
public class MovieEntity {

	@Id @GeneratedValue
	private Long id;

	private String title;

	@Property("tagline")
	private String description;
}
public interface MovieRepository extends CrudRepository<MovieEntity, String> {

	Optional<MovieEntity> findOneByTitle(String title);
}

Migrations in Spring Data Neo4J

https://github.com/michael-simons/neo4j-migrations

Migrations are similar to flyway and verify their validity via checksums.

Hendrik Janßen - 9.12.2020
Databases

Browserstack - Reliable Cross Browser Testing

https://www.browserstack.com/

BrowserStack is a cloud web and mobile testing platform that provides developers the ability to test their websites and mobile applications across on-demand browsers, operating systems and real mobile devices.

Umut Tufanoglu - 9.12.2020
Testing

Learning about PWA on iOS

While PWA is more or less first class citizen on android, iOS support is still limited. The iOS and PWS experience aggregates some information and best practices for PWA developers.

Jörg Herbst - 2.12.2020
JavaScriptPWAiOS

CSS :placeholder-shown & :focus-within

:placeholder-shown

Mit diesem Element können Formulare so bearbeitet werden, dass die Styling-Informationen nur zu sehen sind, solange der Placeholder angezeigt wird. Wird im Formular beispielsweise etwas eingetippt und verschwindet der Placeholder, verschwinden mit ihm auch die Styling-Informationen.

Beispiel: https://codepen.io/team/css-tricks/pen/NxdJgV


:focus-within

Mit diesem Element hat man die Möglichkeit das Elternelement eines Formulars zu adressieren und zu verändern, sobald ein Formularelement fokussiert wird.

Beispiel: https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-within

Rahmi Tufanoglu - 25.11.2020
CSS

🤯 Code Review in IDEA

No more need to leave your IDE for reviewing Merge Requests in Gitlab. Merge Request Integration CE - Code Review for GitLab

  • List open MR's
  • Displays changes as Diffs 😍
  • Needs a paid Enterprise License for private Repos 💵 (Like WinRAR needs a License)
  • Does not stash your current changes 🚨
  • BONUS: Code is OpenSource
Jan Sauer - 25.11.2020
GitlabIntelliJTool

JS Operator Lookup

Why? Because they're ungoogleable: search engines ignore special characters. I can never remember what these things are called, or how they work! https://joshwcomeau.com/operator-lookup/

Jan Sauer - 18.11.2020
JavaScript

Postgres JSON beginner Class

Operators see: https://www.postgresql.org/docs/9.5/functions-json.html

Create column using jsonb

CREATE TABLE article (
    id      UUID PRIMARY KEY,
    properties JSONB NOT NULL
);

Insert values

INSERT INTO article
VALUES (gen_random_uuid(), '{
  "price": 12.1,
  "name": "Kugelschreiber",
  "tags": {
    "manufacturer": "Siemens",
    "discounted": true
  }
}')

Select value from JSON

select 
  properties -> 'price' 
  properties ->> 'price' 
from article
  • -> will extract the value as JSONB
  • ->> will extract the value as text

Compare values

SELECT *
FROM article
WHERE CAST(properties ->> 'price' AS NUMERIC) > 10

Check where value is contained

SELECT *
FROM article
WHERE properties -> 'tags' ? 'discounted'

or

SELECT *
FROM article
WHERE jsonb_exists(properties -> 'tags', 'discounted')

Check where json is contained

SELECT *
FROM article
WHERE properties -> 'tags' @> '{"manufacturer": "Siemens"}'
Simon Jakubowski - 18.11.2020

Postgres string datentypen

Die Datentypen varchar, varchar(n) und text sind in postgres fast das gleiche, sie werden im Hintergrund vom gleichen Datentypen abgebildet und haben keine Performanceunterschiede bezüglich Platz und Schnelligkeit (Bis auf einen extra Check der Länge des Strings wenn varchar(n) benutzt wird.

https://www.postgresql.org/docs/current/datatype-character.html

Postgres komprimiert Textdaten automatisch (TOAST wird dieser Prozess genannt) und lagert sie in einer speziellen Tabelle aus, wenn sie groß genug werden (Standardeinstellung 2kb). Das ist alles ein automatischer Prozess und benötigt kein weiteres Zutun vom DBA.

https://blog.gojekengineering.com/a-toast-from-postgresql-83b83d0d0683

Resultat ist, dass empfohlen wird immer text oder varchar zu nehmen. varchar(n) sollte nur benutzt werden, wenn speziell gewünscht wird, dass ein String eine bestimmte Länge nicht überschreiten soll, was meistens nicht der Fall ist.

Hendrik Janßen - 11.11.2020
DatabasesPerformance

The big list of naughty strings

Was sind Naughty Strings?

  • Strings in Form von u.a.
    • SQL Injections
    • Unicodes
    • 2-Byte Zeichen
    • Sonderzeichen
    • Zeichen verschiedener Alphabete
  • Beispiele:
    • undefined
    • 999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
    • ' OR '1'='1
    • ­؀؁؂؃؄؅؜۝܏᠎​‌‍‎‏‪‫‬‭‮⁠⁡⁢⁣⁤⁦⁧
    • 🐵 🙈 🙉 🙊
    • ̦H̬̤̗̤͝e͜ ̜̥̝̻͍̟́w̕h̖̯͓o̝͙̖͎̱̮ ҉̺̙̞̟͈W̷̼̭a̺̪͍į͈͕̭͙̯̜t̶̼̮s̘͙͖̕ ̠̫̠B̻͍͙͉̳ͅe̵h̵̬͇̫͙i̹͓̳̳̮͎̫̕n͟d̴̪̜̖ ̰͉̩͇͙̲͞ͅT͖̼͓̪͢h͏͓̮̻e̬̝̟ͅ ̤̹̝W͙̞̝͔͇͝ͅa͏͓͔̹̼̣l̴͔̰̤̟͔ḽ̫.͕

Warum Naughty Strings?

  • um Kollegen zu ärgern! :)
  • um naughty Nutzereingaben abzufangen
  • um Schwachstellen im Code zu finden
  • Datenmissbrauch schützen
  • Design von UI-Elementen einhalten

Wo finde ich die Naughty Strings?

Hier ist die Liste der Naughty Strings!

Und hier sind noch mehr Listen von SecLists!

Kerstin Paduch - 4.11.2020
Testing

IntelliJ Task and Context

IntelliJ has added integration for external issue tracker tools. You can user Tools -> Task & Context -> Add Server to configure issue tracker like JIRA or gitlab.

Jörg Herbst - 28.10.2020
IntelliJ

AWS Explorer in IntelliJ

Use AWS Explorer to inspect some AWS applications without logging in into AWS.

You can inspect Cloudwatch Logs, run remote serverless functions, Cloudformation status and more. Its easy to switch profiles.

little demo

AWS Toolkit

AWS Explorer

Adrian Görisch - 28.10.2020
AWSIntelliJTool

OWASP top ten

Who is the OWASP® Foundation? The Open Web Application Security Project® (OWASP) is a nonprofit foundation that works to improve the security of software. Through community-led open source software projects, hundreds of local chapters worldwide, tens of thousands of members, and leading educational and training conferences, the OWASP Foundation is the source for developers and technologists to secure the web.

Tools and Resources Community and Networking Education & Training

https://owasp.org/www-project-top-ten/

https://owasp.org/www-project-api-security/

Sven Röttering - 28.10.2020
NewsTesting

Toggle hidden files / folders Mac

To show hidden files you can simply use the following combination to toggle them:

  • Command+Shift+Dot
Umut Tufanoglu - 21.10.2020
NewsTool

Gitbased CMS

In a typical headless CMS system like Contentful or Storyblock the content is stored externally. A Gitbased CMS system stores the data in a Gitrepo.

Advantages of Gitrepo:

  • The content is versioned.
  • There are no external dependencies
  • Content can also be created in the editor
  • Authentication via gitlab possible

Is interesting for newcubator, because the goal would be to get away from Contentful completely, have everything in your own repo and still have the advantages of a GUI for non-coders

OpenSource: https://www.netlifycms.org/

Lectures:

Demo: will follow

Adrian Görisch - 21.10.2020
GitlabTool

Was macht dieser Typescript Code?

const foo = (a: boolean, b: boolean) => ["neither", "first", "second", "both"][a + b * 2];

console.log(foo(true, true));
console.log(foo(true, false));
console.log(foo(false, true));
console.log(foo(false, false));
Rahmi Tufanoglu - 14.10.2020
QuizTypeScript

UX 101

Usability nach ISO 9241

extent to which a system, product or service can be used by specified users to achieve specified goals with effectiveness, efficiency and satisfaction in a specified context of use

Definitionen der Begriffe, die in der UX fallen.

Übersicht: https://www.iso.org/obp/ui/#iso:std:iso:9241:-11:ed-2:v1:en



🤝 Usability & UI sind Teile der UX 🤝



Customer Journey

accra

  • Nutzerhistorie
  • User Experience beginnt vor der Software-Nutzung
  • Vorerfahrungen mit ähnlichen Produkten:
    • Erwartungshaltung gegenüber Features
    • technische Vorkenntnisse
    • individuelle Anforderungen je Nutzer
  • Customer Journey abteilungsübergreifend eigentlich von einem UX Team unterstützt
  • Ein UX Team kann beinhalten:
    • Interaction Designer:
      Wie interagiert die Webseite mit dem Nutzer, welcher Workflow wird angeboten?
    • Information Architect:
      Wie werden Inhalte aufgeteilt & vermittelt?
    • Visual Designer:
      Welche Farbpalette, Typographie, welches Layout wird genutzt?
    • User Researcher:
      Wie verhält sich der Nutzer, was sind seine Erwartungen & Anforderungen?
      Analyse, Konzeption, Evaluation.
    • Content Strategist:
      Welche Inhalte werden wann & in welchem Ton an den Nutzer vermittelt? Konsistenz des Produkts & der Marke.

Quelle Grafik: https://247grad.de/blog/design-development/customer-journey-map/



Gutes UX Design

ux_honeycomb

  • Useful:
    Inhalt sollte nützlich und sinnvoll sein.
  • Usable:
    Seite sollte leicht nutzbar sein.
  • Desirable:
    Marke / Markenidentität / Interaktionselemente sollten Emotionen wecken & Nutzer an sich binden.
  • Findable:
    Inhalte sollten auffindbar & leicht navigierbar sein.
  • Accessible:
    Inhalte sollten zugänglich (auch barrierefrei) sein.
  • Credible:
    Nutzer sollten Inhalt glauben & vertrauen können.
  • Valuable:
    Seite sollte dem Nutzer einen Mehrwert bringen, v.a. bei For-Profit Organisationen
    Quelle Grafik: http://semanticstudios.com/user_experience_design/



Lean UX

  • UX in agilen Teams
  • Fokus:
    abteilungsübergreifende Kollaboration
    kontinuierlicher Wissensaustausch
  • Lösungen für Nutzerprobleme basieren auf geteilten Erkenntnissen und nicht auf Hypothesen



Literatur

  • Don't make me think, Steve Krug
    Allgemeine Dos & Don'ts
    leicht verständlich & schnell gelesen :)
  • Bottlenecks: Aligning UX Design with User Psychology, David C. Evans
    Psychologische Einflüsse & Grenzen, die die Produktnutzung beeinflussen
    nicht begrenzt auf Webseiten!
  • The User Experience Team of One: A Research and Design Survival Guide, Leah Buley
    Theorie & Anwendung von Methoden für UX Teams & einzelne UX-Vertreter
  • Lean UX, Jeff Gothelf, Josh Seiden
    Umsetzung von UX in agilen Teams



Internetquellen

Kerstin Paduch - 14.10.2020
UX

Vue3 / NuxtJS

VueJs

Was ist VueJs?

Vue.js ist ein clientseitiges JavaScript-Webframework zum Erstellen von Single-Page-Webanwendungen. Sie verbindet die View und das Model über Two-Way-Data-Bindings. Creator → Evan You

yyx990803 - Overview

Was ist NuxtJs?

Nuxt ist ein Framework, das auf Vue.js basiert, um moderne Webanwendungen zu erstellen. Es basiert auf den offiziellen Bibliotheken von Vue (vue, vue-router und vuex) und Entwicklungstools (Webpack, Babel und PostCSS). Das Ziel ist es, effizienter Vue Anwendungen zu schreiben.

https://chunkbytes.com/wp-content/uploads/2019/03/Folder-Structure.png


Einfache Vue App über cdn

message und das Virutal-DOM sind jetzt verknüpft und alles ist jetzt reaktiv

<html>
    <body>
     <div id="app">
       <p>{{ message }}</p>
     </div>
    <script src="https://unpkg.com/vue@next"></script>
    <script>
        const app = Vue.createApp({
          data() {
            return {
              message: 'Hello World',
            }
          }
        })
        app.mount('#app')
    </script>
    </body>
</html>

https://codepen.io/28development/pen/BaKezBo

Über die Vue CLI kann man schnell eine neue Vue 3-App erstellen und dabei beispielsweise direkt bestimmte preset auswählen. Diese werden dann direkt bereitgestellt.

npm install vue → vorher natürlich vue installieren

vue create hello-world

https://cli.vuejs.org/cli-new-project.png

https://cli.vuejs.org/cli-select-features.png

Zusätzlich bietet Vue eine GUI an, in welcher Projekte, aber auch Pakete zu dem jeweiligen Projekt hinzugefügt werden können.

vue ui

https://cli.vuejs.org/ui-new-project.png

Conditional

<template>
	<div id="conditional-rendering">
	  <span v-if="seen">Now you see me</span>
	</div>
</template>

const ConditionalRendering = {
  data() {
    return {
      seen: true
    }
  }
}

Vue.createApp(ConditionalRendering).mount('#conditional-rendering')

Loops

<div id="list-rendering">
  <ol>
    <li v-for="todo in todos">
      {{ todo.text }}
    </li>
  </ol>
</div>

const ListRendering = {
  data() {
    return {
      todos: [
        { text: 'Learn JavaScript' },
        { text: 'Learn Vue' },
        { text: 'Build something awesome' }
      ]
    }
  }
}

Vue.createApp(ListRendering).mount('#list-rendering')

Event Handling

<div id="basic-event">
  <button @click="counter += 1">Add 1</button>
  <p>The button above has been clicked {{ counter }} times.</p>
</div>

Vue.createApp({
  data() {
    return {
      counter: 1
    }
  }
}).mount('#basic-event')

# submit form
<form @submit="checkForm">
...

Lifecycle

https://v3.vuejs.org/images/lifecycle.png

VueJs 3 Major Release 🚀

Release v3.0.0 One Piece · vuejs/vue-next

Breaking Changes

  • Vue 3 has a new Global API, now we use createApp instead of new Vue({})
  • No more support for Filters, you should use computed proprieties or methods instead.
  • $on, $off, and $once methods are removed
  • data option should always be declared as a function
  • defineAsyncComponent is the new method used to import and deal with async components

Vite

Alternativ kann man Vite verwenden, ein schnelles Build-Tool für moderne JavaScript-Projekte. Es verwendet während der Entwicklung Browser-native ES-Module in Kombination mit Hot Module Replacement. Bei diesem Ansatz müssen nur die Dateien gebündelt werden, die tatsächlich benötigt werden.

npm init vite-app hello-world


Neue Features

Composition API

Eine der wichtigsten Änderungen ist die Compositon API. Sie ermöglicht eine funktionsbasierte Schreibweise zum Schreiben von Komponenten.

Die Logik kann in "composition-functions" kapseln werden, welche komponentenübergreifend wiederverwenden werden kann.

Die Components sind so wenig komplex und wartbarer.

Einfaches Beispiel:

<template>
  <div class="about">
    <h1>This is an about page</h1>
    <h1>{{ number }}</h1>
    <button @click="incrementNumber">increment</button>
    <button @click="decrementNumber">increment</button>
  </div>
</template>

<script lang="ts">
import { ref, defineComponent } from "vue";

export default defineComponent({
  name: "Home",
  setup() {
    const number = ref(0);
    const incrementNumber = () => number.value++;
    const decrementNumber = () => number.value--;

    return { number, incrementNumber, decrementNumber };
  }
});
</script>

little-morning-94kfx

ref bezieht sich auf Reactive Reference

    const number = ref(0);

Bei Verwendung der Composition-API müssen die Werte zurückgegeben werden, die unser Template benötigen. Das erzeugt etwas mehr Code, aber dadurch lässt sich steuern, was wirklich verfügbar gemacht werden soll.

Suspense

Suspense ist eine native Vue-Komponente zur Behandlung asynchroner Abhängigkeiten. Mit Suspense lässt sich steuern, was gerendert werden soll, bis eine Bedingung erfüllt ist und unsere asynchrone Komponente bereit ist.

Darüber hinaus ist es eine bessere Möglichkeit, mehrere API-Aufrufe von verschiedenen Komponenten zu verarbeiten, als sich auf eine v-if-Ladebedingung zu verlassen.

<template>
  <Suspense>
    <template #default>
      <GameList /> <!-- async component you want to render -->
    </template>
    <template #fallback>
      Loading ...
    </template>
  </Suspense>
</template>

Teleport

Teleport kann verwenden werden, um Komponenten zu erstellen, welche in verschiedene Teile der App verschoben / teleportiert werden können, indem wir auswählen, wo (DOM-Element) platziert werden soll, auch wenn an diesem Ort Ihre App nicht bereitgestellt ist.

Teleport verwendet die DOM-Elemente wieder, sodass der Status erhalten bleibt.

<div id="app"></div>
<div id="move-to-here"></div>
 
...
<template>
  <teleport to="#move-to-here">
    This should live outside of #app
  </teleport>
</template>

Der Target lässt sich in verschiedenen Variationen auswählen:

<teleport to="#id">
<teleport to=".class">
<teleport to="[data-modal]">

Fragments

In Vue 2 konnte keine Vorlage mit zwei Elementen im selben Stamm erstellt werden. Der Grund dafür ist, dass die Vue-Instanz, die eine Vue-Componente darstellt, in ein einzelnes DOM Element gebunden werden muss.

Vue 2:

<template>
  <div class="about">
		...
  </div>
</template>

Vue 3:

<template>
  <div class="about">
    ...
	<div>
  <div class="about-footer">
		...
  </div>
</template>

Weitere Änderungen

  • Bessere TypeScript-Unterstützung → Vue 3 ist vollständig in TypeScript geschrieben.
    • bessere Typdefinitionen + Intellisense + Autocompletetion
  • Improved Performance
  • smaller bundle sizes
  • treeshaking

Falls Material UI verwendet werden möchte, kann Vuetify verwendet werden:

Vuetify - A Material Design Framework for Vue.js

Other Stuff...

Lieber keine class component mehr benutzen

https://github.com/vuejs/rfcs/pull/17#issuecomment-494242121

Drawbacks:

https://github.com/vuejs/rfcs/blob/class-api/active-rfcs/0000-class-api.md#motivation

Umut Tufanoglu - 7.10.2020
JavaScript

JPA Reference with "orphanRemoval"

Orphan Removal

JPA 2 supports an additional and more aggressive remove cascading mode which can be specified using the orphanRemoval element of the @onetoone and @onetomany annotations:

JPA will keep track of the referencing Objects which need to be removed, when its managed via an PersistentBag:

   @OneToMany(..., orphanRemoval = true)
   private List<Address> addresses = new ArrayList<>();
      
   ...

   employee = employeeRepository.findById(id);
   employee.getAddresses().clear() 

employee.getAdresses() is a hibernate.PersistenceBag therefore hibernate will track the changes within the collection and propagate those to the underlying database (like delete the addresses which have been referenced by the employee when orphanRemoval = true)

If we overwrite the Collection, hibernate is unable to tell what has changed and will fail e.g.

   employee = employeeRepository.findById(id);
   employee.setAddresses(findAddresses(employee))

The Error will be something like this when there were Addresses within the Collection

"A collection with cascade=\"all-delete-orphan\" was no longer referenced by the owning entity instance: xxx nested exception is org.hibernate.HibernateException: A collection with cascade=\"all-delete-orphan\" was no longer referenced by the owning entity instance: xxx"
Simon Jakubowski - 7.10.2020
DatabasesJava

Email rules for shared mail box

We recently introduced a shared mailbox to our office365. I added an alias called flaschenpost@newcubator.com to it, to receive all their mails including the invoices. Now I needed a rule to forward the invoices to our invoice@newcubator.com mailbox. Creating a rule for the shared mailbox is easy when you know where to look! In short: you have to open the shared mailbox in a separate browser tab and then create the rule under the settings menu as normal. To open the mailbox in a separate tab click on your profile icon and then on open new mailbox / Weiteres Postfach öffnen. Enter the name of the mailbox and voila! Now you can create rules for that mailbox.

Sven Röttering - 30.9.2020
Toolnewcubator

AWS Secrets Manager

Credentials, wie Access Tokens, DB-Zugriffdaten oder andere lassen sich mit dem AWS Secrets Manager speichern, damit sie nicht in Lambda Funktionen offen in den Environment Variablen liegen.

var AWS = require('aws-sdk'),
    region = "eu-central-1",
    secretName = "gitlabAPI/privateToken/jzbick",
    secret,
    decodedBinarySecret;

var client = new AWS.SecretsManager({
    region: region
});

client.getSecretValue({SecretId: secretName}, function(err, data) {
    if (err) {
        throw err;
    }
    else {
        if ('SecretString' in data) {
            secret = data.SecretString;
        } else {
            let buff = new Buffer(data.SecretBinary, 'base64');
            decodedBinarySecret = buff.toString('ascii');
        }
    }
    
    // Your code goes here. 
});

gekürztes Code Beispiel; Volle Länge findet man auf der jeweiligen Secrets Seite

Beispiel data Objekt:

{
  ARN: 'arn:aws:secretsmanager:eu-central-1:565575105323:secret:gitlabAPI/privateToken/jzbick-XwWr5W',
  Name: 'gitlabAPI/privateToken/jzbick',
  VersionId: '30262c69-1f91-4c26-9131-67b1de03eebd',
  SecretString: '{"PRIVATE_TOKEN":"jHpce7LGBahALXd4mRcp"}',
  VersionStages: [ 'AWSCURRENT' ],
  CreatedDate: 2020-09-24T09:14:34.864Z
}
Jonathan Zbick - 30.9.2020
AWS

content-visibility

Rendering performance boost ab Chrome 85. Ermöglicht es dem user agent, die Rendering-Arbeit eines Elements, einschließlich Layout und Paiting zu überspringen, bis sie benötigt wird.

https://www.notion.so/content-visibility-582037349d55442597462ee774cd9d22

content-visibility

  • Boost rendering performance
  • Ab Chrome 85 verfügbar
  • Support nur Chrome 85 aufwärts
  • Firefox will es noch einführen
  • https://caniuse.com/?search=content-visibility
  • Ermöglicht dem user agent, die Rendering-Arbeit eines Elements, einschließlich Layout und Painting, zu überspringen, bis sie benötigt wird
  • Da das Rendern übersprungen wird und ein großer Teil Ihres Inhalts außerhalb des Bildschirms angezeigt wird, wird der initial load schneller

Im folgenden beispiel haben wir lila markierten container die Eigentschaft

content-visibility: auto

Die Performance ist in diesem Beispiel bis zu 7x gestiegen

https://webdev.imgix.net/content-visibility/demo.jpg

content-visibility hat 3 Werte:

  • visible

    → Keine Änderung

  • hidden

    → Ein mix zwischen display: none und visibility: hidden. Startet mit display: hidden und wird hinterher visibility hidden

  • auto

    → rendert das Element sobald es vom Browser benötigt wird.

    .element {
        content-visibility:auto;
    }

Ohne content-visibility

https://res.cloudinary.com/practicaldev/image/fetch/s--3v4V-T1H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600617553251/eXoyruH_a.png

Mit content visibility

https://res.cloudinary.com/practicaldev/image/fetch/s--3A-Wul7g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1600617628097/TnFz-bqnQ.png

443ms → 415ms → 28ms schneller

content-visibility: the new CSS property that boosts your rendering performance

I made my website 28ms faster with content-visibility 🤓

Umut Tufanoglu - 30.9.2020
Performance

Finde den TypeScript Fehler 🤔

Default configurations

let netConfig = config.get("network");

let addr = netConfig?.server?.addr || "ws://localhost";

let port = netConfig?.server?.port || 8888;

let compressed = netConfig?.enableCompression || true;

connectToServer(addr, port, compressed);

Answer

Wenn enableCompression=false ist würden wir trotzdem true bekommen. Da Truthy nicht immer auch für absent/present genutzt werden kann. Die Lösung hierfür ist Nullish coalescing.

let netConfig = config.get("network");

let addr = netConfig?.server?.addr ?? "ws://localhost";

let port = netConfig?.server?.port ?? 8888;

let compressed = netConfig?.enableCompression ?? true;

connectToServer(addr, port, compressed);
Jan Sauer - 30.9.2020
JavaScriptQuiz

Lombok @Builder @Singular

@Builder can generate so-called 'singular' methods for collection parameters/fields. These take 1 element instead of an entire list, and add the element to the list. (Promoted in lombok v1.16.0.)

Example definition and usage in the fieldmanagment project.

Jan Sauer - 23.9.2020
Java

Wir freuen uns Sie kennen zu lernen

Hat Sie unser Angebot überzeugt? Dann freuen wir uns, Sie kennen zu lernen. Kontaktieren Sie uns gerne für ein unverbindliches Erstgespräch.

newcubator GmbH
Freie-Vogel-Straße 369
44269 Dortmund
dortmund@newcubator.com
+49 231/586 873 80
newcubator GmbH
Bödekerstraße 22
30161 Hannover
hannover@newcubator.com
+49 511/957 313 00