100%+ Test Coverage vs. Pivots und Rapid Prototyping: Wie macht man es richtig?

von Axel von Leitner am 5.2.2015
Für uns als Software as a Service (SaaS) Anbieter ist es essentiell, dass unsere Software genau das tut, was sie soll. Dafür schreibt man alle Arten von automatisierten Tests, denn niemand will bei großen Änderungen das halbe System manuell testen. Auf der anderen Seite wollen wir natürlich flott vorankommen und Änderungen schnell umsetzen, wenn sie nötig oder sinnvoll sind. 

Aber fangen wir vorne an, genauer gesagt vor gut 4 Jahren. Mit 2-3 Leuten begannen wir CentralStationCRM zu entwickeln. Dank unserer Programmiersprache Ruby on Rails ging das anfangs extrem schnell. Schon bald standen die Grundlagen, die ersten Kunden kamen auch. Wir arbeiten uns von Tag zu Tag voran und fanden mit der Zeit das, was im Startup-Umfeld so gerne als Product-Market-Fit beschrieben wird. Wir wussten jetzt ziemlich genau, was CentralStation sein sollte und vor allem, was nicht. 

In den ersten beiden Jahren unserer Entwicklung änderten wir Funktionen oft und in kurzen Abständen. Anstatt ewig zu diskutieren und uns in Details zu verlieren, setzten wir die für gut befundenen Ideen einfach um. “Fail early, fail often” hört man in diesem Zusammenhang oft und genau so war es. In einer so dynamischen Zeit musste man dann ggf. Änderungen zurück nehmen, wenn sie nicht funktionierten, wie erhofft. Und das möglicherweise gegen die Rufe einzelner Kunden. 

Nun ist gerade Ruby on Rails bekannt für Test-Driven-Development und auch wir hatten irgendwann die ersten Tests. Gerade während der schnellen und häufigen Iterationen kamen diese Tests aber immer zu kurz oder hingen hinterher. Gefühlt fraßen sie mehr Zeit, als sie uns sparten. Und so gab es immer mal wieder “Motivationsschübe” für ein umfangreicheres Testing, im Alltag konnte es sich aber zu dieser Zeit nie wirklich durchsetzen.

Moritz stellte neulich trefflich fest, dass wir das System damals auch primär zu zweit geschrieben und weiterentwickelt haben. Jeder von uns kannte sich also im gesamten System aus, kannte die Abhängigkeiten und den Grundaufbau. So ist es auch leicht(er) auf Tests zu verzichten. 

Mit der Zeit änderte sich dann aber die Komplexität der Software. Die Abhängigkeiten im System wurden kleinteiliger und schwerer im Kopf zu behalten. Ich meine damit nicht zusätzliche Funktionen, denn damit halten wir uns ja grundsätzlich sehr zurück, um unseren besagten Product-Market-Fit nicht zu gefährden. Nein, ich meine damit Komplexität, die der Nutzer auf den ersten Blick nicht sieht. Das perfekte Beispiel dafür ist unser Excel-Import - eine Funktion, mit der man eine Excel Liste mit Kunden in unser System überspielen kann, ohne dabei alles händisch abzutippen. 

Wenn man als CRM-Anbieter Kunden für sich begeistern will, die nicht zufällig gerade gründen und nur wenige Kontakte/Kunden haben, dann ist ein Excel-Import so ziemlich das Wichtigste. Daher war unseren Excel-Import auch bereits nach wenigen Monaten startklar. Dieser Import hatte allerdings so gar nichts mit dem Import von Heute zutun, obwohl er grundsätzlich noch immer nichts anderes tut, als eine Excel Datei einzulesen und die Daten in unser System zu importieren. Was ist also komplexer geworden? Nunja, eigentlich alles. 

Der heutige Import ist zum Beispiel deutlich fehlertoleranter. Er bricht bei einem Fehler nicht ab, sondern macht einfach weiter. Den Fehler notiert er sich und gibt ihn dem Nutzer im Anschluss genau aus. Bevor das passiert, haben wir aber schon einiges versucht, um die Daten zu retten und dem Kunden bloß keine Arbeit zu machen. In gewisser Weise versuchen wir das “Shit in, Shit out” Prinzip (die Datei ist Mist, der Import kann also auch nur Mist werden) außer Kraft zu setzen. Ein Beispiel: Wenn die Spalte der Excel-Datei mit “Webseite” überschrieben ist und in irgendeiner Zeile steht anstelle einer Webseite nun eine E-Mail Adresse, dann gibt es verschiedene Optionen. 

  • Wir könnten die E-Mail als Webseite speichern. Kurzfristig gut, weil der Kunde sich über einen Import ohne Fehler freut. Langfristig schlecht, denn seine Daten sind Murks.
  • Wir könnten auch meckern und sagen, die E-Mail Adresse passt nicht zu dem erwarteten Format. Dann bekommt der Kunde nachher eine Liste mit vielen kleinen Fehlern und hat direkt keine Lust mehr. Auch schlecht. 
  • Also probieren wir einfach einmal, ob es anstelle einer Webseite vielleicht eine E-Mail Adresse ist - denn das passiert häufiger, als man denkt. Und wenn dem so ist, dann speichern wir einfach die E-Mail-Adresse und alle sind zufrieden.

Schön und gut, aber was hat das mit Tests zutun? Eine ganze Menge. Die ersten 1-2 Jahre habe ich unseren Import kontinuierlich verbessert, damit er für diese kleinen Fehler gerüstet ist und die Kunden ein möglichst gutes Erlebnis bei diesem ätzenden Thema haben. 
Und regelmäßig machte ich den Import an einer Stelle besser, übersah dabei aber den Fall, den ich Wochen zuvor angegangen war. Das sollte mir dann aber erst beim nächsten Kunden wieder auffallen, der sich verwundert meldete. Genau hier wurde mir klar, dass wir Tests brauchen. Tests für die kleinen, aber essentiellen Randfälle in den Funktionen. 

In den ersten Monaten und Jahren mit einem kleinen Team argumentierte ich gegen Tests und für die Geschwindigkeit. Heute ist es genau anders herum. Heute macht die solide Basis an Tests uns schneller. Zum einen ist die Komplexität mittlerweile zu hoch, als dass man alle Seiteneffekte bedenken könnte. Zum anderen bringt ein größeres Team mit sich, dass nicht jeder alles gebaut hat. Moritz und Arne arbeiten teilweise parallel an ganz unterschiedlichen Dingen, so dass ich nicht mehr jeden Bereich so kenne, als hätte ich ihn selbst oder mit entwickelt. Hinzu kommt natürlich, dass Änderungen (und insbesondere Fehler) heute viel größere Auswirkungen haben, als wenige Monate nach unserem Start. 

Auch wenn unsere relativ hohe Testabdeckung für uns heute Gold wert ist und ich mich jedesmal freue, wenn mich eine der Tausenden Annahmen auf einen noch so kleinen Fehler hinweist: Bei kleinen, sich schnell ändernden Projekten würde ich es immer wieder so machen wie damals. Ich würde die schnelle Iteration der möglichst hohen Testabdeckung vorziehen. Der Zeitpunkt ab dem die Tests mehr nutzen, als sie an Zeit kosten, kommt sicherlich. Am Anfang der Reise war das bei uns nicht so.
LinkedInFacebook

Axel von Leitner

Mitbegründer von 42he. Beschäftigt sich mit den betriebswirtschaftlichen Dingen und steckt viel Herzblut in Design & Usability. Axel schreibt insbesondere über Produktivität, Design und Startup-Themen.