Grad lese ich Thomas Bandts öffentliche Gedanken zur Frage, ob und wann TDD denn sinnvoll sei. Die treibt ja viele um. Immer wieder. Und so glaube ich, dass irgendwas an ihr noch nicht stimmt. Irgendwie ist die Perspektive falsch.
Wenn es in einer Partnerschaft krieselt und sie klagt “Immer bringst du den Müll nicht runter!” worauf er fragt, “Wann soll ich den Müll denn runterbringen? Wenn die Tüte richtig voll ist oder früher?”, dann ist das auch die falsche Frage. Sie nimmt nur ein Symptom in den Blick, nicht das Wurzelproblem. Das könnte nämlich darin bestehen, dass sie sich in ihrem Bemühen um eine schöne Wohnung nicht anerkannt fühlt.
Also: Was könnte falsch an der Perspektive hinter der ewigen Frage nach “Soll ich eigentlich immer (!) mit TDD arbeiten?” falsch sein?
Widerstand gegen die Silberkugel
Ich glaube, die Frage ist Ausdruck einer großen Skepsis. Entwickler sind zurecht skeptisch, dass es eine Praktik wie TDD gibt, die “alles” besser machen könnte. Aber insofern ist die Frage auch Ausdruck eines Missverständnisses. TDD will gar nicht “alles” besser machen. Nur manches.
Die Frage ist damit falsch gestellt, weil sie suggeriert, TDD würde einen Absolutheitsanspruch formulieren. TDD ist “nur” eine Methode, um ein Ziel zu erreichen: korrekten Code mit einer hohen Testabdeckung und gut evolvierbarem Design.
Evolvierbares Design ist die Voraussetzung für langlebige Software.
Hohe Testabdeckung ist eine gute Grundlage dafür, dass Bugs sich nicht verkriechen können in ungetesteten Code. Verkriechen ist aber nur möglich bei Code, der entweder nicht trivial ist oder der nur sehr selten ausgeführt wird. Ist beides nicht gegeben, dann stolpert man bei Integrations- oder Akzeptanztests sehr schnell über den Bug. Und sehr wahrscheinlich ist dann auch sofort klar, wo und warum es geknallt hat.
Beispiele für solchen Code sind Getter/Setter oder Mappings. Die funktionieren entweder -- oder eben nicht.
Wer also Code schreibt, der nicht evolvierbar sein muss oder der weitgehend aus Trivialitäten besteht… der muss TDD nicht einsetzen. Forms-over-Data Szenarien fallen für mich z.B. in diesen Bereich.
Widerstand gegen Veränderung
Entwickler widersetzen sich aber nicht nur Silberkugeln, sondern auch Veränderungsansinnen. Und nichts anderes ist TDD. TDD will den Entwickler verändern. Und zwar sehr tiefgreifend. Alte Gewohnheiten sollen abgestreift werden, ja geradezu Gewohnheitsrecht soll aufgegeben werden.
Bisher war “Softwareentwicklung ist Spaß beim codieren von spannender Funktionalität codieren”, nun soll aber sein “Softwareentwicklung ist nicht nur spannende Funktionalität programmieren, sondern auch langweilige Tests, die das eigene Werk in Frage stellen und langsam machen.” Das ist ein tiefgehender Eingriff. Denn erstens wird dem Entwickler der Spaß an der Programmierung vergellt. Zweitens setzt er ihn noch mehr unter Druck, denn der Chef ist gewohnt, schnell rausgeschossene Funktionalität zu sehen. Mit TDD kann die Feuerfrequenz nur sinken.
Das Recht auf Spaß und Spannung, das Recht auf Entlastung durch Fokus auf Funktionalität soll mit TDD beschnitten werden. TDD bedeutet also einige Veränderung. Und die macht nie Freude. Deshalb setzt sich der Entwickler zur Wehr wie jeder es tut, dem ungewollte Veränderungen ins Haus stehen.
Doch auch hier lauern Missverständnisse. Erstens ist das Schreiben von Tests nicht pure Langeweile. Im Gegenteil! Es kann sogar eine größere intellektuelle Herausforderung darstellen, als Funktionalität zu programmieren. Code testbar machen, ist oft keine Kleinigkeit. Wer also was auf sich hält als Entwickler, der sollte mehr Tests schreiben.
Zweitens verlängern automatisierte Tests die Softwareentwicklung nicht per se. Es kommt vielmehr auf die Perspektive an. Wer nur auf diesen Moment schaut, der sieht natürlich die Zeit dahin rinnen, wenn er nicht nur 3 Zeilen Funktionalität, sondern auch 6 Zeilen Test schreiben muss.
Diese Perspektive ist jedoch kurzsichtig. Sie folgt dem Gedanken eines Rechnungswesens, das immer nur auf die Kosten stiert. Und dahinter steht die Vorstellung, dass ein optimales Gesamtergebnis erzielt wird, wenn jeder Einzelschritt optimal ist.
Das stimmt aber nicht. So funktioniert die Welt nicht. Oder nur in besonderen Situationen tut sie das.
Diese Perspektive verliert schlicht den Gesamtprozess und auch die Zeit im Großen aus dem Blick. Denn nicht nur die Zeit eines Entwicklers ist wichtig. Viel wichtiger ist der Gesamtaufwand an Zeit über längere Zeit.
Wer nur auf hier und jetzt schaut, kann das nicht sehen. Wirtschaftlichkeit bedeutet nicht, jetzt etwas in einer bestimmten kurzen Zeit zu produzieren, sondern langfristig zu überleben.
Tests heute beim Entwickeln dienen nun dieser Wirtschaftlichkeit. Denn sie verringern die Wahrscheinlichkeit, dass Bugs in der Zukunft die Arbeit behindern. Das tun sie nämlich in zweierlei Hinsicht: Erstens halten Sie davon ab, Funktionalität zu produzieren. Zweitens stören Sie den Fokus des Teams. Beides ist kontraproduktiv.
Auf längere Zeit gesehen, sind automatisierte Tests (bzw. TDD) also wirtschaftlicher. Das ergibt sich auch ganz leicht aus einer simplen Rechnung: Nach jeder Veränderungen am Code müssen alle relevanten Tests wiederholt werden, um sicherzustellen, dass nichts kaputtgegangen ist. Das sind umso mehr, je verquarzter Code ist. Damit ist es umso teurer, je mehr manuelle Tests gefahren werden müssen. Die Ausführung von automatischen Tests hingegen kostet nichts.
Umgekehrt bedeutet das allerdings: Wer sich um längere Zeit nicht scheren muss, der kann auf autom. Tests/TDD verzichten.
Allerdings würde ich immer hinterfragen wollen, ob einer, der aus dem Grunde TDD von der Hand weist, wirklich eine Ahnung davon hat, was in der Zukunft mit seiner Software passiert. Aus so mancher Software, die für einmaligen Gebrauch gedacht war, ist ja schon eine unternehmenskritische Anwendung geworden.
Niemand will ja das Brownfield. Das ist, glaube ich, unzweifelhaft. Aber warum ist es dann überall? Warum gibt es solche Massen an unwartbarem Code, dessen Korrektheit niemand beweisen kann. Nach jeder Änderungen hoffen und bangen alle nur, dass nichts vormals Korrektes nun kaputt ist.
Widerstand gegen Angriffspunkt
Nicht nur gegen Veränderungen und Silberkugeln wehren sich Entwickler mit der kritischen Frage, ob TDD denn wirklich sein müsse. Sie wehren sich auch dagegen, angreifbar zu werden. Sie wehren sich dagegen, sich erklären zu müssen.
Wer bisher keine Tests geschrieben hat und nun damit anfängt und schon deshalb, weil er ein Anfänger ist, länger braucht, der sieht sich Stirnrunzeln ausgesetzt. “Muss das mit diesen neumodischen Tests denn sein?” fragt der Chef?
Darauf dann selbstbewusst mit “Ja, das muss sein” zu reagieren, fällt vielen schwer. Sie können sich auf keinen Berufsethos zurückziehen. Sie haben keine Branche hinter sich, in der es alle so tun. Die Ausbildung steht nicht hinter ihnen. Sie sind auf sich gestellt. Ihre Überzeugung steht gegen die Weisungsmacht des Chefs, der von Softwareentwicklung allzuoft nichts versteht und Experimente so gar nicht mag.
Das sind verständlicherweise unschöne Aussichten. Also ist der Reflex die sehr skeptische Frage, ob denn TDD überhaupt etwas brächte.
Fazit
Natürlich hat die Frage, ob und wann TDD denn sein müsse, eine Sachebene. Die Frage ist sachlich berechtigt. Und die Antwort sollte nicht pauschal sein, sondern differenziert. Entscheidungskriterien sind gefragt.
Lebensdauer und Kompliziertheit und Art von Code gehören für mich als Aspekte in die Antwort. Nicht für jeden Bau sind statische Berechnungen im selben Umfang nötig. Nicht für jedes Unternehmen ist ein Rechnungswesen im selben Umfang nötig. Deshalb: Nicht für jedes Softwareprojekt sind automatisierte Tests im selben Umfang nötig.
Kontraproduktiv im Sinne einer differenzierten Antwort finde ich es jedoch, sich über die wahren Beweggründe der Frage nicht klar zu sein. Jeder, der so fragt, prüfe sich da also am besten erstmal selbst. Das ist schwierig – aber wenn man es nicht tut, läuft man immer wieder gegen Wände aus Missverständnissen. Und nichts ist lähmender als Konflikte, deren Ursachen man nicht kennt bzw. verschleiert.
Ebenfalls kontraproduktiv empfinde ich es, ganz grundsätzlich den Nutzen von automatisierten Tests zu hinterfragen. Das widerspricht aus meiner Sicht der Zivilisationsgeschichte der letzten 1000 Jahre, die ganz klar zeigt, dass Automatisierung wo immer es geht, Vorteile bringt. Menschen ersparen sich langweilige, fehlerträchtige, gefährliche Arbeit, indem sie automatisieren. Warum sollte das nicht auch für Tests gelten?
Nein, da ist für mich die Grenze erreicht. Wer Testautomatisierung pauschal in Frage stellt, der widerspricht grundlegenden Prinzipien. Und dazu sagten schon die Lateiner: contra principia negantem disputari non potest (Mit dem, der die gemeinsamen Prinzipien leugnet, ist nicht diskutieren.) Den Diskussionsaufwand spare ich mir dann.
Also: Wenn die Frage sachlich gestellt ist und nicht als Rationalisierung, d.h. als Abwehrmaßnahme dient, wenn ernstlicher Erkenntnisgewinn gewollt ist und die grundsätzliche Möglichkeit der Beiträge von automatisierten Tests/TDD zu Produktionseffizienz, Korrektheit und Evolvierbarkeit anerkannt sind… dann lässt sich auch eine Antwort für jedes Projekt finden. Und die lautet nicht immer “Ja! TDD musst du machen auf Teufel komm raus.”
Jedes Projekt hat sein Mix an automatisierten Tests wie Akzeptanztests, Integrationstests, Performancetests, Lasttests, Unit Tests. Und ob die nach TDD oder anders geschrieben sind… das ist durchaus auch immer wieder anders.
Nur eines halte ich für unverbrüchlich: Den Willen zur Automatisierung. Denn alles, was automatisiert getan wird, das ist quasi kostenlos wiederholbar, das ist nachvollziehbar, das ist von keinem bestimmten Teammitglied abhängig, das ist schneller als von Hand getan. Wer wollte diese Vorteile der Automatisierung ausschlagen?