Mein Weg zur testgetriebenen Entwicklung
Written on
Testgetriebene Entwicklung (TDD) funktioniert – überall. Sie scheitert nicht am Kunden, den nicht Qualität sondern Tempo interessiert. Sie steht nicht im Widerspruch zum jungen Projekt mit wenig Budget, das schnell Kunden gewinnen muss um zu überleben. Sie hindert nicht daran schnell Features umsetzen zu können. Ja, sie macht mir auch nicht (mehr) langsamer.
Es ist keine neun Monate her, dass ich das nicht glauben konnte. Mehrere Anläufe hatte ich unternommen neben Code auch Tests zu schreiben. Länger als zwei Monate ging das nie gut:
- Ich fühlte mich produktiver, wenn ich „richtigen“ Code statt Tests schrieb.
- Ich arbeitete in einem Team, das kein Interesse daran hatte Tests einzuführen.
- Es war nicht wichtig fehlerfrei zu arbeiten, die schnelle Umsetzung von neuen Features war was zählte.
- Auch ohne Tests konnte ich relativ fehlerfrei entwickeln.
- Manchmal versuchten wir den Kunden zu überzeugen mit Tests zu entwickeln, aber dieser hatte kein Interesse daran.
- Die Software an der ich gearbeitet habe war nicht besonders gut geeignet testgetrieben entwickelt zu werden. Die Tests funktionierten solange gut wie sie mit den knappen Beispiele aus Büchern gemacht wurden, aber unsere reale Software war zu komplex dafür.
Die entscheidenden Hinweise
Zwei mal klick hat es in meinem Kopf gemacht als ich das Buch „Test Driven Development by Example“ von Kent Beck gelesen habe:
- TDD einzuführen ist keine Entscheidung des Kunden, Chefs oder Teams. Das kann jeder für das was er macht selbst tun. Es ist einfach ein Stück persönlicher Programmierstil. Wie ich entscheide, ob ich mir erst auf ein Blatt Papier skizziere was ich programmiere, kann ich auch entscheiden das erst in einem Test zu skizzieren.
- Ich hatte davor versucht mit Unit-Tests mehr zu erreichen als ich sollte. Es reicht wenn ich prüfe, dass meine Klasse (Unit) ihre Funktion erbringt und die erwarteten Ergebnisse liefert. Es war falsch zu prüfen, ob mehrere Klassen sich zusammenfügen lassen und gemeinsam richtig arbeiten. Für diese Dinge gibt es Integrations- und Akzeptanztests. Mein Unit-Test stellt nur sicher, dass ich keinen Sonderfall vergesse und sich bei einem Refactoring meiner Klasse (Unit) nichts im Ergebnis ändert.
Mir war klar geworden, dass nicht die Beispiele mit JUnit zu simpel sind, die in fast allen Java-Büchern zu finden sind. Vielmehr war das was ich als Unit betrachtet habe zu komplex. Der Fehler lag nicht in den Beispielen sondern bei mir. Ich hatte meine Probleme nicht so sehr in kleinere Probleme zerlegt, dass sie einfach zu testen sind.
Die ersten sieben Monate
Ein gutes halbes Jahr entwickle ich nur noch testgetrieben. Den Umstieg habe ich geschafft, ich kann mir nicht vorstellen nochmals in die Zeit davor zurückzufallen. Nach einigen Monaten Umstellung habe ich nicht mehr langsamer entwickelt als ohne Tests. Wie bei jeder neuen Technik musste ich am Anfang lernen sie einzusetzen. Das kostet die ersten Wochen und Monate zusätzlich. Dennoch war der Aufand auch damals nicht so hoch wie ich zuvor dachte.
Warum kostet es mich jetzt keine zusätzliche Zeit mehr? Zuerst Tests zu schreiben ist nun eine Struktur in der ich mir Gedanken mache was ich schreiben möchte. Das musste ich auch zuvor tun indem ich Skizzen gemalt, einen Prototypen gebaut oder auch nur Code geschrieben habe, den ich nochmals ändern musste.
Ohne Zusatzaufwand bekomme ich aber die folgenden Dinge frei Haus geliefert:
- Ich fühle mich viel freier schlechten Code schon in der Entwicklung nochmals umzuschreiben, da ich nicht fürchten muss etwas kaputt zu machen das schon tat.
- Feierabend mache ich, wenn ich gerade einen neuen Test geschrieben habe. Den nächsten Tag beginne ich mit einem Aufruf des Compilers und bin sofort wieder dort wo ich aufgehört habe. Ich muss nicht mehr nachdenken was ich eigentlich als nächstes machen wollte.
- Das Vertrauen darauf, dass ich das Programm jederzeit ändern kann, sorgt dafür, dass ich nicht mehr versuche Änderungen vorauszusehen und bereits einzuplanen. Ich brauche also weniger Code und Zeit investieren um die gleiche Anforderung umzusetzen.
- Die Struktur meiner Programme hat sich merklich verbessert: meine Klassen sind um Welten weniger gekoppelt und haben eine stärkere Kohäsion. Ich merke schon wenn ich Test schreibe, dass ich diese schlecht ausdrücken kann. Wenn ich überlege, wie ich den Test leichter ausdrücken kann entsteht automatisch auch besserer Nutzcode.
- Meine Programme haben Struktur bekommen und ich finde auf natürlichem Weg in ihnen jetzt die üblichen Patterns. Die Facade beispielsweise ist nicht mehr die größte Klasse meiner Module sondern tatsächlich nur eine dünne Kapsel darum.
Was mir sonst noch geholfen hat
Zwei Bücher aus den Weihnachtsferien haben meinen Entschluss nur noch mit Tests zu entwickeln gestärkt. In „Weniger schlecht programmieren“ und „Becomming a Better Programmer“ ist mir klar geworden, dass die Professionalität der Entwicklung meine Aufgabe als Entwickler ist. Ich bin der Profi in diesem Bereich und nicht die Geschäftsführung. Diese hat mich dafür angestellt professionell zu arbeiten. Sie verlässt sich darauf, dass ich weiß was notwendig ist und ich dies tue. Wenn ich ihr den Eindruck gebe, es geht auch ohne, wenn es mal sein muss, dann ist klar, dass sie das bevorzugt. Wenn ich der Überzeugung bin, dass es der falsche Weg ist, dann muss ich das vermitteln und darf nicht auf andere schieben, dass es „bei uns“ eben nicht anders geht. Würde ich gegen mein besseres Wissen arbeiten, so hätte zuerst ich versagt und nicht das Management.
Ebenso hat mich der Klassiker „Clean Code“ auf meinem Weg weiter gebracht. Einerseits weil ich durch die Tests erst einiges daraus richtig umsetzen konnte. Vorallem aber weil ich damit gelernt habe auch meine Tests so zu schreiben, dass sie lesbar sind, jederzeit geändert und erweitert werden können.