Zum Inhalt

TDD: Denken erlaubt

Test-Driven Development (TDD) gibt auch heutzutage noch viel zu diskutieren. Was mir dabei immer wieder auffällt: Es scheint als ob vor lauter Red-Green-Refactor vergessen geht das man eigentlich Software entwickeln soll. Sobald man sich mit Tests beschäftigt vergisst man das grosse Ganze. Oder wieso schreiben gestandene Software-Entwickler einen Test nach dem anderen der ihnen nur bestätigt das 1 + 1 wirklich 2 ergibt?

Code Katas als Ursache?

Code Katas sollen einem dabei helfen sich bei einer Übung auf einen bestimmten Aspekt zu konzentrieren. Dieser Aspekt ist oft TDD, doch gibt es genügend andere Aspekte die man in den Vordergrund stellen kann (wie die Bedienung der IDE nur mit der Tastatur oder Patterns wie das Single Responsibility Principle).

Will man damit TDD erproben nimmt man in der Regel ein ganz einfaches Beispiel. Man will sich ja nicht lange mit dem Problem beschäftigen sondern TDD lernen. Entsprechend schreibt man viele Tests und denkt wenig über die Lösung nach – diese ist ja durch einfache Beispiele wie FizzBuzz gewollt. Man trainiert also ständig mit einfachen Beispielen und vielen Tests. Die Videos zu diesen Trainings zeigen entsprechend viele Tests und wenig Gedanken über die Lösung.

Kurzum: Der Feedback-Loop für den Entwickler zeigt ganz klar dass er TDD erst richtig macht wenn wer viel testet und wenig denkt. Das Problem ist nur das dies komplett falsch ist.

Software-Entwicklung vor TDD

Gehen wir einen Schritt zurück. Bevor man mit TDD Software entwickeln wollte machte man in der Regel diese Schritte:

  1. Problem analysieren
  2. Lösung erarbeiten
  3. Programmieren
  4. Testen
  5. Veröffentlichen
  6. Bugs fixen
  7. Veröffentlichen

Bei der iterativen Software-Entwicklung folgt man ebenfalls dieser Schrittfolge – einzig der Umfang behandelt nicht mehr das ganze System sondern nur einen Teil.

Die Idee von TDD war es ursprünglich einmal die Schritte 3 & 4 zu kombinieren. So hoffte man die teure Behebung von Bugs nach der Veröffentlichung zu minimieren. Nie war es das Ziel die Phase der Problemanalyse oder dem Erarbeiten der Lösung zu streichen.

Babysteps ins Chaos

Die Analyse der Problemstellung und das erarbeiten der Lösung ging irgendwo bei der Einarbeitung in TDD verloren. Irgendwann sollten Babysteps (wie 1+1 = 2) die Verständnislücken der Problemstellung füllen und die Lösung herausfallen. Nur wo passiert dies? Viel eher stehen all die minimalen Tests nur im Weg und erschweren die Weiterentwicklung der Software. Alleine mit Babysteps lösen wir das Problem nicht.

Schrittgrösse variieren

Wie aber geht man "richtig" vor? Kent Beck zeigt in "TDD By Example" wie man erst das Problem analysieren soll, eine Liste mit Testfällen (und noch anzugehenden Problemen) führt und vor allem wie man die Schrittgrösse variieren kann.

Das Red-Green-Refactor soll man beibehalten. Aber wenn man weiss wo hin man will und welche Lösung man verfolgt kann man grössere Schritte machen. Wie gross diese Schritte sind hängt vom konkreten Problem, der Vertrautheit mit der Technologie und dem angepeilten Lösungsweg ab.

Für den Lösungsweg greife ich oft auf Flussdiagramme zurück. So altmodisch die auch sein mögen, für eine grobe Skizzierung der Abläufe finde ich diese Art der Darstellung sehr hilfreich. Auch in der objektorientierten Programmierung gibt es unzählige Teilaufgaben die mit einem Flussdiagramm ideal abgebildet werden können.

Mit wenigen Worten pro Tätigkeit kann ich die einzelnen Kernaufgaben herausarbeiten. Ich sehe so auf einen Blick was alles zur Lösung dazu gehört und was es für Abhängigkeiten gibt. Passende Testfälle (und damit die Schrittgrösse) lassen sich so ebenfalls finden. Beim Programmieren tauchen dann immer noch genügend neue Testfälle auf. Diese können aber auch erst einmal nur auf eine Liste abgelegt und erst später priorisiert (oder gelöscht) werden.

Beispiele

Für das was ich bisher beschrieben habe gibt es zahlreiche gute Beispiele. Besonders empfehlen kann ich den Pluralsight-Kurs "Outside-In Test-Driven Development" von Mark Seemann. Darin wird erklärt wie man mit TDD bei den Akzeptanztests beginnt und schrittweise verfeinert bis der notwendige Code geschrieben ist. Beginnt man mit den Akzeptanztests verliert man das eigentliche Ziel nicht aus den Augen. Das Mantra Red-Green-Refactor bleibt gültig ohne dass man sich in den Babysteps verliert. Und sind diese kleinen Schritte doch nötig hat man ein Rahmenwerk das einem daran erinnert wann genug ist.

Wer Bücher bevorzugt findet in "Rails 4 in Action" von Ryan Bigg eine ausführliche Anleitung um testgetrieben eine Webanwendung zu erstellen. Hier wird noch mehr Wert auf die praktische Implementierung von TDD gelegt und gezeigt wie man mit unterschiedlichen Testebenen zu einer Lösung kommt.

Fazit

Nur weil man TDD macht muss man noch lange nicht aufhören selber zu denken. Eine Analyse der Lösung und ein grober Lösungsweg braucht es noch immer bevor man sich dem programmieren zuwendet. Verzichtet man auf diese grundlegenden Dinge schiebt man nur Code herum. Dies ist nicht nur ineffizient sondern auch teuer – sowohl beim erstmaligen schreiben wie auch bei all den kommenden Änderungen.

Daher unbedingt erst einmal abklären was man eigentlich machen will. Ist das "Was" klar geht es ans "Wie". Ob man dazu ein Flussdiagramm oder eine sonstige Skizze macht spielt keine Rolle – wichtig ist das man sich überlegt wie man vorgehen will. TDD und Red-Green-Refactor können viel besser, klarer und sinnvoller angewendet werden wenn man diese Vorarbeiten macht.