Vor einiger Zeit rief mich ein Kunde an. Im Applikationserver eines Testsystems war eine In-Doubt Transaction aufgetreten. Ein Desaster ruft um Hilfe. Im Normalfall sind diese Fehler extrem selten. Außerdem war es nur ein Testsystem. War wohl irgendein Zufall. Die Transaktion wurde zurückgerollt und die Sache war erledigt.
Zwei Wochen später brach das Inferno los. Nach dem Produktivgang einer neuen Version traten Fehler im Transaktionshandling von globalen Transaktionen zwischen zwei unternehmenskritischen Applikationen auf. Bei ungefähr einer von 3000 Buchungen traten Inkonsistenzen auf. Taskforce, Management-Reports, Red Hat Support, das ganze Programm. Das Desaster hatte zugeschlagen. Der Betrieb hatte doch nur einen Loadbalancer und redundante JBoss-Server eingefügt. Wir haben gelernt, dass globale Transaktionen und Webservices mit dieser Konfiguration nicht funktionieren. Auf die harte Tour.
Leider ignorieren wir Warnungen allzu oft. Flaky Tests werden als nicht änderbare Naturgewalten angesehen. Oft verstecken sich aber echte Fehler hinter den Problemen, die durch genaueres Hinsehen entdeckt und bereinigt werden können. Vor ca. drei Jahren bei der DevConf Bünn haben Red Hat Entwickler:innen von einem Projekt berichtet, in dem sie gezielt Flaky Tests analysiert und in Folge etliche Fehler im Linux-Code bereinigt haben. Die Hilferufe des Desasters wurden erhört.
Ziemlich jedes Projekt hat ein Repository in dem Hilferufe drohender Desaster gesammelt werden. Es wird auch Issue-Tracker genannt und die Hilferufe Bugs oder Issues. Wir können Bugs ansammeln oder ernst nehmen. Ein Konzept wie man sie ernst nimmt ist die Zero Bug Policy. Kurz gesagt besagt sie, dass alle Bugs Vorrang vor Features oder Verbesserungen haben. Ein Bug ist ein Bug oder kein Bug. Keine Unterscheidung in schwer, leicht, dringend, egal. Genial einfach! Wenn man sich etwas mit dem Konzept beschäftigt erkennt man, dass es die billigste Art ist mit Fehlern umzugehen. Bessere Qualität für weniger Geld. Warum machen es nicht alle so? Ich weiß es nicht. Anscheinend haben in traditionellen Softwareentwicklungsprojekten Bugs einen subtilen Mehrwert für das Management und vielleicht auch für Entwickler:innen.
Wir können also erkannte Bugs bereinigen, aber wo Menschen sind werden Fehler gemacht und das Entstehen von Fehler können wir nicht verhindern, oder?
Mit 18 Jahren kaufte ich mein erstes Motorrad, eine gebrauchte Yamaha XT500 Baujahr 1980. Eines Tages blieb ich auf der Strecke kurz stehen, um irgendetwas zu kontrollieren. Den Motor ließ ich laufen. Wenige hundert Meter weiter, in einer leichten Linkskurve, hörte ich ein scharrendes Geräusch. Ich konnte es mir nicht erklären und blieb stehen. Es stellte sich heraus, dass ich beim Weiterfahren vergessen hatte den Seitenständer einzuklappen. Zu dieser Zeit starben immer wieder Motorradfahrer:innen, weil es sie in einer Kurve über einen ausgeklappten Seitenständer aushebelte. Ein Desaster ruft um Hilfe. Man darf das halt nicht vergessen! Das reicht aber nicht. Man muss Wege finden, um das Vergessen zu erschweren. Z.B. eine einfache Routine, ein einfaches Protokoll das man immer, wirklich immer, durchführt.
Für mich war das ein 3-Punkte Check bevor ich einen Gang einlege. Seitenständer, Benzinhahn, Licht – Check. Immer. Später wurde ein Gesetz eingeführt, dass es technisch unmöglich sein muss mit ausgeklapptem Seitenständer wegzufahren. Das ist die bessere Lösung des Problems. Menschen haben über das Problem nachgedacht, gehandelt, und Menschenleben gerettet.
Auch in der Softwareentwicklung haben Menschen über das Problem nachgedacht wie man die Fehlerwahrscheinlichkeit verringern kann, mit welchen Prozessen und Checks die Qualität verbessert werden kann. Ergebnis waren Test Driven Development, Pair Programming oder Code Reviews. Test Driven Development (TDD) fordert nicht, dass es für jeden geschriebenen Code einen Test gibt, den man z.B. auch morgen oder übermorgen schreiben könnte, sondern TDD fordert, dass man nur dann produktiven Code schreibt, wenn man vorher einen Test dafür hat. Dass es für jeden produktiven Code einen Test gibt, wird so zum erwünschten Nebenprodukt.
Allen diesen Praktiken ist eines gemeinsam. Sie benötigen eine positive Einstellung gegenüber Fehlern. Nicht, dass Fehler selbst positiv sind, sie können ernsthafte Schäden verursachen, aber Fehler werden nicht als unerwünschte Störung, sondern als positive Herausforderung gesehen. Unsere Bugs benötigen etwas liebevolle Aufmerksamkeit. Nicht nur einfach liegen lassen und irgendwann schnell abarbeiten. Wenn wir sie ignorieren, schlagen sie zu.
Arbeiten wir daran die Ursache zu finden und nicht nur das Symptom zu bekämpfen. Was können wir an unseren Prozessen verbessern, damit die Bugs erst gar nicht entstehen? Genau um an solchen Themen zu arbeiten wurden agile Entwicklungsprozesse mit Retrospektiven und Iterationen entwickelt.