Mit einem Fallschirm kann man besser springen
Bevor ich bei BRICKMAKERS als Software Entwickler gearbeitet habe, war ich für einige Jahre selbstständig als IT-Berater unterwegs, um mir meine Pommes während des Studiums zu verdienen. Als ich vorher darüber nachgedacht habe, wie es wohl ist, selbstständig zu sein, habe ich durch Zufall bei einem Podcast eine Beschreibung gehört, die ich wohl nie vergessen werde.
Selbstständig zu sein ist wie:
Ohne Fallschirm aus einem Flugzeug zu springen und sich während dem Sturzflug selbst einen (Fallschirm) zu bauen.
Und in dem Satz steckt so viel Wahrheit über die Selbstständigkeit: Man lernt in sehr kurzer Zeit sehr viel über die verschiedensten Dinge und ist am Ende stark überrascht, was man doch alles hinbekommen hat. Wenn man sich dann am Ende zu seinem Fallschirm umdreht, dann ist dieser wahrscheinlich ein sehr kunstvoll gestickter Patchwork Fallschirm.
Aber worüber rede ich hier die ganze Zeit eigentlich? Sind wir nun Softwareentwickler oder selbstständig? Vielleicht seid ihr ja sogar gerade beides.
Aber in jedem Fall ist mir aufgefallen, dass es eine sehr starke Parallele zur Software-Entwicklung gibt. Bei der klassischen Softwareentwicklung ist man meistens genauso vorgegangen: Während dem Entwickeln der Software gab es häufig keine Tests, die gewährleistet haben, dass der Code tatsächlich genau das macht, wofür er bezahlt wird. Dabei ist man dann spätestens kurz vor dem Ausliefern der Software mit enormer Geschwindigkeit auch das erhöhte Risiko eingegangen, dass durch das Lösen eines Fehlers noch weitere Fehler ausgelöst wurden.
Und das Schlimmste dabei ist dann eigentlich, dass einen der schnellere Sturzflug immer mehr die Möglichkeit nimmt, die Software mit der notwendigen Achtsamkeit und Ruhe weiterzuentwickeln.
Wäre es nicht schön, wenn man auch als Entwickler mit einem wunderbaren Navy-Super-Duper Fallschirm ausgestattet aus dem Flugzeug springen kann? Quasi sorglos & nur noch die Routine des Fallschirmspringens abspielen muss?
Ich finde, das klingt sehr entspannt, deshalb bin ich ein großer Fan davon. Ich bin damit nicht mal der einzige; alle in unserem Büro teilen die Begeisterung für das Programmieren mit einem Sicherheitsnetz — unserem Coding-Fallschirm.
Level 2: Wir brauchen einen Fallschirm — So bauet mir einen Fallschirm!
Jetzt sind wir schon beim ersten Schritt der Besserung angekommen: Wir wollen Tests schreiben, die unsere Logik im Code überwachen können. Diese Tests können wir dann einfach bei jeder Gelegenheit ausführen: an Ostern, Weihnachten, vor jedem Release oder auch direkt bei jedem Build Vorgang.
Vielleicht schießen euch folgende Gedanken durch den Kopf, wenn ihr das zum ersten Mal hört:
-
Aber ich bin doch ein Entwickler, weil ich es liebe, faul zu sein… ich möchte nicht mehr Arbeit haben!
-
Mein Code ist immer richtig, warum sollte ich das nochmal überprüfen ?
Euer Vorgesetzter könnte auch vermutlich etwas in die Richtung sagen:
Aber ich bin doch ein Vorgesetzter, ich will nicht mehr bezahlen, das dauert doch länger und hat doch vorher auch geklappt.
Als Entwickler: Von der Frage oben ausgehend, gibt es eigentlich nur zwei Möglichkeiten:
-
Ah, dann macht das einfach ein extra Mensch für mich, der meinen Code testet. Ich nenne ihn Software-Tester!
-
Ich bin für meinen Code verantwortlich und weiß am besten, was er machen sollte — ich schreibe meine Tests also selbst.
Auf die Lösung von Option 2 will ich im nächsten Abschnitt noch genauer eingehen, aber auch Option 1 ist immerhin ein Schritt in die richtige Richtung — wenn auch nur ein kleiner.
Wenn wir nun einen Softwaretester haben, der für uns die Testklassen schreibt, die unsere Logik testen, haben wir immerhin einen Fallschirm. Aber der Fallschirm wurde von jemand anderem gebaut, d.h. nicht, dass ihr euren Kollegen nicht trauen sollt. Das Problem ist nur, dass ihr entweder dem Tester euer ganzes Wissen über eure aktuelle Aufgabe weitergeben müsst (und das ist auch wieder viel Arbeit) oder aber ihr lasst ihn die Tests so schreiben, wie er es für richtig hält. Und dabei kann es dann doch wieder extrem schnell dazu kommen, dass die Tests eine andere Logik abfragen, als eigentlich in der Anforderung gefragt war.
Blöd. Also haben wir zwar einen Test, aber entweder trotzdem nahezu genauso viel Arbeit, wie die Tests direkt selbst zu schreiben oder aber einen gefälschten Fallschirm, der im Einsatz dann doch nicht hält, was er verspricht.
Als Vorgesetzter: Ganz ehrlich, lass das deine Entwickler entscheiden. Es ist allein ihre Verantwortung. Falls dich das nicht überzeugt, frage dich, wie viel Zeit im Nachgang immer noch für das Bugfixen aufgewendet wurde & denke nun daran, dass dem Kunden ein Großteil der Bugs erst gar nicht auffällt, wenn sie durch Tests bereits gefunden und beseitigt wurden.
Ps. Mehr gute Gründe warum TDD sogar finanziell Sinn macht, lest ihr am besten den ganzen Artikel hier.
Level 3: Wir brauchen einen Fallschirm — ich baue einen Fallschirm
So, das war ein langer Weg bis hierhin. Ich fasse nochmal kurz zusammen:
Wir wollen Tests & wir wissen, dass wir für unseren Code verantwortlich sind & die Tests auch am besten gleich selbst schreiben.
Jetzt sind wir schon fast beim Ziel angekommen. Bleibt nur noch die Frage:
Wann baue ich mir meinen Fallschirm ?
Der Mensch ist ein Gewohnheitstier und wird also vermutlich seinen gewöhnlichen Prozess des Programmierens auch nur ungerne verändern, also versuchen wir einfach als erste Option, alle Tests komplett vor dem “Coden” zu schreiben und dann wie gewohnt weiterzumachen. Zu Beginn wissen wir aber gar nicht so Recht, was unser Code denn alles für Fallunterscheidungen machen wird, also ohne in die Zukunft sehen zu können, kann man eigentlich nicht alle Testfälle vorher kennen.
Gut, also weiter zur zweiten einfachen Option: Lass uns erstmal coden und dann im Nachgang die Testfälle ergänzen. Hier haben wir auch 2 Probleme: Zu leicht kann man an der Stelle sagen, “mein Code klappt doch — ich bin schon fertig” oder auch “ich würde zwar Tests schreiben, aber wir haben keine Zeit mehr dafür”.
Tests im Nachhinein schreiben ist außerdem recht langweilig und wenig anspruchsvoll, da man schon den ganzen Code zur Entwicklung kennt & der Denkprozess quasi abgeschlossen ist. Dadurch wirkt das Testen sehr monoton, man testet einfach genau den Code ab, den man schon vorher konzipiert hat. Dabei passiert es dann richtig schnell, dass man Testfälle nicht mehr bedenkt und leidet unter einem Trugschluss, dass der Code stimmt.
Aber hey, das ist auch schon ganze 2 Level weiter als am Anfang und auch hier können schon viele Fehler anfangen, aber …. das geht noch besser & spannender!
Bosslevel: TDD — Testgetriebene Entwicklung
Endlich geschafft, wir sind beim Endgegner angekommen.
Aber so ein Bosslevel, das ist nicht so leicht zu schaffen. Während wir im letzten Level noch damit zu Recht kamen, unsere Gewohnheit nicht zu ändern oder nur geringfügig zu ergänzen, so müssen wir jetzt den kompletten Denkprozess verändern.
Holt euch am besten direkt einen frischen Kaffee und etwas Nervennahrung, denn jetzt wird’s hart.
Wir können nicht alle Tests vorher schreiben, im Nachhinein sind wir zu sehr beeinflusst… Also wie wäre es, wenn wir Tests schreiben während wir auch gleichzeitig den produktiven Code schreiben ?
TDD: Vorbereitung
Zu Beginn sollte man sich ganz genau durchlesen, welche Anforderungen es gibt & bei Zweifeln nochmal nachfragen, bis man alles genau verstanden hat. Das ist einer der wichtigsten Schritte! Sonst entwickelt man zwar perfekt testgetrieben, aber leider in eine falsche Richtung :(
Nun gut, angenommen, wir wissen nun genau, was gewünscht ist. Wie fangen wir nun an unseren Code zu schreiben ?
Das hierbei genutzte System lässt sich ganz einfach zusammenfassen und führt bei Wiederholung immer zum gewünschten Ergebnis: Red-Green-Refactor!!
Am besten stellt ihr euch ab jetzt zwei Seiten vor:
-
Die App Seite: hier schreiben wir unseren produktiven Code, der die Geschäftslogik, etc. enthält.
-
Die Test Seite, auf der wir unsere Tests für die App Seite schreiben
Angenommen, wir benötigen eine Funktion, die eine Summe bilden kann.
Stage: Red 🔴
Wir starten auf der Test-Seite und schreiben einen Test, der fehlschlägt. Ohne einen fehlschlagenden Test dürfen wir nicht auf die andere Seite wechseln! :O
Dabei ist es natürlich nicht Sinn der Sache einen Test zu schreiben, der bpsw. einfach nur vergleicht: true == false
& wir dann allen Code schreiben... :D
Dieser Test sollte genau eine einzelne Sache testen und nur dafür verantwortlich sein.
Stage: Green ✅
Nachdem wir einen sinnvollen Test geschrieben haben, der einen Teil des Problems abdeckt, dürfen wir die Seiten tauschen. Dabei schreiben wir aber auch nur genauso viel Code, dass der Test grün wird. D.h.: jede logische Entscheidung, und sei sie noch so einfach, muss erstmal unterdrückt werden.
Oftmals kann man den ersten Test mit nur einer Zeile schon grün bekommen. In dem “sehr komplexen” Beispiel von oben könnten wir einfach für unseren Test einen festen Rückgabewert vorgeben, der den Test erfüllt.
Stage: Refactor ⛑
Als nächstes schauen wir uns sowohl den produktiven Code als auch den Testcode an und überlegen, ob wir unsere Lösung schöner machen können.
Wer bisher immer nur dachte, dass Tests nicht refaktoriert werden müssen, der irrt sich. Auch der Testcode darf immer bei Bedarf verbessert werden, denn die dabei geschriebenen Tests dienen auch gleichzeitig als eine Dokumentation zur Anwendung deiner Klassen oder Services. Und auch hier ist Lesbarkeit ein wichtiges Kriterium.
Nach dem ersten Durchgang durch den Prozess sind wir aber noch nicht fertig mit unserem Problem, also starten wir wieder von vorne & fügen einen weiteren Test hinzu und spielen das gleiche Lied nochmal!
Taktik für den Sieg
Durch die Kombination von Tests schreiben und gleichzeitig den produktiven Code erstellen wird außerdem der Denkprozess verändert. Wir schneiden das Problem in kleinere Stücke und haben mehr Sicherheit bei dem entstandenen Produkt. Die Tests wirken außerdem wunderbar als Erinnerung, wenn man am nächsten Tag an dem Problem weiter arbeitet, kann man seinen Gedanken sehr schnell wieder aufgreifen & weiß genau, wo man aufgehört hat.
Auch für das Refactoring gibt es direkt einen fest integrierten Slot, d.h. man lernt, dass es völlig in Ordnung ist am Anfang eine Lösung zu entwickeln, die “nur den Anforderungen” gerecht wird. Danach kann man dann sein Entwickler Ego glücklich machen und den Code verbessern.
Aber das Schönste daran ist, wir können mit gutem Gewissen Fallschirm springen gehen! Denn mit unserem hochwertigen Fallschirm haben wir viel eher den Mut ein größeres Refactoring anzufangen. Ein funktionierender Fallschirm bietet jedem Entwickler ein großes Stück Sicherheit.
Credits
Vielen Dank an alle Leser,
Vielen Dank an BRICKMAKERS, die einem immer bewusst machen, dass Qualität immer Priorität hat.
Vielen Dank an Philipp & Jannik, die mir damals das System vorgestellt und auch beigebracht haben.
Vielen Dank an Uncle Bob, der auch diese Botschaft an alle anderen Entwickler außerhalb von unserem Büro verteilt und mit seinen Videos das Ganze perfekt erklärt.
Vielen Dank an die Boys & Girls, die Kommas ergänzt und hilfreiche Tipps abgegeben haben: Frank, Caro & Philipp !