Ein Sinnbild dafür, dass die einfachste Lösung oft die tragfähigste ist.
Brian Kernighan brachte es in „The Elements of Programming Style“ (Kernighan & Plauger, 1978) auf den Punkt: Das Debuggen ist doppelt so schwer wie das Schreiben von Code. Wenn wir also so clever wie möglich programmieren, sind wir per Definition nicht klug genug, um unseren eigenen Code zu debuggen. Ein Satz, über den wir kurz schmunzeln. Bis uns auffällt, dass Kernighan uns gerade ertappt hat.
Denn seien wir ehrlich: Wir alle haben schon Code geschrieben, der uns beim Schreiben brillant vorkam. Eine elegante Abstraktion hier, ein raffiniertes Pattern dort. Und dann kommen wir sechs Monate später zurück und verstehen unsere eigene Brillanz nicht mehr. Noch schlimmer ist es, wenn eine andere Person diesen Code warten muss und keine Chance hat, die Überlegungen hinter unseren Entscheidungen nachzuvollziehen.
Das Problem wird noch deutlich größer, sobald KI-Agenten ins Spiel kommen. In meinem Artikel „Schneller als Verstehen“ beschreibe ich, wie ein KI-Agent eine nicht-triviale Softwaremetrik in 15 Minuten umgesetzt hat. Anschließend habe ich Stunden damit verbracht, zu überprüfen, ob die Umsetzung korrekt ist. Der Code sah sauber aus. Die Tests waren grün. Aber richtig aussehen und richtig sein sind nicht dasselbe. Mehr Code bedeutet nicht automatisch mehr Wert. Vor allem nicht, wenn ich nicht weiß, ob der Code das tut, was er tun soll.
Code ist kein Vermögenswert
In unserer Branche gibt es ein hartnäckiges Missverständnis: dass mehr Code automatisch mehr Wert bedeutet. Eine wachsende Codebasis gilt als Zeichen von Fortschritt. Oder dass die Anzahl der Zeilen, die wir pro Tag schreiben, ein Maß für unsere Produktivität ist.
Das Gegenteil ist der Fall. Das wusste Edsger Dijkstra bereits 1975: In seinem Essay „How do we tell truths that might hurt?“ formulierte er, dass wir Codezeilen nicht als „lines produced“, sondern als „lines spent“ verbuchen sollten: als Ausgaben, nicht als Einnahmen. Die landläufige Meinung verbucht sie auf der falschen Seite.
Jede Zeile Code birgt das Potenzial für einen Bug. Jede Zeile Code ist eine Zeile, die ein Sicherheitsproblem enthalten kann. Jede Zeile Code ist eine Zeile, die ich bei zukünftigen Änderungen berücksichtigen muss und die langfristig zu einem Problem werden kann.
Code ist eine Verbindlichkeit, kein Vermögenswert.
Die versteckten Kosten
Was für manuell geschriebenen Code gilt, gilt umso mehr für automatisch generierten Code. Der KI-Agent aus meinem Beispiel hat Code produziert, dessen Funktion ich bis heute nicht mit Sicherheit beurteilen kann. Es ist die teuerste Art von Code: Code, dessen Daseinsberechtigung niemand mehr hinterfragen möchte, weil das Risiko einer Änderung unkalkulierbar geworden ist.
Sir Tony Hoare beschrieb dieses Spannungsfeld in seiner Turing-Award-Vorlesung „The Emperor's Old Clothes“: Wir können eine Software entweder so einfach gestalten, dass keine Mängel offensichtlich sind, oder sie so kompliziert machen, dass keine offensichtlichen Mängel vorhanden sind. Oder wir machen sie so kompliziert, dass keine offensichtlichen Mängel vorhanden sind. KI-generierter Code tendiert zur zweiten Variante. Unsere Aufgabe ist es, auf der ersten zu bestehen.
Nicht jedes Problem braucht Code
Im selben Essay hat uns Edsger Dijkstra auch daran erinnert, dass Einfachheit eine Voraussetzung für Zuverlässigkeit ist.
Bevor ich auch nur eine Zeile Code schreibe, sollte ich mich fragen: Muss dieses Problem überhaupt mit Software gelöst werden? Gibt es einen Prozess, eine Konvention oder ein Gespräch, durch das neuer Code überflüssig wird? Und wenn Code unvermeidlich ist, lautet die Frage: Was ist die einfachste Lösung, die funktioniert?
Code, den ich nicht habe, verursacht keine Probleme.
Das gilt unabhängig davon, ob ein Mensch oder eine Maschine ihn erstellt hat. Ob ich 15 Minuten oder drei Tage für eine Implementierung brauche, ist irrelevant, wenn das Problem gar nicht erst mit Code gelöst werden müsste.
Für Menschen schreiben
Martin Fowler schrieb 1999 in „Refactoring: Improving the Design of Existing Code“, dass jeder Anfänger Code schreiben kann, den ein Computer versteht. Gute Programmiererinnen und Programmierer aber schreiben Code, den Menschen verstehen. Harold Abelson und Gerald Sussman formulierten es in „Structure and Interpretation of Computer Programs“ noch grundsätzlicher: Programme sollten für Menschen geschrieben werden und nur nebenbei für Maschinen.
Code, den ich verstehen kann, bereitet keine Probleme. Probleme bereitet der Code, den niemand mehr versteht, den niemand mehr zu ändern wagt und den niemand löschen möchte, da unklar ist, was dann passieren würde.
Den treffendsten Ratschlag dazu hat John F. Woods 1991 in einem Beitrag in der Newsgroup comp.lang.c++ formuliert: „Programmiere immer so, als sei die Person, die deinen Code am Ende warten muss, ein gewalttätiger Psychopath, der weiß, wo du wohnst.“ Hinter dem Humor steckt eine ernste Wahrheit. Code muss sich selbst erklären. Nicht durch Kommentare oder externe Dokumentation, sondern durch seine Struktur, seine Benennung und seine Einfachheit.
Perfektion durch Weglassen
Der Schriftsteller Antoine de Saint-Exupéry hat es 1939 in „Terre des Hommes“ so formuliert: „Perfektion ist nicht dann erreicht, wenn es nichts mehr hinzuzufügen gibt, sondern wenn es nichts mehr wegzunehmen gibt.“
Dies sollte der Maßstab sein, den wir an unsere Software anlegen. Nicht: „Was kann ich noch hinzufügen?“ Sondern: Was kann ich noch weglassen?
Code, den ich nicht habe, verursacht keine Probleme. Code, den ich verstehen und testen kann, bereitet ebenfalls keine Probleme. Und für alles dazwischen brauche ich Tests: für den Code, von dem ich nicht weiß, ob ich ihn noch brauche und ob er das tut, was er tun soll. Tests, die mir das Vertrauen geben, Code zu ändern oder zu löschen. Tests, die dokumentieren, was der Code tun soll. Tests, die mir sagen, wenn etwas kaputt ist.
Einfachheit ist Disziplin
Einfachen Code zu schreiben, ist schwieriger als komplizierten. Es erfordert, dass wir ein Problem wirklich verstanden haben, bevor wir es lösen können. Wir müssen den Mut haben, Nein zu sagen: Nein zu einer Abstraktion, die niemand braucht. Nein zu einem Feature, das vielleicht irgendwann einmal nützlich sein könnte. Nein zu einer cleveren Lösung, wenn eine einfache reicht. Und ja, auch zu 15 Minuten KI-generiertem Code, wenn wir seine Korrektheit nicht beurteilen können.
Einfachheit ist keine Schwäche. Sie ist Disziplin. Und sie ist die beste Versicherung, die wir für die Zukunft unserer Software abschließen können.