Skip to content

return null;

In seinem Buch "Clean Code" empfiehlt Robert C. Martin, nicht explizit "null" zurück zu geben. Weil es Arbeit erzeugt und den Code mit null-checks unleserlich macht.
Ich bin aber der Meinung, dass man das nicht verallgemeinern kann und sollte. An folgenden Beispiel will ich das einmal deutlich machen.

These:
Wenn wir einen DAO haben, mit einer Methode "findItemById(id)" dann soll "null" zurück geben werden, wenn kein Item mit dieser Id existiert!

Begründung:
Zum einen bekommen wir mit dem Wert "null" genau das zurück, was wir erwarten würden. Denn wir müssen davon ausgehen, dass in dem Repository oder der DB die wir da abfragen kein Eintrag mit dieser Id existiert.
Es wäre idiotisch zu erwartet, dass die DB einen Eintrag für jede Id hat, die wir uns ausdenken können - es zwingt uns schließlich niemand, der Methode nur Ids zu übergeben, für die ein Eintrag existiert!
Die Methode in dem DAO gibt uns also genau das zurück, was in der DB steht: kein Eintrag! Und "null" ist IMO die beste Repräsentation von "kein Eintrag".

Ich habe schon Implementationen gesehen, wo im Fall von "kein Eintrag" eine UnknownEntryException geschmissen wird. Aber das ist ja nicht richtig.
Eine Exception - also eine Ausnahme - impliziert ja, dass ein Fehler aufgetreten ist, der so nicht zu erwarten war. Aber das stimmt ja nicht. Wie bereits erläutert mussten wir ja zwingend davon ausgehen, dass so ein Fall eintreten könnte. Und es ist auch kein Fehler! Einen Eintrag mit einer beliebigen Id in einer DB nicht zu finden ist kein Fehler sondern normal.

Uncle Bob empfiehlt in seinem Buch "special case"-Objects zu verwenden. Aber in dem Fall würde das ja nur noch mehr Verwirrung stiften. Denn es wäre noch schwerer zu erkennen ob er den Eintrag in der DB gefunden hat, und dieser einfach nur leer ist, oder ob der Eintrag nicht existiert. (Special-Case Objekte sind nur dann sinnvoll, wenn ich nicht explizit diese Unterscheidung machen muss, weil sie ggfs. nicht relevant ist)

Prüfen muss ich es in dieser Konstellation nämlich in jedem Fall!
Das heißt, egal was ich mache um das Zurückgeben von "null" zu vermeiden - die Arbeit, den Fall "kein Eintrag gefunden" zu checken, kann ich mir dadurch nicht ersparen!
Wenn ich es doch machen würde, hieße das: ich frage explizit etwas an, schere mich aber einen Dreck um das Ergebnis - das wäre hochgradig Verantwortungslos. (Zumindest in den allermeisten Fällen)

Da wir nun also festgestellt haben, dass wir eine Überprüfung machen müssen, schauen wir doch mal, wie diese am Einfachsten realisiert werden kann (KISS-Prinzip).

Fall 1 - "return null":
ResultObject result = dao.findItemById(42);
if(result == null) {
    return;
}
Ich denke dazu brauch ich nicht viel schreiben: kurz, auf den Punkt, sofort verständlich.


Fall 2 - "throw Exception":
ResultObject result;
try {
    result = dao.findItemById(42);
} catch(UnknownEntryException e) {
    return;
}
Doppelt so viele Zeilen wie in Fall 1.
Es macht den Code außerdem unleserlicher und kann zu Verwirrung führen, da nicht auf den ersten Blick erkenntlich ist, ob hier tatsächlich ein Fehlerfall behandelt wird.
Dass es keine Option ist, das try-catch-statement einfach weg zu lassen, muss ich hoffentlich nicht extra erwähnen (das hab ich oben schon genug getan).


Fall 3 - "Special case object 1"
ResultObject result = dao.findItemById(42);
if(result.getId() == 0) {
    return;
}
Wie ein Special-Case-Object gestalltet wird, ist natürlich nicht fest vorgegeben. Hier also der Fall, dass es einfach ein normales ResultObject mit leeren Feldern ist.
Und wir sehen direkt die Probleme die damit einher gehen! Zum einen ist nicht klar, ob "0" nicht eventuell eine gültige Id sein könnte.
In diesem Fall setzen wir auch voraus, dass die Id, mit der wir anfragen auch Teil des Ergebnis ist. Wenn sie das nicht wäre, könnten wir nicht mehr unterscheiden, ob der Eintrag gefunden wurde und einfach nur leer ist oder ob er nicht gefunden wurde.
Das nächste Problem damit, erläutere ich gleich in Fall 4.


Fall 4 - "Special case object 2"
ResultObject result = dao.findItemById(42);
if(result.isNoEntry()) {
    return;
}
In diesem Fall haben wir dass Problem, dass wir unser Ergebnis-Objekt um eine Methode oder ein Feld erweitern müssen, um diesen Fall explizit abzufragen.
(bzw. wird es sich wohl eher um eine DataStructure handeln, aber in Java gibt es da keine so explizite Unterscheidung, also nennen wir es der Einfachheit halber ein Objekt)
Das führt direkt zu einem weiteren Problem: wie benennt man so etwas? "isEmpty()" wäre z.B. schlecht, weil jemand der den Code ließt, davon ausgehen könnte, es handelt sich um ein Objekt dass von Collection erbt.
Aber auch bei "isNoEntry()" stellt sich die Frage, ob es sich dabei um einen Wert handelt, der so im Eintrag in der DB steht.
Und was das schon in Fall 3 angeteaserte Problem angeht: bei diesem Code wird die verwendete IDE vermutlich anmeckern, dass "result" null sein könnte. Aber selbst wenn nicht: normalerweise arbeitet man ja nicht alleine. Und sobald ein Kollege den Code anfasst, wird ihm (oder ihr) wahrscheinlich auffallen, dass dort ein null-check fehlt! Und dann sieht der Code ganz schnell so aus:

ResultObject result = dao.findItemById(42);
if(result == null || result.isNoEntry()) {
    return;
}
Was fällt uns auf? Genau: der Code sieht so aus wie in Fall 1 - nur mit einem zusätzlichen Aufruf von "isNoEntry"!
Wäre es nicht einfacher, diesen zusätzlichen Aufruf einfach weg zu lassen? Dann könnten wir auch darauf verzichten, das ResultObject zu erweitern.


Schlussfolgerung:
Wenn wir in einem Repository ein bestimmtes Item abfragen, dann ist es sinnvoll "null" zurück zu geben, wenn dieses Item nicht existiert!


Zusätzliche Anmerkung:
Und dass mir jetzt keiner mit dem Vorschlag kommt, doch stattdessen eine Liste mit nur einem Eintrag zurück zu geben!
Nicht nur, dass wir dem Aufrufer (also dem Nutzer des DAO) damit zusätzliche und unnötige Arbeit aufhalsen, weil dieser auch noch den unwahrscheinlichen Fall abfragen muss, falls mehr als ein Item in der Liste ist.
Es ist unnötige Ressourcenverschwendung, dass Item noch mal in eine Liste zu packen, die sonst keinen Zweck erfüllt.
Außerdem wird das API des DAO dadurch kontra-intuitiv und umständlicher zu benutzen (um es mal vorsichtig zu formulieren).

Nachtrag:
Eine zusätzliche Methode im DAO "existsItemWithId(id)" die ein boolean zurück gibt, halte ich im Hinblick auf Performance ebenfalls für untauglich. Die Datenbank ist ohnehin schon das Bottleneck der gesammten Applikation - da muss man nicht noch eine zweite Abfrage absetzen, wenn eine auch reichen würde.

Maven in Eclipse

Wie beschissen das m2e-Plugin in Eclipse ist, sollte ja hinlänglich bekannt sein.

Die letzte halbwegs funktionierende Version von m2eclipse war 0.12.1 - bevor es von Sonatype zu Eclipse gewandert ist und dort bis zur Unbenutzbarkeit verhunzt wurde. Die repositories/update-sites für die alten Versionen gibt es natürlich schon lange nicht mehr. Das Plugin selber funktioniert an und für sich noch mit aktuellen Eclipse-Versionen - sofern das Eclipse-eigene m2e-plugin nicht installiert ist.

Ich war so frei, die nötigen Daten zusammen zu stellen:
m2eclipse-0.12.1.tar.gz

Das Plugin selbst, benötigt noch einige andere Standard-Plugins (wie zum Beispiel die Web- und XML-Tools). Zum "installieren" müssen dann einfach nur noch die Verzeichnisse "features" und "plugins" in das Eclipse Install-dir kopiert werden.

Das ist zwar alles nicht das Gelbe vom Ei, sollte aber um einiges besser funktionieren, als das aktuelle m2e-Plugin, dem immer irgendwelche Module fehlen!

Netbeans oder Eclipse?

Nachdem die letzte Version "Juno" von Eclipse bei mir unterirdisch langsam war - beinahe unbenutzbar - entschied ich mich, nach Jahren, mal wieder Netbeans auszuprobieren.
Um zwei Dinge gleich vorweg zu nehmen: Netbeans ist nicht schlecht und das Problem mit Eclipse kann gelöst werden.
Aber der Reihe nach.

Das erste was bei Netbeans auffällt, ist das SVN-Plugin. Man kann es benutzen, aber es ist nicht sonderlich überragend. Insebsondere fehlt mir der Repository-Explorer, wie ich ihn von Eclipse kenne. Vor allem wenn man mehrere Projekte auschecken will, artet das bei Netbeans schnell in eine ziemliche klick-und-tipp-Orgie aus. Man muss sich für jedes Projekt wieder neu zum Repository verbinden und - je nach Struktur - den Projektnamen noch mal eintippen, weil Netbeans sonst immer nur in das Verzeichnis "trunk" auschecken will. Aber es funktioniert und so oft checke ich persönlich auch keine Projekte aus.

Kommen wir zur Integration von Maven. Das Plugin dafür ist schon dabei und nach dem auschecken fällt auf, dass die Projekte automatisch als Maven-Projekte angezeigt werden. Auch funktioniert das Maven-Plugin mehr wie ein Wrapper (also ähnlich wie die m2eclipse Versionen bis 0.12.1) und funktioniert damit out of the box (ohne das ich erst Plugins für das Plugin downloaden muss, oder Probleme mit lifecycle-mappings bekomme, wie bei den aktuellen m2e Versionen).
Leider fehlen mir ein paar der Features die m2e vorzuweisen hat. Zum Beispiel die Dependency Hierarchy über die man direkt Abhängigkeiten ausschließen kann.

Das Programmieren selber geht in Netbeans gut von der Hand. Das Syntax-Highlighting lässt sich inzwischen überaus filigran einstellen und auch Content-Assist und Compare-View sind überaus gelungen und machen Spaß zu benutzen!

Einen Dämpfer erlebt man jedoch, wenn es ans Testen geht. Netbeans wickelt die Tests auch über Maven ab, sodass man nur die Ausgabe in der eingebauten Konsole hat. Schon alleine in dieser Hinsicht ist die Integration von JUnit in Eclipse um einiges besser. Noch umständlicher wird es allerdings wenn es ans Thema Testcoverage geht. Bei Eclipse muss ich dafür nur das Plugin ECLemma installieren. Bei Netbeans muss ich jedoch die pom.xml meines Projektes erweitern, und dort ein Mavenplugin wie bspw. JaCoCo einbinden. Auch wenn ich den nicht invasiven Weg von Eclipse deutlich bevorzuge, wäre das noch nicht ganz so schlimm - wenn es denn wenigstens funktionieren würde. Tut es aber - zumindest bei den Projekten die ich habe - nicht! Es könnte daran liegen, dass besagtes Plugin Probleme mit multi-module-poms hat - aber dem bin ich dann nicht weiter nachgegangen.

Zusammenfassend kann ich sagen: Netbeans ist wirklich nicht schlecht! Es ist schnell, hat ein paar wirklich nette Features, die einem Arbeit abnehmen und ist einfach zu Bedienen. Die erwähnten Drawbacks haben mich allerdings dennoch wieder zurück zu Eclipse getrieben.

Und damit komme ich wieder zurück zum Anfang. Es stellte sich nämlich heraus, dass die Probleme mit der non-responsive GUI von Eclipse Juno, nur auftreten, wenn man sich das Package "J2EE" (Eclipse IDE for Java EE Developers) gedownloaded hat! Die Classic-version (Eclipse Classic 4.2.1) hat diese Issues nicht, und reagiert gewohnt schnell!

TriGalaxy wartet auf euch

Das Beta-testen hat ein Ende. Nach Monaten gibt es nun endlich die Version 1.0 von


Das neue, kostenlose Open-World Multiplayer-Science-Fiction-Rollenspiel für Android!


Den Rest kopiere ich einfach mal aus der offiziellen Beschreibung, die Uwe sehr schön zusammen gefasst hat:



Treibe Handel und erfülle Missionen, erforsche mehrere tausende Sternsysteme.

Triff dich mit dubiosen Händlern in dunklen Korridoren, flieg durch Wurmlöcher, baue Erz auf Asteroiden ab oder suche in Wracks nach Alien-Artefakten. Verbessere deine Talente und deinen Ruf bei einer der drei Fraktionen, um besondere Aufträge und Fähigkeiten freizuschalten.
Kauf dir ein größeres Raumschiff und einen Hyperantrieb, und die ganze Galaxis steht dir offen.



Nach einer Aufwärmphase beginnt das erste Kapitel einer Hintergrundstory, die alle Mitspieler betrifft (ja, es ist ein Multiplayer-Spiel). Der Autor der Geschichte ist ein mehrfach ausgezeichneter SciFi-Autor.


Das Spiel ist komplett kostenlos. Es gibt im Bazar die Möglichkeit, ein preiswertes Booster-Pack zu erstehen, mit dem man einige Dinge etwas beschleunigen kann. Aber grundsätzlich steht jedem Mitspieler alles offen. Das Spiel wird ständig weiterentwickelt.

Und nun tauche ein in eine unbekannte Galaxis!

Externes JavaScript in Pentaho Kettle laden

Kettle bietet die Möglichkeit in einer Transformation auch JavaScript aus externen Files zu laden.
Dazu braucht man lediglich einen Step "Modified Java Script Value" in dem man die Funktion "LoadScriptFile()" aufruft.
Damit die Datei nicht bei jeder Zeile erneut geladen wird, sollte optimalerweise ein neuer Tab erzeugt werden und via "Set Start Script" so markiert werden, dass er nur beim Laden der Transformation aufgerufen wird.

Das ist soweit nichts Neues, und durch ein bisschen googlen relativ schnell heraus zu finden.
Was hingegen nicht so einfach zu ergründen ist: wie kann man das benutzen, ohne den kompletten Pfad hardcoded angeben zu müssen?

Denn die ganzen Felder kann man nicht benutzen - die stehen ja nur bei der zeilenweisen Verarbeitung zur Verfügung. Aber da soll die Lib ja nicht geladen werden.
Das Beispiel das Kettle bereit stellt ist da auch alles andere als hilfreich:

// Load's a JavaScript File into your actual running Context.
// This function should called from your defined StartScript
// otherwise your JavaScript-File is loaded on each processing
// Row.
//
// Usage:
// LoadScriptFile(var);
//
// 2006-11-15
//
var xPfad = "Your Filename, with Path";
LoadScriptFile(xPfad);

Wie üblich bleibt mal wieder nichts anderes übrig als Probieren.
Das Rumspielen mit Parametern und Argumenten der Transformation war nicht von Erfolg gekrönt, aber da das JavaScript-File in meinem Fall im selben Verzeichnis wie die Transformation liegt, hat sich folgendes bewährt:
var workingDirectory = getVariable("Internal.Transformation.Filename.Directory", "/var/APP/ETL/");
var libraryPath = workingDirectory + "/etl-lib.js";
LoadScriptFile(libraryPath);
Ich habe irgendwo gesehen das jemand "getEnvironmentVar()" statt "getVariable()" benutzt hat - das hat jedoch nicht funktioniert.
Zumindest hat "getVariable()" den Vorteil, dass als zweiter Parameter ein Fallback spezifiziert werden kann, falls die Variable nicht gefunden wird.