Sie öffnen eine Datei, die 1.800 Zeilen lang ist. Eine Funktion namens process() nimmt sieben Parameter, von denen drei irgendwo tief drin per global überschrieben werden. Es gibt keinen Test, keinen Kommentar, der stimmt, und der Kollege, der das geschrieben hat, ist seit vier Jahren nicht mehr im Unternehmen. Trotzdem läuft dieser Code jeden Tag und wickelt echte Bestellungen ab.
Das ist die typische Ausgangslage. Und der erste Reflex ist meist der falsche: alles wegwerfen und neu bauen. Bevor Sie diesen Weg gehen, lohnt sich eine andere Perspektive. Ein System, das seit Jahren im Produktivbetrieb läuft, ist kein Müll. Es ist der Beweis, dass die Fachlogik funktioniert. Das Problem ist fast nie die Logik selbst, sondern der Code drumherum, der sie unlesbar macht.
Warum ist alter PHP-Code oft unlesbar, obwohl er funktioniert?
Unlesbarer Legacy-Code entsteht selten durch Inkompetenz, sondern durch Zeitdruck über viele Jahre. Jede Änderung war für sich sinnvoll, aber niemand hatte je das Budget, danach aufzuräumen.
Typische Ursachen, die Ihnen in fast jeder gewachsenen PHP-Anwendung begegnen:
- Vermischte Verantwortlichkeiten: Datenbankzugriff, HTML-Ausgabe und Geschäftslogik stehen in derselben Funktion.
- Namen, die lügen: Eine Variable
$tmp, die durch die halbe Datei getragen wird, odergetUser(), die nebenbei auch noch speichert. - Impliziter Zustand:
global, statische Variablen und Superglobals wie$_SESSION, die mitten in der Logik gelesen werden. - Toter Code: auskommentierte Blöcke und
if (false)-Zweige, bei denen niemand mehr weiß, ob sie noch gebraucht werden.
Wichtig ist die Einsicht: Die Fachlogik in diesem Code ist wertvoll. Sie kodiert Jahre an Sonderfällen, Steuerregeln und Kundenwünschen, die nirgendwo dokumentiert sind. Genau deshalb ist eine Neuentwicklung meist die teuerste und riskanteste Option. Sie werfen nicht schlechten Code weg, sondern ungeschriebenes Wissen.
Wie machen Sie Legacy Code lesbar, ohne das Verhalten zu ändern?
Der Schlüssel ist eine strikte Trennung: Zuerst nur lesbarer machen, ohne das Verhalten zu ändern. Refactoring und Bugfix dürfen niemals im selben Schritt passieren, sonst wissen Sie bei einem Fehler nie, was ihn ausgelöst hat.
Konkret gehen Sie in dieser Reihenfolge vor:
- Sicherheitsnetz spannen. Bevor Sie eine Zeile anfassen, schreiben Sie einen Charakterisierungstest (characterization test). Der prüft nicht, was der Code tun sollte, sondern hält fest, was er aktuell tut — inklusive der Macken. Für schwer testbaren Code reicht anfangs ein grober Test auf Ein- und Ausgabe eines ganzen Skripts.
- Formatierung automatisieren. Lassen Sie einmal PHP-CS-Fixer oder PHP_CodeSniffer über die Datei laufen. Einheitliche Einrückung und Klammern kosten Sie null Denkleistung und machen die Struktur sofort sichtbar.
- Namen reparieren. Benennen Sie Variablen und Funktionen so um, dass sie die Wahrheit sagen. Ihre IDE erledigt das sicher. Aus
$dwird$deliveryDate, ausdoStuff()wirdcalculateShippingCost(). - Kleine Einheiten extrahieren. Ziehen Sie zusammengehörige Zeilen in kleine, benannte Methoden heraus ("Extract Method"). Eine Funktion, die vorher 300 Zeilen hatte, liest sich danach wie eine Inhaltsangabe aus zehn Methodenaufrufen.
Jeder dieser Schritte ist einzeln committbar und einzeln überprüfbar. Genau das macht ihn im Team verantwortbar.
Wo fangen Sie an, wenn alles unlesbar ist?
Fangen Sie nicht dort an, wo der Code am schlimmsten ist, sondern dort, wo Sie ihn ohnehin gerade ändern müssen. Das nennt sich Boy-Scout-Regel: Sie hinterlassen jede Datei ein kleines Stück sauberer, als Sie sie vorgefunden haben.
Der Grund ist wirtschaftlich. Code, den seit drei Jahren niemand anfasst, muss auch nicht lesbar sein — er läuft. Ihre Zeit ist am besten investiert in den Dateien, die Sie und Ihr Team ständig öffnen. Ein Blick in die Git-Historie zeigt Ihnen diese Hotspots: Dateien mit vielen Commits und vielen beteiligten Autoren sind fast immer die, die schmerzen.
Ein Beispiel aus der Praxis. Ein häufiges Muster in älteren Symfony- oder Laravel-Anwendungen ist der aufgeblähte Controller, der alles selbst macht:
Ein Controller nimmt den Request entgegen, validiert ihn von Hand, baut eine SQL-Abfrage per String-Konkatenation, formatiert das Ergebnis und rendert das Template — alles in einer Action mit 250 Zeilen.
Sie müssen das nicht in einem Rutsch auflösen. Ziehen Sie zuerst nur die Datenbankabfrage in eine Repository-Klasse. Im nächsten Schritt die Validierung in ein Form-Objekt oder eine Request-Klasse. Der Controller schrumpft mit jedem Schritt, und jeder Schritt ist für sich harmlos.
Lesbarkeit und Sicherheit gehören zusammen
Wenn Sie Legacy-Code lesbar machen, stoßen Sie zwangsläufig auf Sicherheitslücken — und lesbarer Code macht diese Lücken überhaupt erst sichtbar. Die per String zusammengebaute SQL-Abfrage von eben ist nicht nur schwer zu lesen, sie ist eine klassische SQL-Injection.
Nutzen Sie das Aufräumen, um solche Stellen zu entschärfen, sobald Sie sie sehen:
- Ersetzen Sie String-SQL durch Prepared Statements beziehungsweise den Query Builder Ihres Frameworks.
- Ersetzen Sie ungeprüfte Ausgaben durch Escaping — in Twig-Templates ist das Standard, in altem PHP-HTML-Mischcode oft nicht.
- Ziehen Sie Zugangsdaten aus dem Code in Umgebungsvariablen.
Behandeln Sie diese Funde konsequent als eigene Commits, getrennt vom reinen Umbenennen. So bleibt die Historie ehrlich und nachvollziehbar.
Woran erkennen Sie, dass sich die Arbeit gelohnt hat?
Der beste Indikator ist banal: Ein neuer Entwickler kann eine Funktion öffnen und in wenigen Minuten erklären, was sie tut, ohne zehn andere Dateien aufzumachen. Messbar wird das über sinkende Komplexität — Werkzeuge wie PHPStan oder Psalm auf steigender Level-Stufe und die zyklomatische Komplexität pro Methode geben Ihnen dafür Zahlen.
Setzen Sie diese Werkzeuge früh in die CI-Pipeline. Wenn die Prüfstufe einmal erreicht ist, sorgt die Pipeline dafür, dass der Code nicht wieder unlesbar wird. Lesbarkeit ist kein einmaliges Projekt, sondern eine Eigenschaft, die man verteidigen muss.
Der ehrliche Praxis-Tipp zum Schluss
Der größte Fehler ist, aus dem Aufräumen ein monatelanges Großprojekt zu machen, das keinen sichtbaren Nutzen liefert und irgendwann abgebrochen wird. Machen Sie es umgekehrt: Koppeln Sie das Lesbarmachen immer an eine ohnehin anstehende Aufgabe. Sie fixen einen Bug oder bauen ein Feature und räumen genau die Dateien auf, die Sie dafür anfassen. So finanziert sich die Modernisierung selbst und liefert bei jedem Schritt einen greifbaren Gegenwert.
Wenn Sie vor einer PHP-Anwendung stehen, bei der niemand mehr weiß, wo man anfangen soll, ist genau das der Punkt, an dem ich mit LegacyWerk gemeinsam mit Ihrem Team die ersten lesbaren Schritte gehe.