Alle Artikel
12. September 2026
8 mins

Coding-Agenten im Altsystem

Von Tim Rutte, Cloud & Software ArchitectThemaKI & Automatisierung

Ein Roboterarm greift in eine Maschine, dazwischen steht eine Schutzscheibe im blauen Rahmen.

Coding-Agenten werden an neuen Projekten vorgeführt, und dort sehen sie gut aus: leeres Verzeichnis, klarer Auftrag, keine Geschichte. Der Code, um den es in den meisten Unternehmen tatsächlich geht, sieht anders aus. Er ist zwölf Jahre alt, hat vier Generationen von Entwicklern überlebt, und die Hälfte der Entscheidungen darin steht nirgends geschrieben.

Die verbreitete Erwartung an diesem Punkt ist, dass ein Agent mit so einem System schlechter zurechtkommt als mit einem neuen. Das stimmt, aber nicht aus dem Grund, den die meisten vermuten. Es liegt nicht an der Sprache, nicht am Alter und nicht am Stil. Es liegt daran, dass das Entscheidende nicht im Code steht.

Dieser Artikel handelt davon, wofür ein Agent im Bestand tatsächlich taugt, woran er zuverlässig scheitert, und welche Vorbedingung den Unterschied macht.

Was einem Agenten im Bestand fehlt

Ein Agent liest, was dasteht. In einem gewachsenen System ist das der kleinere Teil der Wahrheit.

Er sieht die Verzweigung, die für einen einzigen Großkunden existiert, aber nicht, dass sie nach dessen Kündigung 2021 nur noch aus Vorsicht dasteht. Er sieht zwei Tabellen mit fast gleichem Inhalt, aber nicht, welche von beiden das Abrechnungssystem liest. Er sieht eine Funktion, die aussieht wie tot, und nicht den nächtlichen Aufruf aus einem Skript, das in einem anderen Verzeichnis liegt.

Das ist kein Modellproblem, das mit der nächsten Version verschwindet. Diese Information existiert nirgends als Text. Sie existiert in drei Köpfen, und einer davon ist letztes Jahr gegangen.

Daraus folgt die praktische Regel für alles Weitere: Ein Agent ist im Altcode so gut wie das, was jemand ihm über das System aufgeschrieben hat, und dieses Aufschreiben ist die eigentliche Arbeit.

Wofür es zuverlässig taugt

Vier Aufgaben funktionieren im Bestand besser, als die Skepsis erwarten lässt, und sie haben ein gemeinsames Merkmal: Es gibt eine Instanz, die das Ergebnis prüft, und sie ist nicht der Mensch.

Orientierung. „Verfolge den Weg einer Bestellung vom Eingang bis zur Rechnung und nenne jede Datei, die dabei beteiligt ist." Das ist eine Aufgabe, für die ein neuer Entwickler zwei Tage braucht und ein Agent zehn Minuten, und das Ergebnis lässt sich gegen den Code prüfen. Es ist auch die Aufgabe, die den Einstieg in ein fremdes System am stärksten verkürzt.

Charakterisierungstests. Tests, die festhalten, was der Code heute tut, ohne zu bewerten, ob es richtig ist. Diese Arbeit ist stumpf, umfangreich und für einen Menschen unangenehm, und sie ist die Voraussetzung für jeden Umbau. Für einen Agenten ist sie ideal, weil das Ergebnis sofort messbar ist: Der Test läuft gegen den unveränderten Code, oder er ist falsch.

Mechanische Umbauten mit einem Schiedsrichter. Eine veraltete Funktion an zweihundert Stellen ersetzen, eine Signatur ändern, einen Zugriff umstellen. Der Schiedsrichter ist der Übersetzer, die statische Prüfung oder die Testsuite. Wo es einen gibt, ist die Arbeit erledigt, wenn er schweigt.

Wiederkehrende Muster übertragen. Sind achtzehn Controller nach demselben Schema gebaut und muss jeder dieselbe Änderung bekommen, ist der erste von Hand und die restlichen siebzehn sind eine Aufgabe, die niemand vermissen wird.

Woran es zuverlässig scheitert

Die Fehlerarten sind ebenso vorhersagbar, und das ist die gute Nachricht: Vorhersagbares lässt sich abfangen.

Stilles Ändern von Verhalten. Der häufigste Schaden entsteht nicht durch Code, der nicht läuft, sondern durch Code, der läuft und etwas anderes tut. Ein Agent räumt eine merkwürdige Sonderbehandlung auf, weil sie nach einem Versehen aussieht. Sie war die Umsetzung einer Vereinbarung mit einem Kunden.

Plausible Annahmen über Totes. „Diese Methode wird nirgends aufgerufen" ist im Bestand eine Aussage über die Suche, nicht über die Wirklichkeit. Aufrufe über Zeichenketten, Konfigurationsdateien, Cronjobs und andere Repositorys sind unsichtbar.

Tests, die bestehen sollen. Ein Agent, der eine Änderung und ihre Tests schreibt, hat zwei Stellschrauben für dasselbe Ziel. Kommt er nicht durch, ändert er den Test. Das ist kein böser Wille, sondern die logische Antwort auf einen schlecht gestellten Auftrag.

Zu große Ausschnitte. Eine Datei mit viertausend Zeilen ist für ein Kontextfenster kein Problem mehr. Der Zusammenhang zwischen dieser Datei und den elf anderen, die von ihr abhängen, ist weiterhin eines. Große, vage Aufträge erzeugen große, plausible und falsche Ergebnisse.

Die Vorbedingung, ohne die nichts davon gilt

Alles Obige setzt dasselbe voraus: eine Möglichkeit zu prüfen, ob sich Verhalten geändert hat. Ohne sie vervielfacht ein Agent nicht die Geschwindigkeit, sondern das Risiko, und zwar in einem Tempo, bei dem die Überprüfung nicht mitkommt.

Das heißt nicht, dass erst eine vollständige Testsuite entstehen muss; das wäre ein Vorhaben von Monaten und der übliche Grund, es gar nicht erst anzufangen. Es reicht ein Netz um die Stelle, die angefasst wird, und genau dieses Netz ist selbst eine gute erste Aufgabe für den Agenten.

Die Reihenfolge, die sich bewährt hat, ist deshalb immer dieselbe, und sie trennt die beiden Aufgaben bewusst: erst die Tests, die den heutigen Zustand festhalten, dann von einem Menschen angesehen, dann die Änderung. Wer beides in einem Auftrag verlangt, bekommt Tests, die zur Änderung passen.

Schritt 1  Schreibe Tests, die das heutige Verhalten von
           RabattRechner festhalten. Erfinde nichts und bewerte
           nichts. Wo du unsicher bist, was richtig ist, halte
           fest, was der Code tut, und markiere die Stelle.

  (Mensch liest die Tests. Nicht den Code: die Tests.)

Schritt 2  Die Tests sind die Grenze. Baue den Rabattstaffel-Teil
           um, ohne dass einer davon rot wird. Faellt ein Test,
           melde es, statt ihn anzupassen.

Der zweite Satz in Schritt 2 ist der wichtigste des ganzen Vorgehens. Ohne ihn verschiebt sich die Grenze mit der Arbeit.

Wie dieses Netz entsteht, wenn es keine Tests gibt, steht in Legacy-Code testen, wenn es keine Tests gibt.

Das, was aufgeschrieben werden muss

Bleibt der Teil, der am Anfang stand: Das Entscheidende steht nicht im Code. Es muss also hin, und zwar an eine Stelle, die der Agent bei jeder Aufgabe liest.

Was dort hineingehört, ist nicht die Architektur. Es ist das, was ein neuer Kollege am ersten Tag falsch machen würde:

Die Tabelle `bestellung_alt` wird noch gelesen, aber nicht mehr
geschrieben. Die Abrechnung haengt daran. Nicht anfassen.

Alles unter src/Legacy/Export laeuft nachts per Cronjob, nicht
ueber die Anwendung. Aufrufe sind dort per Zeichenkette
zusammengesetzt und mit der Suche nicht auffindbar.

Sonderbehandlungen mit dem Kommentar "KD-####" sind Vereinbarungen
mit einzelnen Kunden. Sie sehen falsch aus und sind es nicht.
Vor einer Aenderung fragen.

Tests laufen mit `make test`. `vendor/bin/phpunit` direkt nimmt
die falsche Konfiguration und ist gruen, wenn es nicht sollte.

Diese Datei entsteht nicht an einem Nachmittag, sondern über Wochen, und der Anlass ist jedes Mal derselbe: Immer wenn ein Agent etwas falsch verstanden hat, das ein Mensch gewusst hätte, kommt der Satz dazu, der ihm gefehlt hat.

Der Nebeneffekt ist wertvoller als der Anlass. Was man einem Agenten aufschreiben muss, muss man ohnehin jedem neuen Kollegen sagen. Nach einem halben Jahr steht dort das, was vorher in drei Köpfen lag, und der Bus-Faktor ist nicht mehr eins.

Für mechanische Änderungen ist ein deterministisches Werkzeug die bessere Wahl: Rector im Altprojekt.

Was sich am Prüfen ändert

Die Durchsicht wird nicht überflüssig, sie verschiebt sich, und das wird im Team am wenigsten vorbereitet.

Bei menschlichem Code prüft man vor allem, ob die Lösung richtig ist. Bei erzeugtem Code ist die Lösung meist plausibel und oft richtig; die zwei Fragen, die zählen, sind andere. Ist das die Änderung, die verlangt war? Und: Was hat sie angefasst, wonach niemand gefragt hat?

Daraus folgt eine Vorgabe, die mehr bringt als jede Richtlinie zum Stil: Ein Änderungsantrag hat einen Zweck, und alles darin muss zu diesem Zweck gehören. Eine nebenbei aufgeräumte Datei, eine nebenbei geänderte Abhängigkeit, ein nebenbei umbenanntes Feld gehen zurück, auch wenn sie für sich genommen Verbesserungen sind. Im Bestand ist die Überraschung teurer als die Verbesserung.

Die Zahl, an der man es misst

Zum Schluss die Frage, die bei einer solchen Einführung immer kommt: Woran sieht man, ob es etwas bringt?

Nicht an Zeilen pro Tag, und auch nicht am Anteil erzeugten Codes. Beide Zahlen steigen zuverlässig und sagen nichts darüber, ob das System danach besser zu ändern ist.

Die Zahl, die zählt, ist die Zeit bis zur ersten sicheren Änderung in einem Bereich, den niemand im Team kennt. Sie lag vorher bei Tagen. Mit Charakterisierungstests, einer gepflegten Kontextdatei und einem Schnitt, der eine Sache zur Zeit ändert, liegt sie bei Stunden. Das ist der Gewinn, und er entsteht nicht am Modell, sondern an dem, was daneben aufgeschrieben wurde.

Wie ich das in Teams einführe, steht auf einer eigenen Seite.

Dieser Artikel gehört zu einer Reihe über Systeme, die es schon gibt. Der Rückblick ordnet alle Artikel der Reihe nach Anlass.