Keine Regel ohne Exception

Keine Regel ohne Exception

Ich "liebe" ja diese ans dogmatische grenzenden Forderungen, die (wenn überhaupt) dann wirklich nur in ganz bestimmten Kontexten Sinn machen.

Trotz allem, was an Clean Code (Version "Martin") gut und richtig ist, gibt es leider, leider auch hier solche Merksätze, die man nur mal versuchsweise auf Nicht-Java-Umgebungen übertragen muß, um berechtigte Zweifel am Sinngehalt aufkeimen zu lassen. Oder man übernimmt einfach unkritisch alles, was der lieber Autor so in seinem Buch schreibt, in seinen/ihren Blog.

Zum Beispiel hätten wir da einen meiner ganz persönlichen Favoriten:

Thou Shalt Prefer Exceptions over Returning Error Codes

Der Extrakt, den der Blog-Autor aus der Sache zieht, ist kurz und bündig. Leider so kurz, daß der restliche noch verbliebene Sinngehalt dabei grenzwertig entstellt wird.

Kapitel 7 Error Handling
Moderne Programmiersprachen haben ein Feature namens Exceptions.
Das sollte man auch nutzen.

Ja, sicher, aber natürlich. Auf jeden Fall. Gar keine Frage.

Fehlercodes oder ähnliches sind veraltet.

Das wiederum halte ich für eine recht gewagte Hypothese. Ganz im Gegenteil. Eine Exception kann zwar sinnvoll sein, sie muß es aber nicht automatisch auch immer. Die weiterführende Grundregel:

Don’t Return null – somit wird es unnötig auf null zu prüfen.

ist ähnlich leicht anfechtbar: Es gibt Fälle, in denen genau das das erwünschte Verhalten sein kann und wo eine Exception den aufrufenden Code nur unnötig verkomplizieren würde. Und wer genau nachliest, stellt auch hier wieder fest: Korrekt, also in Martins Buch, lautet die Passage nämlich ganz anders:

Wenn Sie versucht sind, einen Nullzeiger zu liefern, sollten Sie stattdessen erwägen, eine Exception zu werfen.

Habe ich mich verhört? Nein tatsächlich, da steht: ERWÄGEN.

Also doch nichts mit Dogma?

Natürlich nicht. Logischerweise können solche Regeln, so wohlbegründet und gut durchdacht sie auch sein mögen, immer nur Richtlinien sein. Denn im Real Life™ ist das für jede aktuell zu treffende Entscheidung anzuwendende Regel-Set doch erst dann wirklich vollständig, wenn man auch alle anderen, in der konkreten Situation relevanten, Faktoren mit in die Betrachtung einbezogen und gewichtet hat, wie zum Beispiel:

Blenden wir all diese Aspekte mal für einen Moment aus und fragen uns: Watt is dat denn eijentlisch genau, so eine Exception? Nun ja, technisch betrachtet handelt es sich um nichts anderes als einen Sprung an eine gegebenenfalls sehr weit entfernte Stelle im Code, wo die mehr oder weniger aus dem Zusammenhang gerissene Exception dann behandelt werden soll. Ein GOTO für Fortgeschrittene also? Mmmh.

Interessanterweise stehe ich mit dieser Ansicht nicht etwa einsam auf weiter Flur, sondern bewege mich in guter Gesellschaft, siehe Larry Ostermans Blog vom 10.09.2004 mit Verweis auf Joel on Software, Text vom 13.10.2003.

Auch Fehlerbehandlung ist ein Feature

Ein weiterer Aspekt ist folgender: Code in try-finally-Abschnitten wird regelmäßig durchlaufen und erfährt somit bereits während der reinen Entwicklungsarbeit ein hohes Maß an Aufmerksamkeit. Fehler sind daher hier erfahrungsgemäß nicht häufiger als im restlichen Code auch. Andererseits reichen meine Finger nicht mal näherungsweise aus, um die teils haarsträubenden Fehler aufzuzählen, die ich schon in real existierenden Exceptionhandlern gefunden habe. Naja, da kam halt nie einer durch ... und Unit-Tests gab es dafür auch nicht.

Wohlgemerkt - die Schlußfolgerung ist nun NICHT die, daß man Exceptions und -handler vermeiden sollte. Problematisch wird es allerdings auf jeden Fall, wenn Fehlerbehandlungscode nicht richtig oder sogar überhaupt nie getestet wird.

Fehlerbehandlung muß getestetwerden wie jedes andere Feature
Eine bessere Schlußfolgerung wäre also: Fehlerbehandlung ist ein Feature und sollte auch so getestet werden.

Entwicklung ist eine zutiefst konstruktive Angelegenheit. Das macht Spaß, klaro. Testen und Fehlerbehandlung hingegen erfordern destruktives Denken. Man muß sich quasi auf die andere Seite begeben und intensiv darüber nachdenken, welche Ereignisse dem soeben geschrieben Code zustoßen könnten, wodurch man ihn zum Fehlschlagen bringen könnte und wie sich der Code in diesen Situationen verhalten wird bzw. sollte.

Genau das ist auch der Grund, weshalb unerfahrene Entwickler nur sehr ungern Zeit an die Implementierung einer korrekten Fehlerbehandlung "verschwenden". Tief im Innern glauben die nämlich nicht wirklich daran, daß der Speicher jemals ausgehen könnte, daß sich eine Datei mal wegen eines simplen vom User gesetzten Schreibschutzes nicht öffnen läßt, etc. Bei mir auf der Entwicklungsmaschine mit 10 Datensätzen funktioniert doch alles, wo also ist das Problem? Und außerdem will ich jetzt lieber das nächste coole Feature bauen!

coolEin nicht zu unterschätzender Punkt ist auch: Ausgelöste Exceptions sind in vielen gängigen Hochsprachen recht teuer, und viele Exceptions kosten dann unter Umständen auch schon mal erstaunlich viel Performance.

Natürlich haben Exceptions ihren berechtigten Platz in der Welt und werden an vielerlei Stellen völlig zu Recht geworfen, gefangen und behandelt. Ich möchte auch mitnichten die GOTO-Debatte erneut aufrollen. Allerdings sollte man sich meiner bescheidenen Ansicht nach dabei schon vor einer zu starken Vereinfachung hüten und nicht einfach pauschal anhand irgendwelcher flüchtig angelesener zehn "Du sollst XY"-Gebote entscheiden, sondern auch mal selbst nachdenken, gegebenenfalls Kollegen oder andere Professionals konsultieren und schließlich eine sinnvolle Entscheidung treffen, die der Situation auch wirklich angemessen ist.

Und wenn diese Entscheidung schließlich zugunsten der Exception fällt, dann ist das wahrscheinlich auch tatsächlich die optimale Lösung für diesen Fall.