Samstag, November 24, 2018

Javascript Object Destruction

Dieses Feature wünsche ich mir für Java: Objekt Dekonstruktion.

Variablen austauschen:

Das auslesen von Rückgabewerten aus Arrays bzw. das ignorieren von Rückgabewerten.

Das teilweise übernehmen von Objekteigenschaften.

Zuweisen mit neuem Variablennamen:

Quelle: Devloper Mozilla

Mittwoch, Oktober 31, 2018

CompletableFuture II

Das CompletableFuture wurde mit Java 8 eingeführt und ist ein Teil des Packages java.util.concurrent. Ziel: Verkettung von asynchronen Aufgaben. Als Einstiegspunkt dienen die Methoden #get(...) und #complete(...). #get(...) stellt den aktiven Thread wartend und setzt die Ausführung erst dann fort, wenn ein paralleler Thread die Methode #complete(...) ausführt. Folgendes Beispiel zeigt, wie man es nicht umsetzen sollte. Das CompletableFuture wird mit #get() befragt. Da es keinen parallelen Thread gibt, der #complete() aufrufen könnte, wird der Thread ewig warten, wenn wir #get() keinen Timeout Wert mitgeben.

@Test
public void dontDoThat() {
    CompletableFuture<String> cf = new CompletableFuture<>();
    try {
        // cf.get() would wait forever! Don´t do that!
        cf.get(10, TimeUnit.MILLISECONDS);
    } catch (InterruptedException | ExecutionException
            | TimeoutException ex) {

        assertThat(ex).isNotNull();
    }
}

Erfolgreiche asynchrone Verarbeitung

Das erste Beispiel zeigt eine typische (sehr einfache) asynchrone Verarbeitung. Die asynchrone Verarbeitung wird in der Methode #calculateAsync() (siehe [1]) gestartet. CompletableFuture#get() (siehe [2]) wartet auf die Fertigstellung der Berechnung und liefert das berechnete Ergebnis.

In [3] wird ein CompletableFuture direkt mit dem berechneten Ergebnis erzeugt.

/**
 * Startet einen Thread und übergibt als Synchronisationspunkt ein
 * CompletableFuture. Der Thread meldet über CompletableFuture#complete(...)
 * die fertige Berechnung.
 */
private CompletableFuture<String> calculateAsync()
        throws InterruptedException {

    CompletableFuture<String> completableFuture = new CompletableFuture<>();

    Executors.newCachedThreadPool().submit(() -> {
        Thread.sleep(500);
        completableFuture.complete("Hello");
        return null;
    });

    return completableFuture;
}

private CompletableFuture<String> calculateAsync2() {
    return CompletableFuture.completedFuture("Hello2");
}

@Test
public void completableFuture() throws Exception {
    /* (1) */
    CompletableFuture<String> future = calculateAsync();

    /* (2) */
    String result = future.get();
    assertThat(result).isEqualTo("Hello");
    assertThat(future.isCompletedExceptionally()).isFalse();

    /* (3) */
    assertThat(calculateAsync2().get()).isEqualTo("Hello2");
}

Abgebrochene asynchrone Verarbeitung

In dem nächsten Beispiel wird die Verarbeitung über CompletableFuture#cancel(boolean) abgebrochen. Am Synchronisationspunkt #get() erhält der Aufrufer eine CancellationException. Der Parameter, den man #cancel(boolean) übergibt, hat keine Auswirkungen. Der Interrupt-Mechanismus wird für die Ablaufsteuerung von CompletabeleFutures nicht verwendet.

private CompletableFuture<String> calculateAsyncWithCancellation()
        throws InterruptedException {

    CompletableFuture<String> completableFuture = new CompletableFuture<>();

    Executors.newCachedThreadPool().submit(() -> {
        // Die Verarbeitung wird abgebrochen. Der Aufrufer erhaelt eine
        // CancellationException.
        completableFuture.cancel(false);
        return null;
    });

    return completableFuture;
}

@Test
public void cancelCompletableFuture()
        throws InterruptedException, ExecutionException {

    CompletableFuture<String> future = calculateAsyncWithCancellation();

    try {
        future.get(); // CancellationException
        fail("Expected CancellationException");
    } catch (CancellationException ex) {
        assertThat(future.isCancelled()).isTrue();
        assertThat(future.isCompletedExceptionally()).isTrue();
    }
}

Utility Methoden

Neben den oben genannten Möglichkeiten bietet CompletableFuture einen ganzen Blumenstrauß an weiteren hilfreichen Methoden. Z.B. #completeAsync(Supplier) nimmt eine Funktion entgegen, die asynchron mit Hilfe des ForkJoinPool#commonPool() verarbeitet wird.

@Test
public void completeAsyncOfCompletableFuture() throws Exception {
    CompletableFuture<String> cf = new CompletableFuture<>();
    cf.completeAsync(() -> { return "Hallo"; });
    assertThat(cf.get()).isEqualTo("Hallo");
}

Mit #runAsync(Runnable) kann eine parameterlose Funktion übergeben werden. Ein Rückgabeparameter entfällt ebenfalls. In dem Beispiel verwende ich eine Variable, die außerhalb der Funktion liegt. Im Sinne der funktionalen Programmierung ist das nicht optimal. In diesem Fall wöre #completeAsync() die bessere Wahl.

@Test
public void runAsyncOfCompletableFuture() throws Exception {
    final StringBuilder sb = new StringBuilder();
    CompletableFuture<Void> cf = CompletableFuture.runAsync(() -> {
        sb.append("Start calculation ...");
    });

    cf.get();
    assertThat(sb.toString()).isEqualTo("Start calculation ...");
}

Mehrfach Synchronisierung

Um verschiedene nebenläufige Tasks zu einem gemeinsamen Synchronisationspunkt zu bringen, hat CompletableFuture eine Lösung zur Verfügung. In dem Beispiel werden drei CompletableFutures instanziert und per #allOff() zu einem neuen CompletableFuture zusammen gefasst. Der Aufruf von #get() wartete so lange, bis alle drei CompletableFutures ein Ergebnis liefern.

@Test
public void completableFutureWithMultipleParallelTasks() throws Exception {
    CompletableFuture<String> future1 = CompletableFuture
            .supplyAsync(() -> "Hello");
    CompletableFuture<String> future2 = CompletableFuture
            .supplyAsync(() -> "Beautiful");
    CompletableFuture<String> future3 = CompletableFuture
            .supplyAsync(() -> "World");

    CompletableFuture<Void> combinedFuture = CompletableFuture
            .allOf(future1, future2, future3);

    combinedFuture.get();

    assertThat(future1.isDone()).isTrue();
    assertThat(future2.isDone()).isTrue();
    assertThat(future3.isDone()).isTrue();
}

Referenzen

Freitag, Oktober 12, 2018

Links der Woche

Dieses mal gibt es nur drei Links: Adam 55th Airhacks, Joshua Bloch über sein Buch 'Effective Java' und Javascript Pro Tips. UPDATE: Also das ist mittlerweile ein MUSS geworden: Installieren der ZSH Shell unter cygwin.

Donnerstag, September 13, 2018

Links der Woche

UPDATE:

Sonntag, September 09, 2018

JPA Entities, equals und hashCode

Wer hat noch nicht mit seinen Kollegen über die ‘korrekte’ Implementierung von #hashCode() und #equals() diskutiert? Hier kommt meine Zusammenfassung.

Grundlagen

Zunächst die Grundlagen: Welche Bedingungen stellt Java an #hashCode() und #equals()? Da wären:

  1. reflexiv: Für alle x gilt: x.equals(x) liefert immer true zurück.
  2. symmetrisch: Für alle x,y gilt: x.equals(y) == y.equals(x)
  3. transitiv: Für alle x,y,z gilt: x.equals(y) und y.equals(z) dann gilt x.equals(z)
  4. konsistent: Das Ergebnis von #hashCode() und #equals() muss während der gesamten Lebensdauer eines Objekts gleich sein. Konsistenz kann eigentlich nur für unveränderliche Objekte gelten. Oder sagen wir mal so: Es wäre vermutlich ganz praktisch. Allerdings gibt es hier Tricks. Wie z.B. das die Methode #hashCode() eine Konstante zurückliefert. Oder das sich der HashCode nur aus den fachlichen Schlüsseln zusammensetzt.

Das sollte als Einführung reichen. In der JPA Community habe ich 3 Stilrichtungen gefunden, die praktikabel erscheinen. Jede mit gewissen Vor- und Nachteilen. Meine persönliche Präferenz, um das mal vorweg zu nehmen, ist die, die den wenigsten Code erzeugt.

Konsens oder ‘no-go’

Die drei Experten (Gavin King, Vlad Mihalcea, Mark Struberg) sind sich in einer Sache einig. Habe ich eine JPA Entity sollte ich auf gar keinen Fall #equals() und #hashCode() über alle Eigenschaften der Entity ermitteln. Denn wenn ich das tue, was hätte das für die geforderte Eigenschaft ‘konsistent’ zur Folge? Genau. Die Entity müsste unveränderlich sein. D.h. die Code-Generatoren der bekannten IDEs und die Klassen EqualsBuilder oder HashCodeBuilder aus Apache Commons sind tabu.

Variante 1. Die Struberg-Methode | Die Nicht-Implementierung.

Struberg hat einen eigenen Blog. Allein der ist schon empfehlenswert. Der für mich interessante Artikel findet sich hier. Die sogenannte Struberg Variante empfiehlt, auf #equals() und #hashCode zu verzichten. Hauptgrund: Die anderen Varianten (die ich später aufzähle) sind kompliziert und fehleranfällig. Zu dem stellt sich die Frage, benötige ich überhaupt eine spezielle #hashCode() Methode für meine Entity? I.d.R wird dann angeführt, dass die Entities in einem Set gespeichert werden. Also z.B.

@OneToMany 
private Set others;

Aber selbst hier ist die Defaut-Implementierung aus Object absolut ausreichend. Das wird durch zwei Annahmen untermauert. Das erste Argument: Der EntityManager selbst sorgt für die Eindeutigkeit der Objekte im Set. Das zweite Argument, in dem Artikel nicht aufgeführt, aber dennoch interessant: Die Datenbank selbst sorgt mit Unique-Constraints dafür, dass die Elemente im Set eindeutig sind. Allerdings richtig ist der Einwand, dass in diesem Fall das Set nicht mehr selbst in der Lage ist, doppelte Objekte zu erkennen. Aber vielleicht ist in diesem Fall die Validierung in der Geschäftslogik zu lückenhaft?

Wichtig: Das abwägen von Aufwand und Nutzen. Als ‘so-wenig-Code-wie-möglich’ Liebhaber bin ich auf alle Fälle ein Fan dieser Variante.

Variante 2. Hibernate Dokumentation | Der fachliche Schlüssel

In der Hibernate Dokumentation findet sich die Variante 2. Eine Empfehlung lautet aber auch hier, eventuell auf die Implementierung von #hashCode() und #equals() zu verzichten. Will oder kann man das nicht, sollte man den natürlichen Schlüssel der Entity bei der Gestaltung verwenden. Erwähnt wird ebenso, wie bei Struberg oben, dass der EntityManager oder die Session dafür sorgt, dass gleiche Objekte nur einmal instanziert werden. Das Problem kann nur dann auftreten, wenn gleiche Objekte über verschiedene Sessions aus der Datenbank gelesen werden. In diesem Fall würde das #equals(), #hashCode() aus Object zu kurz greifen. Doch man muss sich die Frage stellen, habe ich so eine Situation in meiner Anwendung?

In der Dokumentation findet sich der Hinweis, dass das heranziehen allein der ID aus der Entity i.d.R. nicht ausreicht. Bei Neuinstanzierung einer Entity ist diese Eigenschaft nicht gesetzt und wird erst nach einem flush oder commit der Session in der Entity gesetzt. Damit hätten wir ebenfalls eine Verletzung der Konsistenz. Also bleibt nur der natürliche oder fachliche Schlüssel, der sich nicht ändert und von Anfang an bekannt ist. In dem Beispiel ist es die ISBN eines Buches. Ich verzichte darauf, dass Beispiel hier wiederzugeben. Der interessierte folgt einfach dem Link.

Variante 3. Die Vlad-Methode

Vlad ist der Meinung, dass man #hashCode() und #equals() in jedem Fall implementieren sollte. Er hat für Entities einen sehr guten Test geschrieben, der entscheidet, ob die gewählte Implementierung den Forderungen von #hashCode() und #equals() und den Anforderungen der JPA Spezifikation entspricht. Siehe dafür in seinem GitHub Account oder direkt in der Klasse AbstractEqualityCheckTest.java. Ohne korrekte #hashCode() und #equals() Implementierung wird dieser Test einen Fehler reporten.

In seinem Blog-Artikel unterscheidet Vlad zwischen zwei Typen von Schlüsseln (Identifiables):

Natürliche/Fachliche Schlüssel oder UUIDS

Beiden gemein ist, dass sie bereits vor dem #flush() (Persistierung) in die Datenbank bekannt sind und der Entity zugewiesen werden. In diesen Fällen sollte eine Implementierung so aussehen:

@Entity(name = "Book")
@Table(name = "book")
public class Book 
    implements Identifiable<Long> {

    @Id
    @GeneratedValue
    private Long id;

    private String title;

    @NaturalId
    private String isbn;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Book)) return false;
        Book book = (Book) o;
        return Objects.equals(getIsbn(), book.getIsbn());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getIsbn());
    }

    //Getters and setters omitted for brevity
}

D.h. die Implementierung zieht nur den fachlichen Schlüssel. Alle anderen Eigenschaft werden ignoriert.

Datenbank generierte Schlüssel

In den anderen Fällen, in denen der Schlüssel von der Datenbank generiert wird, empfiehlt er die folgende Implementierung:

@Entity
public class Book implements Identifiable<Long> {

    @Id
    @GeneratedValue
    private Long id;

    private String title;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Book)) return false;
        Book book = (Book) o;
        return id != null && id.equals(o.id);
    }

    @Override
    public int hashCode() {
        return 31;
    }

    //Getters and setters omitted for brevity
}

Wichtig: Die #hashCode() Methode liefert eine Konstante zurück. Damit ist sichergestellt, dass der gleiche HashCode über alle Entity-Persistenz-Zustände geliefert wird.

Weitere Erkenntnisse

So, having a cache is really a great idea, but please do not store JPA entities in the cache. At least not as long as they are managed.

Der Dirty-Check von Hibernate funktioniert NICHT über die #equals() Methode. Hibernate verwaltet ein Duplikat der Entity und fährt über dieses Duplikat einen eigenen Vergleich. Siehe Hibernate dirty check.

Another way is to generated a UUID in the constructor or the getId() method. But this is pretty performance intense and also not very nice to handle on the DB side (large Strings as PK consume a lot more storage in the indexes on disk and in memory).

Referenzen

  1. https://vladmihalcea.com/the-best-way-to-implement-equals-hashcode-and-tostring-with-jpa-and-hibernate/
  2. https://vladmihalcea.com/how-to-implement-equals-and-hashcode-using-the-jpa-entity-identifier/
  3. https://vladmihalcea.com/hibernate-facts-equals-and-hashcode/
  4. http://docs.jboss.org/hibernate/orm/5.3/userguide/html_single/Hibernate_User_Guide.html#mapping-model-pojo-equalshashcode
  5. https://github.com/vladmihalcea/high-performance-java-persistence/blob/master/core/src/test/java/com/vladmihalcea/book/hpjp/hibernate/equality/AbstractEqualityCheckTest.java#L55
  6. https://struberg.wordpress.com/2016/10/15/tostring-equals-and-hashcode-in-jpa-entities
  7. https://courses.vladmihalcea.com/?utm_source=blog&utm_medium=banner&utm_campaign=article
  8. Das gleich Buch wie oben, aber bei amazon.de
  9. Thoughts on Java

Mittwoch, August 29, 2018

Links der Woche

  • Schon mal in Eclipse das Problem gehabt, dass im Editor die Tastenkürzel CTRL-left und CTRL-right nicht funktionierten? Dann einfach den Autostarthaken der Eclipse Startseite abwählen und Eclipse neu starten. Dann funktionierts. Problemlösung gefunden auf Stackoverflow.
  • Rod Johnson, einer der Erfinder von Spring, mit einem Artikel über die Zukunft der 'Software Delivery'.
  • Ein Artikel auf Heise über die zukünftigen Releases von Java. Thema ist der halbjährige Release-Zyklus, die kostenpflichtigen Varianten des Oracle JDKs und die Alternativen der Anbieter wie IBM, RedHat oder das OpenJDK.
  • Ein Podcast von Adam Bien und Elder Moraes über das langweilige JEE. Bzw. warum JEE so effizient in der Entwicklung von Unternehmensanwendungen ist.
  • Microservices sind keine Patentlösung. Vor allem der Ausblick auf die Zukunft von Microservices im letzten Abschnitt des Artikels interessant.

Mittwoch, August 22, 2018

Links der Woche

Samstag, August 11, 2018

Links der Woche

  • Es gibt ein Thunderbird Update.
  • Das Bounded Context Pattern. In dem Artikel findet sich ein Verweis auf MultipleCanonicalModels. Ist das das Ende, der alles vereinheitlichenden Datenmodelle und Modellbegriffe? Vermutlich nicht, da die Ideen schon ein paar Jahre auf dem Buckel haben und es zu reizvoll ist, es dennoch zu versuchen.
  • Schon mal was von der zsh gehört? Hier gibt es ein Video zu den Vorzügen. In schriftlicher Kurzform: zsh kann die gleichen Dinge wie die bash. Um in andere Verzeichnisse zu wechseln muss man kein cd mehr tippen. Außerdem kann man tiefe Verzeichnispfade in Kurzform eintippen und automatisch erweitern lassen. Hört sich alles praktisch an. Ich werde es ausprobieren. Geht das auch mit cygwin? Siehe da: Es geht. Und zwar wie hier beschrieben.
  • Meinen alten Tipp für das öffnen einer cygwin Shell aus Eclipse heraus, muss ich ändern. Auf Stackoverflow findet sich eine bessere Variante.

Montag, Juli 30, 2018

Links der Woche

  • Apache´s XMLBeans ist zurück. Das Projekt war bereits auf der Abschussliste und erlebt ein Comeback. Die Meldung und weitere Infos gibt es auf Heise.
  • Angular 6 ist (schon lange) da. Die neuen Features in der Zusammenfassung.
  • Für die Programmierer von morgen: Codecombat. Das könnte bei meinen Kindern funktionieren.
  • Spring Framework 5.0.8 ist erschienen.
  • Falls ihr eure Kommunikation verbessern möchtet, dann kann ich diesen Youtube Kanal empfehlen.

Montag, Juli 02, 2018

DTOs mit einem Interface

Frage: Lohnt es sich ein DTO (Data Transfer Object) mit einem Interface zu versehen? Aus dem Bauch heraus würde ich sagen nein. Eine Google-Suche nach 'Interface' und 'DTO' bzw. 'Value Object' scheint meine Annahme zu unterstützen. Siehe Stackexchange oder Stackoverflow. Letzter Beitrag erhielt von den Nutzern des Forums eine schlechte Bewertung. Die Begründung: closed as primarily opinion-based.

Und in dieser Bewertung steckt auch schon die Antwort. Die Antwort auf diese Frage ist stark abhängig von der persönlichen Meinung der beteiligten Person. Es gibt kein eindeutiges wahr oder falsch zu dieser Frage. Ich versuche einfach mal ein paar Argumente zu sammeln.

Wann lohnt es sich, ein Interface zu verwenden? Wenn ich mehr als eine Implementierung habe? Wenn mir nur eine sinnvolle Implementierung für ein Interface einfällt, ist es dann noch in Ordnung ein Interface für die Implementierung anzulegen? Bei einem DTO fällt es mir schwer, eine andere Implementierung als die Default-Implementierung vorzustellen. Was ist die Default-Implementierung für ein DTO? Ein Objekt mit ein oder mehreren Eigenschaften, versehen mit einer getter und/oder setter Methode. Erweitere ich das DTO um eine weitere Eigenschaft, muss ich das Interface ebenfalls erweitern, wenn ich möchte, dass die Eigenschaft nach außen sichtbar ist. Wenn ich das nicht möchte, benötigt das DTO nicht die neue Eigenschaft. Zwei DTOs, die die gleiche Schnittstelle implementieren, werden sich gleich Verhalten. Was für ein anderes Verhalten sollte das zweite DTO im Vergleich zu dem Ersten haben?

Wenn ich mich entscheide, dass ein Service ein DTO zurückliefert, treffe ich die architektonische Entscheidung, das ein Service nur banale DTOs zurückliefert. Ich würde vermutlich der allgemeinen Architekturentscheidung widersprechen, wenn ich was anderes als ein DTO zurückgebe. Insofern habe ich Zweifel, dass ein Interface für ein DTO einen Mehrwert bietet.

Allerdings gibt es keinen kategorischen Grund, Interfaces für DTOs nicht zu definieren. Es entsteht im Zweifel erst einmal nur mehr Code. Obwohl die Codevermeidung kein schlechtes Qualitätsziel ist.

Zum Abschluss habe ich ein etwas ungewöhnliches Beispiel für die Verwendung eines DTOs. Schaut euch mal dazu den folgenden Code an:

public interface DataTransferObject {
    Long getId();
    String getName();
    LocalDateTime getBirthday();
    
    default DefaultDataTransferObject newDTO(DataTransferObject dto) {
        DefaultDataTransferObject ddto = new DefaultDataTransferObject(dto.getId()); 
        ddto.setBirthday(dto.getBirthday());
        ddto.setName(dto.getName());
        return ddto;
    }

    public static class DefaultDataTransferObject implements DataTransferObject {
        private final Long id;
        private String name;
        private LocalDateTime birthday;

        public DefaultDataTransferObject(Long id) {
            this.id = id;
        }
        
        @Override
        public Long getId() {
            return id;
        }

        @Override
        public String getName() {
            return name;
        }
        
        public void setName(String name) {
            this.name = name;
        }

        @Override
        public LocalDateTime getBirthday() {
            return birthday;
        }
        
        public void setBirthday(LocalDateTime birthday) {
            this.birthday = birthday;
        }        
    }
}

public class Service {
    public DataTransferObject read(Long id) {
        return DTOMapper.toDto(repository.find(id));
    }

    public DataTransferObject write(DataTransferObject dto) {
        Entity entity = repository.find(dto.getId());
        DTOMapper.from(dto).to(entity);
        return DTOMapper.to(entity);
    }
}

Die Idee ist, dass der Service, der das DTO returniert, in seiner Signatur als Return-Typ das Interface verwendet. Der Aufrufer des Service erhält erst einmal ein nicht veränderliches Objekt. Um Eigenschaften per Setter Methode zu ändern, muss der Aufrufer newDTO aufrufen und erhält eine Kopie des DTOs. An diesem kann er seine Änderungen vornehmen und ggf. das neue DTO einem Service übergeben.

Welchen Mehrwert hat diese Lösung? Nun zunächst steht dem Aufrufer das Original DTO zur Verfügung, welches nicht verändert werden kann. Das kann praktisch sein, wenn man Änderungen im Client mit dem Original vergleichen möchte. Ein Argument für dieses Konstrukt ist die explizite Kennzeichnung von Änderungen am DTO. Der Service-Benutzer muss sich aktiv entscheiden newDTO() auzurufen und erhält dann ein neues Objekt. Erst jetzt kann er die Setter-Methoden aufrufen. Ein unveränderliches DTO hat durchaus einen gewissen Mehrwert, insbesondere wenn man einen funktionalen Programmierstil pflegt.

Donnerstag, Juni 28, 2018

Links der Woche

  • Eclipse PHOTON ist da.
  • WHATWG über Fortschritte und Ideen bei der Standardisierung von HTML. Hier finden sich interessierte Menschen, die eher einen pragmatischen Ansatz einsetzen, um die Standardisierung von HTML voranzutreiben. Also ein Gegenentwurf zum W3C. Interessant finde ich das Motto: Please leave your sense of logic at the door, thanks!
  • Die Javascript Engine Nashorn soll aus dem JDK entfernt werden. Damit geht Oracle den Weg konsequent weiter bei der Entschlackung des JDKs.
  • Einen kurzen Blog-Post, wann es sich lohnt einen Testfall zu automatisieren.
  • Eine Buchempfehlung: 'Wie man sie alle rumkriegt' von Scott Adams. Genau. Das ist der Erfinder der Dilbert-Comics, der den Wahlsieg von Trump vorhergesagt hat und dafür gehasst wird.
  • Und noch eine Buchempfehlung: Homo Deus, Eine Geschichte der Zeit. Ich habe mir die Hörbuchversion angehört. Sehr unterhaltend, die Schlussfolgerungen nachvollziehbar, natürlich eher populärwissenschaftlich. Anhand der Geschichte des Menschen versucht der Autor die Zukunft vorherzusagen.

Donnerstag, Juni 14, 2018

Die Links der Woche...

  • Die Browser unterstützen endlich Modules. Eine Überblick verschafft der Artikel Basics of modular Javascript. Verwendet jemand diese Konzepte bereits in seinem Produktionscode?
  • Schon mal was von Processing gehört? Ich bin schon lange auf der Suche nach einer Programmiersprache, die meine Kinder etwas mehr fesselt. Nach einem Selbstversuch habe ich leise Zweifel, dass Processing Begeisterung bei den Kids weckt. Rechtecke, Ellipsen. Sehr schön. Aber nicht spannend. Hat schon mal jemand Minecraft Educations ausprobiert? Das Lizenz Modell erscheint mir etwas umständlich. Mit Lego Mindstorms bzw. in Kombination mit Open Roberta hatte ich kleine Erfolge. Ebenfalls gut aufgenommen wurde Blockly. Eine echte intrinsische Eigeninitiative ist beim Nachwuchs allerdings nicht entstanden.
  • Nach dem Aufschrei über die Veräußerung von GitHub an Microsoft, habe ich mir mal GitLab angeschaut. Auf den ersten Blick eine 1:1 Kopie von GitHub. Allerdings bietet GitLab eine Docker Registry an. Das finde ich interessant.
  • Der Schachblog der FAZ.

Freitag, Juni 08, 2018

Links der Woche (EE8, Github, Microsoft, Angular)

  • Wildfly (ehemals JBoss) liefert eine erste, fast vollständige, EE8 kompatible Version aus. Ein guter Zeitpunkt um mal in die EE8 Neuerungen reinzuschauen. Große Versionssprünge gibt es in den Modulen
    • 'Java Servlet' (3.1 nach 4.0)
    • 'Contexts and Dependency Injection for Java' (1.2 nach 2.0)
    • und 'Bean Validation' (1.2 nach 2.0).
    Die Neuerungen aus HTTP/2 haben großen Einfluß auf die Servlet Spezifikation. Hier gibt es einen guten Überblick über die Probleme mit HTTP/1 und die Ziele von HTTP/2. Adam Bien liefert ein pragmatisches Beispiel zu Server-Push. CDI (Context and Dependency Injection). Da lohnt sich ein Blick in die Referenzimplementierung Weld. Ich muss zugeben, dass ich in meinem beruflichen Umfeld für CDI bisher noch keinen Bedarf hatte. Im Jaxenter gibt es weitere Infos. Zu dem Thema Bean Validation geht es hier lang.
  • Der Angular Update Guide: Update Angular. Ein kleines Wunder. Und das
    npm install rxjs@6 rxjs-compat@6 --save
    soll auch helfen.
  • Microsoft übernimmt GitHub. Welche Strategie steckt dahinter? Wie will Microsoft mit Github Geld verdienen? Vielleicht sind es die Daten, die Github über uns gesammelt hat? Oder die Plattform GitHub an sich? GitHub hat Sourceforge als führende Plattform für OpenSource Code abgelöst und die Idee des kollaborativen Arbeiten mit Hilfe von GIT ins Web gebracht. Meinen ersten Pull-Request habe ich mit GitHub erstellt (oder war es Bitbucket?). Zu dem hat Microsoft mit VSCode und Typescript (mindestens) zwei sehr bekannte Projekte auf der Plattform. Insgesamt besitzt Microsoft 1836 Repositories auf Github. Auf Heise gibt es hier und hier einen kritischen Bericht zu der Übernahme.
  • Thema Finanzen: Der Finanzwesir beleuchtet die Frage nach dem optimalen ETF und warum diese Frage bzw. die Suche nach einer Antwort vermutlich nur Zeitverschwendung ist.

UPDATE: Zu dem Thema CDI habe ich einen alten Artikel von Adam Bien auf Oracle.com gefunden. Es wird Zeit, dass ich mich mit dem Thema mehr beschäftige.

UPDATE: Jetzt weiß ich auch, warum mein CDI Kenntnisse eher sporadischer Natur sind. Spring unterstützt CDI gar nicht erst vollumfänglich. Und wird es vermutlich auch in Zukunft nicht.

Dienstag, Mai 29, 2018

Links der Woche

  • Eine Sammlung der 75 besten(?) Blogs über das Testen von Software: abtstracta.us/blog/75-best-software-testing-blogs
  • Werden manuelle Tests benötigt? Eine Antwort versucht dieser Blog zu geben.
  • Und hier ein Beitrag zu dem Thema, wann ist Testautomatisierung sinnvoll.
  • Ein Post über das Löschen von automatisierten Test.
  • Wie ist mit nicht-deterministischen Tests umzugehen? Dieser Blog versucht das Thema zu beleuchten.
  • Google´s Guava ist mittlerweile ein alter Hut und mit Java 8 sind viele Ideen aus Guava mit ins JDK eingeflossen. Dennoch lohnt sich ein Blick. Beispiel: Ranges, Throwables, Graphs
  • Wiremock simuliert HTTP basierte APIs. Interessant ist die Wiremock API selber. Die Aufrufe für das Starten/Stoppen und Stubben der Methoden kann man bequem im Testcode integrieren oder man startet Wiremock als eigenständigen Service.
  • Zahlen-, Datums- oder Währungskonvertierungen in Javascript? Dann empfiehlt sich Globalize.
  • Ein Texteditor für das Web. Im Mittelpunkt der Funktionalität steht das gemeinsame, gleichzeitige Arbeiten an einem Dokument.
  • Fefes Blog. Kennt ihr schon, oder?
  • Brewcraft, die wahre Kunst Bier zu brauen. Hier gibt es alles für den Hobbybrauer. Mit einem interessanten Artikel über alkoholfreie Biere.
  • Das java.util.Optional lässt mich nicht in Ruhe. Auf der einen Seite bietet es neben #isPresent() nette Abkürzungen wie #ifPresent(), #orElse() oder #orElseThrows(). Auf der anderen Seite habe ich im Alltag das Gefühl, dass das Optional eine inflationäre Verwendung findet. Im www fand ich dazu die folgenden Artikel. Eine allgemeine Empfehlung lautet:
    • Never, ever, use null for an Optional variable or return value.
    • Never use Optional.get() unless you can prove that the Optional is present.
    • Prefer alternative APIs over Optional.isPresent() and Optional.get().
    • It’s generally a bad idea to create an Optional for the specific purpose of chaining methods from it to get a value.
    • If an Optional chain has a nested Optional chain, or has an intermediate result of Optional, it’s probably too complex.
    • Avoid using Optional in fields, method parameters, and collections.On a related note, I thought of another rule after I presented the session: Don’t use an Optional to wrap any collection type (List, Set, Map). Instead, use an empty collection to represent the absence of values.

Dienstag, Mai 22, 2018

Hibernate und java.util.Date

In der Hibernate Welt geschehen manchmal unerklärliche Dinge. In diesem Fall war es der java.util.Date Typ einer Eigenschaft aus einer Hibernate Entity. Dieses Datumsfeld wurde für einen Vergleich mit einem anderen Datum herangezogen. Als Beispiel dient die Entity Person mit dem Datumsfeld #geburtstag. Die interessanten Dinge finden sich in (1) und (2). Bevor die Entity in der Datenbank angelegt wird, ist alles wie erwartet. Das java.util.Date ist ein java.util.Date. Der Vergleich liefert ebenfalls ein positives Ergebnis.

@Entity
@Table("PERSON")
public class Person {
    @Id
    @Column(name = "PERSON_ID")
    private Long personId;

    @Column(name = "NAME")
    private String name;

    @Column(name = "VORNAME")
    private String vorname;

    @Column(name = "GEBURTSTAG")
    private java.util.Date geburtstag;

    ...
}

final Date date = new DateTime(2018, 5, 22, 17, 0, 0).toDate();

Person person = new Person();
person.setGeburtstag(date);
person.setName("Name");
person.setVorname("Vorname");

// (1) Vergleich vor #save() und #refresh()
assertThat(person.getGeburtstag()).isInstanceOf(Date.class);
assertThat(person.getGeburtstag()).isNotInstanceOf(java.sql.Timestamp.class);
assertThat(person.getGeburtstag()).isEqualTo(date);

getSessionFactory().getCurrentSession().saveOrUpdate(person);
getSessionFactory().getCurrentSession().refresh(person);

// (2) Vergleich nach #save() und #refresh()
assertThat(person.getGeburtstag()).isInstanceOf(Date.class);
assertThat(person.getGeburtstag()).isInstanceOf(java.sql.Timestamp.class);
assertThat(person.getGeburtstag()).isNotEqualTo(date);
// IS NOT EQUAL, weil java.sql.Timestamp!
assertThat(now).isEqualTo(newRound.getDateTime());
// IS EQUAL! java.util.Date benutzt für den Vergleich long getTime()

Nach dem persistieren der Daten geschehen die bemerkenswerten Dinge. Aus dem java.util.Date wird ein java.sql.Timestamp. Das wäre nicht weiter tragisch, wenn nicht der Vergleich assertThat(person.getGeburtstag()).isNotEqualTo(now); positiv ausfallen würde. Was ist passiert? Mit dem refresh wurde die Entity Person neu aus der Datenbank gelesen, d.h. Hibernate liest per JDBC Verbindung die Daten aus der Datenbank. Für eine Timestamp Spalte lautet der entsprechende JDBC Typ java.sql.Timestamp, welcher von java.util.Date abgeleitet ist. In der #equals() Methode von java.sql.Timestamp findet sich der Hinweis:

true if the given Object is an instance of a Timestamp that is equal
to this Timestamp object; false otherwise

D.h. ein Vergleich von java.sql.Timestamp und java.util.Date ist immer false. Umgekehrt funktioniert der Vergleich: assertThat(now).isEqualTo(newRound.getDateTime());, da java.util.Date#equals() für den Vergleich auf das Ergebnis der Methode #getTime() zugreift. Das beste ist, man umgeht dieses Problem und verwendet gleich das java.time.LocalDateTime aus JDK 8 oder höher. Falls diese Option nicht besteht, empfiehlt sich für den Vergleich die #compare() Methode. java.sql.Timestamp implementiert #compare(Timestamp) und ein #compare(Date).

Donnerstag, Mai 17, 2018

Mockito Stubbing

Mockito gibt dem Entwickler zwei Möglichkeiten an die Hand, Methoden zu stubben. Variante 1, und vermutlich die beliebteste, ist die when/thenReturn Variante. Die Variante 2 doReturn/when dreht die Syntax um. Ein wesentlicher Unterschied zwischen den beiden Methoden ist die Typsicherheit der Variante 1.

when(mockOfClassXy.methodCall(anyParam())).thenReturn(anObject);

Der Typ von anObject muss dem Rückgabetyp der Methode #methodCall(...) entsprechen. Im Gegensatz zu der Variante 2

doReturn(anObject).when(mockOfClassXy).methodCall(anyParam());

kann anObject ein beliebiger Typ sein. Der Fehler wird erst zur Laufzeit entdeckt. Für das Stubben von void Methoden muss auf Variante 2 zurückgegriffen werden. Statt doReturn wird doNothing verwendet. Beispiel:

doNothing().when(mockOfClassA).voidMethodCall(anyParam());

Das stört bei strikter Verwendung von Variante 1 den Lesefluß. Teilweise gibt es hier die Empfehlung ganz auf Variante 1 zu verzichten und komplett auf Variante 2 umzusteigen. Wie gesagt, würde man dann auf die Typprüfung verzichten. Insbesondere bei ‘großen’ Projekten mit langen Testausführungszeiten wäre das vermutlich ein Problem.

Auf Stackoverflow finden sich zu dem Thema massig Einsendungen. Hier ein Beispiel:
Mockito when/thenReturn vs doReturn/when

Links der Woche

  • CSV Dateien verarbeiten mit Javascript? Vielleicht verrückt. Hier ist eine Lösung: papaparse
  • Auf Heise gibt es einen Kommentar zu den aktuellen Problemen mit EFail und der Aufregung, dass PGP kaputt sei: heise.de
  • Eine Javascript Bibliothek zum Zeichnen von Diagrammen. Die Diagramme versuchen möglichst handgemalt auszusehen. Das lässt das Ganze weniger steril wirken: Rough.js
  • Für C++ Programmierer ein Muss. Der CPP Core Guide von und mit Bjarne Stroustrup zu finden auf GitHub:
  • Eine Alternative zu Angular und anderen -eher schwergewichtigen- Frameworks. cujojs.com. Cujo orientiert sich wieder mehr an den Web-Standards und an den Möglichkeiten, die Javascript bietet.
  • Fear of the Dark. Interpretiert von den Mozart Heros: Fear of the Dark

AssertJ und java.util.List

AssertJ hat eine praktische Möglichkeit, Listen in JUnit Tests abzuprüfen. Insbesondere, wenn in der Liste komplexe Objekte abgelegt sind, s...