Bekannt gemacht hat das Konzept Michael Feathers mit seinem 2004 erschienenen Standardwerk „Working Effectively with Legacy Code“. Darin beschäftigte er sich mit der Frage, wie sich große, ungetestete Codebestände unter Kontrolle bringen und Änderungen absichern lassen. Das Buch erschien im September 2004 und arbeitete bereits mit Beispielen in Java, C++ und C#. Characterization Tests gehören zu den dort behandelten Techniken.
Die Grundidee ist bis heute aktuell: Ein Characterization Test prüft zunächst nicht, ob eine Anwendung fachlich das Richtige tut. Er hält fest, wie sich das vorhandene System tatsächlich verhält. Dieses Ist-Verhalten wird damit überprüfbar und kann bei späteren Änderungen als Referenz dienen.
Mehr als zwei Jahrzehnte später taucht der Ansatz nun im Zusammenhang mit KI-gestützter Softwaremodernisierung wieder vermehrt auf. Einen aktuellen Anlass liefert ein Ende August veröffentlichter Beitrag von Hugo Teijiz, Gründer und CTO der Modernisierungsplattform OrkestCloud. Bereits im Juni hatte Markus Harrer, Senior Consultant bei INNOQ, das Characterization Testing in einem Vortrag über „Agentic Software Modernization“ in München aufgegriffen. Travis Frisinger, Head of Agentic AI bei 8th light, stellte bei TDD Buddy im selben Monat noch direkter die Frage, wie solche Tests KI-Agenten einen kontrollierten Einstieg in ungetesteten Legacy-Code ermöglichen könnten.
Erst das bestehende Verhalten erfassen
Teijiz beschreibt Characterization Tests als Sicherheitsnetz vor dem Refactoring von Legacy-Code. Gerade bei älteren Anwendungen bestehe die Gefahr, dass vermeintlich überschaubare Änderungen unerwartete Auswirkungen hätten. Bestehender Code könne Funktionen oder Seiteneffekte enthalten, deren Bedeutung Entwicklern nicht mehr vollständig bekannt sei.
Vor einem Refactoring sollten deshalb relevante Verhaltensweisen erfasst werden. Dazu könnten neben Rückgabewerten beispielsweise Zustandsänderungen, Datenbankoperationen, Aufrufe externer Systeme, ausgelöste Events oder Fehlerzustände gehören. Entscheidend sei dabei nicht, möglichst viel Code mit Tests abzudecken. Teijiz empfiehlt, vor allem das Verhalten abzusichern, das für die jeweils geplante Änderung relevant sei.
Dabei könne zunächst auch Verhalten dokumentiert werden, das auf den ersten Blick falsch oder ungewöhnlich erscheine. Das bedeute nicht, dass ein solcher Zustand dauerhaft erhalten werden müsse. Eine spätere Änderung werde dadurch jedoch sichtbar und könne bewusst vorgenommen werden, anstatt unbemerkt im Zuge eines Refactorings zu entstehen.
KI kann beim Erfassen helfen
Teijiz bezieht ausdrücklich KI in diesen Prozess ein. Sie könne umfangreiche Legacy-Funktionen analysieren und beispielsweise mögliche Testfälle, Zustandsänderungen, externe Aufrufe, Exceptions oder Grenzfälle identifizieren.
Eine wichtige Grenze zieht er bei den erwarteten Ergebnissen. Diese solle die KI nicht selbst bestimmen. Als Grundlage müssten nach seiner Darstellung das tatsächlich beobachtete Verhalten des Systems oder andere belastbare Quellen dienen. Die KI könne damit bei der Suche nach relevanten Testfällen unterstützen, solle aber nicht darüber entscheiden, welche Geschäftsregeln gelten.
Gerade bei Bestandsanwendungen ist diese Unterscheidung relevant. Aus dem Quellcode allein lässt sich nicht zwangsläufig erkennen, ob ein bestimmtes Verhalten fachlich gewollt, historisch gewachsen oder schlicht ein Fehler ist.
Leitplanken für AI Agents
Die Verbindung zwischen etablierten Legacy-Techniken und KI hatte im Juni auch Markus Harrer von der IT-Beratung INNOQ aufgegriffen. In seinem Vortrag „Agentic Software Modernization: Back to the Roots“ beim iSAQB Software Architecture Forum beschäftigte er sich damit, wie sich AI Agents bei der Modernisierung bestehender Softwaresysteme kontrollieren lassen.
Harrer verwies dabei auf etablierte Techniken, die als Leitplanken für agentische Modernisierung dienen könnten. Dazu zählte er Characterization Testing zur Absicherung des aktuellen Verhaltens, sogenannte Seams zur Begrenzung des „Agent Blast Radius“ und Fitness Functions, mit denen sich Qualitätsverbesserungen überprüfen ließen.
Hintergrund sei die Geschwindigkeit, mit der AI Agents umfangreiche Änderungen an einer bestehenden Codebasis vornehmen könnten. Damit werde zugleich wichtiger, überprüfen zu können, ob die Änderungen tatsächlich die gewünschten Verbesserungen bringen und unerwünschte Auswirkungen vermieden werden.
Erst Tests, dann mehr Autonomie
Noch weiter geht Travis Frisinger von der Softwareentwicklungs- und Beratungsfirma 8th light. Sein im Juni veröffentlichter Beitrag trägt den Titel „Characterization Tests Are How Agents Enter Legacy Code“. Ausgangspunkt ist die Frage, wie ein Agent Code verändern soll, wenn keine Tests vorhanden sind, die dessen bestehendes Verhalten beschreiben.
Frisinger argumentiert, dass ein Agent in diesem Fall zwar den vorhandenen Code analysieren und daraus dessen Funktion ableiten könne. Er könne jedoch nicht zuverlässig unterscheiden, welches Verhalten einen fachlichen Vertrag darstelle und welches lediglich zufällig oder historisch entstanden sei. Characterization Tests könnten zunächst eine überprüfbare Referenz schaffen.
Für das Erfassen des bestehenden Verhaltens sieht Frisinger wiederum Potenzial für die KI selbst. Ein Agent könne zahlreiche Eingaben untersuchen, die jeweiligen Ergebnisse erfassen und daraus Tests erzeugen. Die eigentliche Bewertung müsse jedoch beim Menschen bleiben: Welche Beobachtungen sollen als fachlich relevantes Verhalten erhalten bleiben, welche bedürfen weiterer Prüfung und welche müssen nicht dauerhaft abgesichert werden?
Daraus leitet Frisinger eine klare Grenze für die Autonomie von AI Agents bei Legacy-Code ab. Bevor ein Agent selbstständig einen bislang ungetesteten Bereich bearbeite, müsse das relevante bestehende Verhalten zunächst beschrieben und überprüfbar gemacht werden.
Von Java und C++ bis TypeScript
Dass Characterization Testing nicht an eine bestimmte Programmiersprache oder Systemgeneration gebunden ist, zeigt schon die zeitliche Spannweite der Beispiele. Feathers‘ Standardwerk von 2004 enthält Beispiele in Java, C++ und C#. Teijiz demonstriert das Vorgehen mehr als 20 Jahre später mit TypeScript und Vitest und weist darauf hin, dass sich das Prinzip auf andere Sprachen und Test-Frameworks übertragen lasse.
Auch die fachlichen Beispiele gehen über einfache Programmfunktionen hinaus. Teijiz nennt unter anderem Finanzberechnungen und regulatorische Regeln als Bereiche, deren Verhalten bei Änderungen besonders relevant sein könne. Hinzu kommen Datenbankzustände, externe Schnittstellen und Datentransformationen.
Einen speziellen Fokus auf Banken, Versicherungen oder Mainframes haben die aktuellen Veröffentlichungen allerdings nicht. Für Finanzinstitute ist die Diskussion dennoch interessant: Viele der genannten Anforderungen finden sich gerade in langlebigen, geschäftskritischen Bestandsanwendungen. Mit dem zunehmenden Einsatz von KI bei deren Modernisierung könnte damit auch eine alte Frage neue Bedeutung bekommen – wie sich vorhandenes Verhalten zuverlässig erfassen lässt, bevor Mensch oder Maschine den zugrunde liegenden Code verändern. (td)





