Am 4. September war ich beim legendären Freitagsfrühstück von team neusta und habe meine KI-Strategie vorgestellt. Rund 170 Zuhörerinnen und Zuhörer. Vielen Dank erst einmal für die Einladung.
Und dann ging es los. Diskutiert wurde ordentlich, und der Widerspruch kam genau da, wo ich ihn immer bekomme: bei den Leitplanken. Mein Satz war, dass die KI das braucht, was Softwareentwicklung schon immer gebraucht hat. Architektur, Test-First, Coverage, Mutationstests, Gates im Build.
Die Gegenfrage war besser als das, worauf ich vorbereitet war. Sie ging so: Wenn es am Ende funktioniert, wenn die Security-Vorgaben eingehalten sind, wenn die Fachlichkeit stimmt, warum stören dann zehn Zeilen Code, die keiner mehr braucht? Bei der nächsten Anforderung sind sie sowieso weg. Diese Regeln haben wir für Menschen erfunden. Gelten sie noch?
Ich habe die Frage mitgenommen und nachgelesen. Das Ergebnis hat meine Position an einer Stelle bestätigt, an einer zweiten geschärft und an einer dritten korrigiert.
Coverage ist eine Behauptung
Dabei bleibe ich: Eine Testabdeckung ohne Mutationstests sagt fast nichts über Qualität. Coverage misst, wie gründlich die Tests durch den Code laufen. Sie misst nicht, ob die Tests einen Fehler überhaupt bemerken würden. Ein Test ganz ohne Zusicherung bringt dieselben 100 Prozent wie ein guter.
Geschärft hat mich, was Google macht. Dort laufen Mutationstests seit Jahren produktiv, über tausend Projekte, und der absolute Mutation Score wird bewusst nicht berechnet. Zu teuer bei zwei Milliarden Zeilen. Und aus ihrer Sicht sagt die Zahl niemandem, was er als Nächstes tun soll. Mutiert werden nur die geänderten, abgedeckten Zeilen, im Review, und Mutanten in uninteressanten Zeilen wie Logausgaben werden unterdrückt.
Das nehme ich mit. Mein Anspruch heißt ab jetzt 100 Prozent auf dem Diff. In meinen eigenen Projekten ist das dasselbe wie 100 Prozent insgesamt, weil ich sie von Anfang an so gebaut habe. Wer eine gewachsene Codebasis vor sich hat, kommt anders nie los.
Mein Versuch, und was die Forschung dazu sagt
Michael Albrecht und ich haben vor einiger Zeit intern etwas ausprobiert. Wir haben dasselbe Projekt zweimal entwickelt, einmal Test-First und einmal Test-Last, und dann den Mutation Score verglichen. Bei Test-First war er sehr hoch. Bei Test-Last sehr niedrig. Für mich war die Sache damit klar.
Die Forschung ist da unbequemer. Lech Madeyski hat 2010 genau diesen Vergleich als Experiment durchgeführt, Test-First gegen Test-Last, gemessen an Branch Coverage und Mutation Score. Er fand keinen Unterschied, der sich von Zufall unterscheiden ließ. Aleksandar Causevic kam in einem ähnlichen Aufbau auf 81,9 gegen 83,3 Prozent, also praktisch dasselbe. Erst eine Langzeitstudie von Simone Romano aus dem Jahr 2021 fand einen Vorteil für TDD bei der Fehlerfindungsfähigkeit der geschriebenen Tests, und der war knapp.
Ich halte trotzdem an Test-First fest, aber ich formuliere es jetzt als das, was es ist: meine Erfahrung, nicht ein bewiesener Satz. Und ich habe eine Vermutung, warum unsere Zahlen so viel weiter auseinanderlagen als die aus den Experimenten. In den Studien schreiben beide Gruppen Tests, unter derselben Vorgabe. Im Alltag heißt Test-Last, dass die Tests gegen den fertigen Code geschrieben werden. Dann zeichnet der Test die Implementierung nach statt die Anforderung, und er trifft dieselbe falsche Annahme wie der Code. Genau das killt keine Mutanten.
Es ist nicht die Reihenfolge, es ist die Schrittgröße
Davide Fucci hat TDD auseinandergenommen und in vier Merkmale zerlegt: die Reihenfolge, die Länge der Zyklen, wie konstant diese Länge bleibt, und den Aufwand fürs Refactoring. Ausgewertet hat er, wie 39 Profis wirklich gearbeitet haben. Qualität und Produktivität hingen an der Zykluslänge und an ihrer Gleichmäßigkeit. Die Reihenfolge hatte keinen nennenswerten Einfluss.
Das ist eine gute Nachricht für alle, die glauben, sie müssten erst ein Ritual lernen. Die Leitplanke heißt: kleine Schritte, gleichmäßiger Takt. Übersetzt auf meine Arbeit mit Agenten heißt das kleine Issues. Ein Issue, eine Fachlichkeit, ein Durchlauf. Das ist auch der Grund, warum ich Leuten, die mit KI anfangen, nie zuerst ein Werkzeug empfehle, sondern kleinere Anforderungen.
Und jetzt kommt der Teil, der mich überrascht hat
Bei Sprachmodellen kippt der Befund.
Es gibt eine Untersuchung dazu, was passiert, wenn ein Agent erst den Code schreibt und danach die Tests. Die Fehler aus dem Code wandern in die Tests. Implementierung und Test werden gemeinsam falsch und stimmen dabei perfekt überein, decken sich also gegenseitig. Die Fehlererkennung fällt von 25 auf 14 Prozent, wenn die Tests nach dem Code entstehen statt unabhängig davon.
Bei Menschen war die Reihenfolge nach Aktenlage Geschmackssache. Bei Modellen ist sie messbar teuer. Ich finde das die interessanteste Zahl der ganzen Recherche, weil sie meine Kernthese härter macht, als ich sie bisher formuliert habe. Ich habe immer gesagt, dass die KI genau das braucht, was es schon immer brauchte, nur sehen wir es jetzt wie unter einer Lupe. Hier ist es stärker. Eine Praktik, die bei Menschen kaum messbar war, wird beim Modell zur Voraussetzung.
Die Pyramide drehe ich nicht um
Damit zu dem Punkt, an dem ich mich korrigiert habe. Ich war nahe dran, für deutlich mehr End-to-End-Tests zu argumentieren, weil die KI sie so billig macht. Das war zu kurz gedacht.
Billiger geworden ist das Schreiben. Die Laufzeit ist unverändert. Die Flakiness ist unverändert. Und die Diagnose ist unverändert teuer. Bei Google gingen 16 Prozent der Testrechenzeit für flakige Tests drauf, und ein einzelner davon kostete im Schnitt 3,7 Stunden Arbeitszeit. Dazu kommt mein eigener Grundsatz: Leitplanken müssen scheitern können. Ein roter End-to-End-Test sagt mir, dass etwas kaputt ist. Er sagt mir nicht, was.
Gesucht habe ich nach Forschung, die die Umkehrung stützt. Gefunden habe ich Marketingtexte von Firmen, die Testautomatisierung verkaufen. Das ist kein Gegenbeweis, aber es ist auch keine Grundlage, auf der ich eine Teststrategie ändere.
Bleibt die Frage vom Frühstück. Zehn überflüssige Zeilen sind kein Drama. Kritisch wird es, wenn dieselbe Fachlichkeit ein zweites Mal im Projekt landet.
Duplikate nehmen in KI-Projekten messbar zu, und SonarQube meldet sie mir zuverlässig. Es meldet allerdings nur die eine Hälfte. Ein Sprachmodell zieht das nächste Token aus einer Verteilung, deshalb schreibt es dieselbe Sache nie zweimal gleich. Anderer Name, andere Parameter, anderer Rückgabewert, andere Implementierung, identische Wirkung. Für jedes tokenbasierte Werkzeug sind das zwei verschiedene Methoden.
In einem meiner Projekte lagen drei Implementierungen von getRepoName() nebeneinander, mit drei verschiedenen Rückgabeformen. Im Duplikatsbericht stand dazu nichts. Aufgefallen ist es beiläufig in einer laufenden Sitzung. Wie man solche Fälle beweist, statt sie zu vermuten, habe ich in einem eigenen Papier beschrieben: Beweisen statt vermuten.
Die zehn Zeilen kosten mich also wenig. Teuer wird, dass ich beim zweiten Mal nicht merke, dass es das zweite Mal ist.

Schreibe einen Kommentar