Agile / Software-Entwicklung / Software-Test

Warum sind Unit Tests rentabel?

„Dieser Stress! Wir haben keine Zeit und müssen noch so viele Features bis Ende des Monats ausliefern. Es ist momentan einfach zu stressig, um Unit Tests zu entwickeln.“

Unit Test_rentabel_Fehlersuche

Das typisches Killerargument, um die Entwicklung von Unit Tests zu verhindern. Der Hintergrund ist einfach erklärt: Wenn wir nur die Zeit des Erstellens des „produktiven“ Codes berücksichtigen, sind wir schneller ohne diese lästigen Tests. Dabei bedeutet die höhere Geschwindigkeit für einen kleinen Ausschnitt nicht, dass wir schneller ans Ziel kommen. Das Gegenteil ist der Fall – „Gleiten statt Hetzen“ in der Software Entwicklung ist die Devise und nicht kurzfristiges Hudeln.

Trotzdem funktioniert diese Killerphrase oft und ist nur ein Beispiel für viele andere. Ich höre sie häufig in vielen Unternehmen und Projekten. Das Thema Unit Test polarisiert im Jahr 2014 immer noch Entwickler, Tester, Projektleiter und Manager. Ziel ist es, sämtliche Argumente auf eine subjektive Art und Weise zu entkräften und damit jede weitere Diskussion abzuwürgen.

 

Wo befindet sich das Einsparungspotential durch einen Unit Test?

Unit Tests werden vom Entwickler während der Implementierung erstellt. Fehler, die hier gefunden und korrigiert werden sind wesentlich günstiger als Fehler, die später gefunden werden. Neben den Ergebnissen aus Studien, gibt es dafür auch eine einfache Erklärung. Dazu betrachten wir wie sich die Zeit, um einen Fehler zu korrigieren, verteilt.

1_Unit Test_Fehlersuche

Den ersten Teil nenne ich die „Fehlersuche“. Üblicherweise sind einige  Schritte notwendig, um einen Fehler zu finden und die Ursache des Problems zu verstehen:

  • Fehlerbeschreibung verstehen
  • Testumgebung und Entwicklungsumgebung aufsetzen
  • Fehler reproduzieren
  • Code verstehen und lesen
  • Debuggen
  • Code ändern, um das Problem besser zu verstehen z.B. mehr Logging

Der zweite Teil ist die eigentliche „Fehlerkorrektur„. Interessant ist, dass egal wann ich einen Fehler korrigiere, wenn ich das Problem verstanden habe, die Dauer für die Fehlerkorrektur beinahe konstant ist.

 

Warum dauert die Fehlersuche länger je weiter die Erstellung zurück liegt?

Wovon hängt die Dauer der Schritte innerhalb der Fehlersuche ab? Sie sind massiv abhängig davon wie viel Zeit vergangen ist seitdem der Entwickler diesen Code erstellt hat (= Differenz zwischen Erstellung und Fehlersuche). Der schlimmste Fall tritt dann ein, wenn ich einen Fehler in einem Codestück korrigiere, das ich nicht selbst erstellt habe. In diesem Fall benötigt der Entwickler am meisten Zeit, um den Code zu verstehen.

Wenn ich heute einen Aufsatz lesen würde, den ich während meiner Schulzeit geschrieben habe, dann würde ich mich erstens kaum daran erinnern, dass er von mir stammte und zweitens müsste ich nachdenken, was ich damals aussagen wollte.

Code zu entwickeln ist dem Vorgang des Schreibens sehr ähnlich. Der Formalismus und die Abstraktionsmöglichkeiten von Programmiersprachen machen das entwickelte Werk unverständlicher. Der Entwickler entwickelt ein eigenes mentales Modell zur Umwandlung der Anforderungen in Code. Verstehen bedeutet also zuerst den Code lesen und dann das mentale Modell des Entwicklers nachvollziehen. Das mache ich auch bei meinem eigenen Code, deswegen habe ich das Gefühl, dass ich bereits nach ein oder zwei Wochen mehr Zeit brauche, um meinen eigenen Code zu verstehen. Dabei bin ich davon überzeugt, dass ich versuche lesbaren Code zu entwickeln. Das Vergessen nimmt rasant zu und je weiter der Erstellungszeitpunkt in der Vergangenheit liegt, desto mehr Zeit muss ich ins Verstehen investieren.

2_Unit Test_Vergessenskurve

Diese Tatsache wird „die Kurve des Vergessens“ genannt, entdeckt von dem deutschen Psychologen Hermann Ebbinghaus. Die Vergessenskurve ist abhängig von der Art des zu lernenden Stoffes. Die Werte können nicht eins zu eins auf die Programmierung übernommen werden, aber zugrunde liegende Modell schon. Man kann daher die Zeit für die Suche eines Fehlers als Funktion des Vergessens darstellen.

3_Unit Test_Erinnerung

Das mit dem Vergessen gilt übrigens für alle anderen  Aufgaben auch, die zur Fehlersuche notwendig sind. Schon einmal Testdaten reproduziert und hergerichtet für einen alten Fehler? Oder vielleicht sogar die Entwicklungsumgebung zurückgesetzt, weil der Fehler nur in einer älteren Produktversion reproduzierbar ist? Alle diese Tätigkeiten dauern massiv länger je weiter die Erstellung der Software in der Vergangenheit liegt.

 

Sind Unit Tests eine günstige und rentable Lösung?

Unit Tests werden vom Entwickler während der Implementierung erstellt. Es gibt keinen günstigeren Zeitpunkt, um Fehler zu finden und zu beheben. Warum? Weil das Wissen über die entwickelte Lösung frisch im Gedächtnis haftet. Der Entwickler testet seinen Code zu dem Zeitpunkt, wo er sich inhaltlich mit den Anforderungen beschäftige und die Kurve des Vergessens erst beginnt. Dadurch reduziert sich der Aufwand für die Fehlersuche auf Null! Natürlich benötigt die Erstellung der Testfälle Zeit, aber das ist minimal im Vergleich zu dem notwendigen Aufwand für die Fehlersuche. Außerdem kann man das Erstellen der Testfälle erlernen und der Aufwand reduziert sich zunehmend mit der gewonnenen Erfahrung.

4_Unit Test_Umsetzung

Betrachtet man nur den Aspekt der Fehlersuche beim Test Driven Development Ansatz fällt auf, dass dieser noch effizienter und wirtschaftlicher ist. Im 1. Schritt entwirft und implementiert der Entwickler einen Testfall, der zu diesem Zeitpunkt fehlerhaft sein muss. Der 2. Schritt beschäftigt sich mit der Behebung, die gleichzeitig die Umsetzung ist. Im Anschluss erfolgt ein Refactoring, um die Lösung zu verbessern.

Dieser Zyklus wird so lange wiederholt, bis alle Anforderungen durch Tests umgesetzt sind. Der Aufwand für die Suche reduziert sich auf Null und Implementierung und Korrektur verschmelzen miteinander.

 

Fazit

Alleine aus dem Aspekt des Aufwands ist das frühzeitige Erstellen von Unit Tests wirtschaftlich. Es wundert mich daher wirklich, warum in so wenigen Projekten diese agile Praktik angewandt wird. Ich bin davon überzeugt, in Summe schneller und sicherer mit TDD und Unit Tests Software zu entwickeln als ohne. Ich vermeide durch das frühe Testen „wasted time“ – Zeit, die ich mit der langwierigen Fehlersuche vertrödle.

Neben dem Aufwandsaspekt der Fehlersuche gibt es weitere Gründe um TDD einzusetzen. An erster Stelle steht für mich die Fokussierung auf die tatsächlichen Anforderungen. Um Testfälle zu implementieren, müssen die Anforderungen klar formuliert werden und es wird eher vermieden, dass nicht geforderte Anforderungen umgesetzt werden. Außerdem unterstützen Unit Tests den Entwickler bei der Suche nach besseren Lösungen und Design.

 

Passende Artikel

3 Kommentare

  1. Martin Lemanski sagt:

    Hallo Roland,

    sehr guter Beitrag. Besonders über das Thema Vergessen habe ich gar nicht nachgedacht. Dabei ertappe ich mich manchmal, wie ich über meinen eigenen Code schimpfe, den ich vor längerer Zeit geschrieben habe :).

    Bei uns praktizieren wir auch TDD und fahren sehr gut damit. Coverage steigt und die Feature hatten bisher fast keine Bugs. Weiter so.

    LG, Martin

    PS: Ich mag deine Grafiken. Sie fühlen sich viel persönlicher an als digital gemachte Grafiken.

  2. Roland Germ Roland Germ sagt:

    Hallo Martin,

    Danke für deinen Kommentar.

    ciao, roland

  3. Sehr guter Kommentar, Gratulation

    Freundliche Grüsse
    Markus Zaar