© GoodStudio/Shutterstock.com
Erkenntnisse von der anderen Seite des Tellerrands

Was ich durch Clojure über Java gelernt habe


Wir schreiben das Jahr 2012. Curiosity landet auf dem Mars, Windows 8 wird veröffentlicht, der erste Teil von „Der Hobbit“ kommt in die Kinos, die Beastie Boys lösen sich auf und Deutschland wird mal wieder nicht Fußballeuropameister. Nimmt man die Marslandung aus, also (subjektiv) ein Jahr voller Enttäuschungen. Scheinbar …

Im selben Jahr lernte ich in meinem damaligen Job viel über Softwareentwicklung mit dem noch gar nicht so alten Java 7 und Java EE 6. Während ich mich also mit Application-Servern, EJB, JPA und JSF beschäftigte und die „Gang of Four“-Patterns in meinen Handwerkskoffer aufnahm, stolperte ich zufällig in einem Forum über Clojure – eine JVM-kompatible Sprache, die von meinen mühsam erlernten OOP- und Java-Skills sehr wenig zu halten schien: Keine statische Typisierung, keine Klassen, unveränderliche Datenstrukturen, Funktionen im Zentrum der Sprache. Nachdem der erste Kulturschock verdaut war, beschäftigte ich mich privat zunehmend mit den Konzepten der Sprache. Dabei fiel mir recht schnell auf, dass sich nicht alle, aber einige Problemstellungen in Clojure gefühlt besser lösen ließen – und dass das nicht immer an der Sprache an sich, sondern eher an der idiomatischen Herangehensweise lag. Über die letzten Jahre sind einige dieser Paradigmen in meinen Java-Code durchgesickert und haben mein Bild von gutem und wartbarem Code stark geprägt. In diesem Artikel möchte ich einige dieser Konzepte herausstellen. Dabei ist es natürlich nicht das Ziel, Java-Code zu schreiben, den nur noch Clojure-Entwickler verstehen, oder gänzlich von Javas Paradigmen abzuweichen. Um dem Artikel folgen zu können, werden keine Clojure-Kenntnisse vorausgesetzt.

Veränderlichen Zustand vermeiden

Beim Einstieg in Clojure fällt schnell auf, dass Zustand in der Applikation drastisch anders behandelt wird als in Java. Zum einen wird das durch Clojures unveränderliche Datentypen bedingt. Wird auf ihnen eine Funktion angewandt, gibt diese eine neue Datenstruktur zurück und lässt die ursprünglich übergebene unverändert. Am Beispiel in Listing 1 zeigt sich, dass die Datenstruktur hinter dem Symbol my-vector nicht nachträglich manipuliert werden kann. Das Inkrement wird im zweiten Statement zwar auf jedes Element des Vektors angewandt, das Ergebnis ist jedoch eine neue Datenstruktur. Daraus folgt, dass Entwickler eine Datenstruktur jederzeit bedenkenlos an weitere Funktionen übergeben und dabei sicher sein können, dass keine Operation sie manipuliert. Das Verändern dieser übergebenen Daten hätte mehrere Nachteile: Parallelisierte Ausführung von Code wird erschwert, da das Auftreten von Race Conditions nicht ausgeschlossen werden kann. Immerhin kann niemand sagen, welcher aufgerufene Code das Objekt wann modifiziert. Zum anderen kann eine angepasste Codestelle auf einmal an einer ganz anderen Stelle des Codes für Fehler sorgen, ohne dass Entwickler das erwarten. Dieses Problem sprach der Erfinder von Clojure, Rich Hickey, auf der Java One in seinem Talk „Clojure Made Simple“ [1] ausführlich an. Ein erster Schritt auf dem Weg zu einem robusteren Datenmodell kann der Verzicht auf ein anämisches Datenmodell sein, also etwa Java Beans, in denen jedes Feld über Getter und Setter verfügt. Die Klasse Square in Listing 2 ist ein Beispiel für eine unveränderliche Datenstruktur in Java. Reflection außen vorgelassen, kann ein einmal erstelltes Objekt dieser Klasse nicht mehr geändert werden.

Listing 1

; Zuweisen eines Vektors zum Symbol my-vector (def my-vector [1 2 3 4 5]) ; Anwenden der Funktion inc auf jedes Element (map inc my-vector) -> [2 3 4 5 6] ; Ausgabe des ursprünglichen Vektors my-vector -> [1 2 3 4 5]

Listing 2

class Square { private final int x; private final int y; Square(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public int getY() { return y; } }

In Java lässt sich Code zwar defensiv schreiben, faktisch kann aber nicht immer verhindert werden, dass ein Objekt im weiteren Verlauf der Arbeit manipuliert wird – verschachtelte Objektstrukturen und Collections bieten viel Raum für (unabsichtliche) Zustandsmanipulationen am Objekt. Letztendlich...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Gewinner-Teams

Wir bieten Lizenz-Lösungen für Teams jeder Größe: Finden Sie heraus, welche Lösung am besten zu Ihnen passt.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang