Mittwoch, 22. Juni 2016

Pair Programming & das Gehirn

Mitte Mai haben Stephan Kraus und ich auf der SEACON einen Vortrag über Pair-Programming-Coaching im Großprojekt gehalten. Wir haben dabei von unseren Erfahrungen mit der Neu- und Weiterentwicklung einer großen E-Commerce-Plattform berichtet.

Das Coaching bieten wir dort als Angebot an die zahlreichen Teams an, um Pair Programming einfach mal ein paar Wochen während der ganz normalen Arbeit kennenzulernen (bzw. zu intensivieren), um die Vorzüge von kontinuierlichem Wissenstransfer und gegenseitiger Qualitätsverbesserung zu erleben. Immer im Wissen, dass man auch bei schon bei ziemlich guter Qualität immer noch besser werden kann – weil wir als Menschen Fehler machen (aus denen wir als Team viel lernen können) und weil auch Technik nicht perfekt ist.

Spannend war, dass bei der Konferenz direkt nach uns der Vortrag von Julia Dellnitz und Jan Gentsch über Brain Patterns in der Softwareentwicklung stattfand – wo ganz nebenbei ;-) erklärt wurde, warum man mit Pair Programming die typischen Gehirn-Fallen, in die man sonst leicht bei der Kopfarbeit hineintappt, elegant austrickst:
  • Unser Gehirn interpretiert unklare Dinge so, wie sie uns gerade passen. Natürliche Sprache (zwischen Fachbereich und Entwickler, aber auch zwischen den Entwicklern selbst!) ist oft nicht eindeutig... Pair Programming hilft hier, indem das, was man meint, zügig als Programmcode hingeschrieben und dann vom Pair verbessert bzw. vervollständigt wird. Programmierer können erfahrungsgemäß über und mit Code viel klarer diskutieren.
  • Wir können alleine nicht gleichzeitig über das "Was" und das "Wie" nachdenken. Die zwei Rollen beim Pair Programming decken aber beides ab: Der Driver an der Tastatur kümmert sich um die Implementierung (das "Wie"), der Navigator als strategischer Denker ist für das "Was" zuständig. Und weil die Rollen in Mikroiterationen ständig wechseln, kann dann jeder doch beides zur Lösung beitragen.
Die Patterns erklären außerdem, warum es wichtig ist, Pair Programming als sehr intensive Form der Zusammenarbeit zu üben:
  • Sozialer Schmerz durch offenes, ehrliches Feedback wird im Gehirn wie physischer Schmerz empfunden. Das Geben und Annehmen von konstruktivem Feedback muss daher Schritt für Schritt gelernt und verbessert werden, damit es von den Team-Mitgliedern nicht als persönlicher Angriff empfunden wird.
  • Ich als der beste Programmierer der Welt muss lernen, dass ich vielleicht doch mal einen Fehler mache... und dass meine Kollegen manchmal auch echt gute Ideen haben.
Der Vortrag war eine schöne Bestätigung, dass wir mit der Förderung von Pair Programming als wichtiger XP-Praktik auf dem richtigen Weg sind. Die kurze, schriftliche Zusammenfassung inkl. Brain-O-Mat sollte jeder Kopfarbeiter mal gelesen haben!

Samstag, 19. März 2016

Closures in Clojure

Eine Sprache, die nach Closures benannt ist (und genauso ausgesprochen wird), sollte ziemlich gut mit Closures umgehen können :-). Das Zähler-Beispiel für Java, Groovy, Scala etc. sieht in Clojure wie folgt aus:

; closures.clj

(defn zaehlerMitStartwert [startwert]
  (let [zaehler (atom startwert)]
    (fn [] (swap! zaehler inc))))

(def next1 (zaehlerMitStartwert 10))
(def next2 (zaehlerMitStartwert 20))

(println (next1))  ;; 11
(println (next2))  ;; 21
(println (next2))  ;; 22
(println (next1))  ;; 12

In der Funktion zaehlerMitStartwert wird im let-Block ein lokales Binding für zaehler angelegt. Der Wert von zaehler ist ein Atom mit dem übergebenen startwert. Ein Atom speichert in Clojure einen Zustand, der threadsicher ausgetauscht werden kann. Rückgabe von zaehlerMitStartwert ist eine Funktion ohne Parameter: (fn [] ...) - dies ist die Closure, die die freie Variable zaehler außerhalb der Closure-Funktion bindet (umschließt). Die Closure-Funktion verändert (swap!t) den zaehler-Wert mithilfe der inc-Funktion und gibt den neuen (reingeswap!ten) Wert zurück.

Dann definieren wir zwei globale Variablen next1 und next2, die mit je einer Closure-Instanz initialisiert werden. Diese Funktionen werden mit der Clojure- bzw. Lisp-typischen Syntax (next1) aufgerufen (statt next1() o.ä.).

Mittwoch, 16. März 2016

Closures in Groovy

Beim JavaLand 2016 vor einer Woche hat Dierk König einen schönen Einstieg in die elegante und kompakte Ausdrucksweise von Groovy gegeben. Dabei hat er als Closure-Beispiel einen Zähler verwendet, den ich hier – weil er so gut zu meinen bisherigen Closure-Beispielen (u.a. für Java, JavaScript und Scala) passt – zeigen möchte (Fehler im Code gehen selbstverständlich auf mein Konto ;-):

// closures.groovy

Closure zaehlerMitStartwert(startwert) {
  return {
    startwert++
  }
}

def next1 = zaehlerMitStartwert(10)
def next2 = zaehlerMitStartwert(20)

println next1()  // 10
println next2()  // 20
println next2()  // 21
println next1()  // 11

Das return in der Funktion zaehlerMitStartwert gibt die Closure – den darauffolgenden Block mit geschweiften Klammern und der Zähl-Anweisung – zurück. Im Block selbst ist kein return notwendig, weil hier für den Compiler klar ist, dass die letzte (und hier einzige) Anweisung im Block das Ergebnis der Block-Funktion ist. Man sieht sehr schön, dass Groovy-Closures problemlos freie Variablen außerhalb des Closure-Blocks binden - so, wie das auch bei Scala der Fall ist (aber anders als bei Java, wo normalerweise nur final-Werte und nur mit Tricks Variablen gebunden werden können).

Wer das Groovy-Skript ausprobieren möchte, kann es einfach in die Groovy-Web-Console kopieren und dort ausführen.

Dienstag, 1. März 2016

Closures in Java

Java 8 ist nun bald zwei Jahre alt – eine gute Gelegenheit, meine kleine Closures-Reihe weiterzuführen. Nach Scala, JavaFX und JavaScript sind heute also Closures in Java an der Reihe. Das Zähler-Beispiel sieht mit den Lambda-Ausdrücken aus Java 8 so aus:
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.IntSupplier;

public class ClosuresJava8 {

  static IntSupplier zaehlerMitStartwert(int startwert) {

    AtomicInteger n = new AtomicInteger(startwert);

    IntSupplier s = () -> {
      return n.incrementAndGet();
    };

    return s;
  }

  public static void main(String[] args) {

    IntSupplier next1 = zaehlerMitStartwert(10);
    IntSupplier next2 = zaehlerMitStartwert(20);

    System.out.println( next1.getAsInt() ); // 11
    System.out.println( next2.getAsInt() ); // 21
    System.out.println( next2.getAsInt() ); // 22
    System.out.println( next1.getAsInt() ); // 12
  }
}
Die Methode zaehlerMitStartwert() gibt eine IntSupplier-Lambda-Funktion zurück. IntSupplier ist ein sogenanntes "funktionales Interface", d.h. ein Interface mit genau einer Methode (in diesem Fall getAsInt()). Ein "Supplier" bezeichnet dabei eine Methode ohne Parameter, die einen Rückgabewert liefert.

Der Lambda-Ausdruck ist dabei so etwas wie eine Kurzschreibweise für ein anonymes Objekt des IntSupplier-Interfaces, wobei das new, der Interface-Name und der Methodenname weggelassen werden. Die Anweisung im Lambda-Ausdruck ("return n.incrementAndGet();") wird dabei zum Rumpf der unsichtbaren getAsInt()-Methode.

Im Lambda-Ausdruck wird der übergebene Startwert erhöht und zurückgegeben. Allerdings müssen die gebundenen Variablen außerhalb des Lambda-Ausdrucks in Java final oder "effectively final" sein (d.h. sie dürfen nicht verändert werden, damit der Compiler final annehmen kann). Deshalb lassen wir den Lambda-Ausdruck ein AtomicInteger-Objekt binden – der Inhalt des AtomicInteger-Objektes ist veränderbar, die Referenz darauf ist aber wie gewünscht final.

Im obigen Beispiel wird die Lambda-Funktion nur zum einfacheren Verständnis in der lokalen Variablen s zwischengespeichert. Man kann den Lambda-Ausdruck auch direkt als Methodenergebnis zurückgeben:
  static IntSupplier zaehlerMitStartwert(int startwert) {

    AtomicInteger n = new AtomicInteger(startwert);

    return () -> {
      return n.incrementAndGet();
    };
  }
Und da unser Lambda-Ausdruck nur aus einer einzigen Anweisung besteht, deren Ergebnis als Funktionsergebnis zurückgegeben wird, kann man das noch weiter kürzen und die geschweiften Klammern und das return im Lambda-Rumpf weglassen:
  static IntSupplier zaehlerMitStartwert(int startwert) {

    AtomicInteger n = new AtomicInteger(startwert);

    return () -> n.incrementAndGet();
  }
Das sieht doch schon fast richtig funktional aus :-)

Donnerstag, 30. April 2015

Bean-Mapping mit MapStruct

Am vergangenen Wochenende habe ich auf dem MATHEMA Campus einen Vortrag über MapStruct gehalten. MapStruct ist ein Annotations-basierter Code-Generator für Mappings zwischen beliebigen Java-Beans und kann damit hervorragend zum Umkopieren der Daten zwischen den diversen Domänen-Modellen einer Anwendung (JPA, JAXB, REST, sonstige DTOs/POJOs ... ) genutzt werden.

Der generierte Mapping-Code nutzt keine Reflection, sondern Getter- und Setter-Aufrufe – und erreicht damit die Geschwindigkeit von handgeschriebenem Mapping-Code. Ganz nebenbei ist der generierte Code lesbar und verständlich. Das ist wichtig, falls der Projektverantwortliche Angst hat, ein weiteres Werkzeug ins Projekt einzubinden – zur Not stellt man den generierten Code unter Versionskontrolle und pflegt ihn später von Hand weiter (wer einmal MapStruct verwendet hat, wird das aber nicht wollen ;-).

MapStruct wird als Annotations-Prozessor eingebunden, d.h. der Mapping-Code wird beim Aufruf von javac (bzw. bei jedem Speichern z.B. in Eclipse) generiert. Das Prozessor-JAR wird dabei nur zur Compile-Zeit benötigt. Zur Laufzeit ist bei einem Komponentenmodell wie CDI gar kein JAR als Abhängigkeit nötig, ohne Komponentenmodell nur ein winziges JAR < 20 K.

Folgender Code reicht, um den Mapping-Code zwischen einer Kunde-Entity und einem Kunde-DTO generieren zu lassen:

@Mapper(componentModel = "cdi")
public interface KundeMapper {

  @Mapping(target = "geburtsdatum", format = "dd.MM.yyyy")
  KundeDTO jpaEntity2RestDto(Kunde kunde);
}

MapStruct erzeugt daraus in etwa folgenden Code:

@Generated("org.mapstruct.ap.MappingProcessor")
@ApplicationScoped
public class KundeMapperImpl implements KundeMapper {

  public KundeDTO jpaEntity2RestDto(Kunde kunde) {
    // null-Checks
    // Ziel-Objekt-Erzeugung
    // Getter-/Setter-Aufrufe
    // ...
  }
}

Der standardmäßig generierte Code ist oft schon genau das, was man benötigt. Ansonsten ist so ziemlich alles konfigurierbar: Unterschiedliche Property-Namen in Quell- und Ziel-Bean, unterschiedliche Typen, die Objekt-Fabriken zur Ziel-Objekt-Erzeugung... Zudem können vorhandene, handgeschriebene Mapper eingebunden werden. Und Objekt-Graphen werden selbstverständlich genauso gemappt wie Collections, Maps, Arrays... Für JAXB, Joda-Time und Java 8 Date&Time stehen automatische Mappings zur Verfügung.

Man merkt, dass dieser Mapper mit vielen Praxis-Problemen im Hinterkopf entwickelt wurde. Und man fragt sich relativ schnell, warum man nur so lange das Bean-Mapping von Hand oder mit Reflection-Bibliotheken durchgeführt hat ;-)

Mindestvoraussetzung für MapStruct ist Java 6 – aber da heute der letzte Tag der kostenfreien Java-7-Updates (und ab morgen nur noch Java 8 "aktuell") ist, sollte das kein Problem darstellen.

Die Folien zu meinem Vortrag finden sich hier.

Freitag, 13. März 2015

Scope-Events in CDI 1.1

Wer in einer Java-Webanwendung mitbekommen möchte, wann die Anwendung fertig bereitgestellt ist (z.B. um den Deployment-Timestamp zu ermitteln und anzuzeigen), hat dazu diverse Möglichkeiten. Eine lang verfügbare Lösung ist ein ServletContextListener, seit Java EE 6 kann man auch eine @Singleton-@Startup-EJB verwenden. Mit CDI 1.1 in Java EE 7 haben wir nun eine weitere Variante, ein @Initialized-Event für den Application-Scope (d.h. für den ServletContext):

import javax.inject.Named;
import javax.enterprise.event.Observes;
import javax.enterprise.context.*;

@Named
@ApplicationScoped
public class DeploymentInfoBean {

  private Date deploymentTimestamp;

  public Date getDeploymentTimestamp() {
    return deploymentTimestamp;
  }

  void deploymentFinished(
    @Observes
    @Initialized(ApplicationScoped.class)
    ServletContext context) {

    deploymentTimestamp = new Date();
  }
}

Wer nur am Zeitpunkt interessiert ist und keine Werte aus dem ServletContext benötigt, kann sich als Parameter auch einfach ein Object übergeben lassen und beseitigt damit die Abhängigkeit zu javax.servlet.

Man kann sich nicht nur über die fertige Initialisierung eines Scopes informieren lassen, sondern auch über die Beendigung eines Scopes – und so beispielsweise Anfang und Ende von HTTP-Sessions überwachen:

public class SessionWatcher {

  void sessionCreated(
    @Observes
    @Initialized(SessionScoped.class)
    HttpSession session) {
      ...
  }

  void sessionDestroyed(
    @Observes
    @Destroyed(SessionScoped.class)
    HttpSession session) {
      ...
  }
}

Freitag, 6. März 2015

Java in OS X 10.10 "Yosemite"

Wie auch schon die Vorgängerversion wird OS X 10.10 ohne vorinstalliertes Java 6 ausgeliefert. Bei einem Update wird eine vorhandene Java-6-Installation aus /System/Library/Java/JavaVirtualMachines gelöscht. Das alles ist eigentlich kein Problem, denn Java 6 ist eh veraltet, seit Oracle vor zwei Jahren den kostenlosen Support für Version 6 eingestellt hat – und in /Library/Java/JavaVirtualMachines installierte Versionen von Java 7 und Java 8 bleiben bei einem Update auf OS X 10.10 erhalten.

Manche Programme benötigen aber noch Java 6 zum Starten. Yosemite weist mit einem Dialog darauf hin:
Mit der Schaltfläche "Weitere Infos" gelangt man zur Download-Seite von Java für OS X 2014-001, mit dem in Mac OS X 10.7 bis OS X 10.10 Java 1.6.0_65 installiert werden kann. Dies ist dieselbe Java-Version, die Apple auch schon mit "Java für OS X 2013-005" ausgeliefert hat – nur ein geringfügig aktuellerer Build.