Code verbessern, ohne zu ändern, was er tut. Die Disziplin, die Codebasen gesund hält.
Refactoring bedeutet, die interne Struktur von Code zu verbessern, ohne sein externes Verhalten zu ändern.
Diese Definition hat zwei entscheidende Teile:
Struktur verbessern: Code verständlicher, änderbar oder erweiterbarer machen. Dazu gehören bessere Namen, kleinere Funktionen, klarere Organisation, weniger Duplikate.
Ohne Verhaltensänderung: Der Code tut genau das, was er vorher getan hat. Eingaben erzeugen dieselben Ausgaben. Seiteneffekte sind identisch. Tests bestehen weiterhin.
Refactoring ist nicht:
Wenn du änderst, was der Code tut, refaktorierst du nicht – du machst etwas anderes. Refactoring betrifft speziell die Struktur, nicht das Verhalten.
Refactoring ist wie deine Küche aufräumen. Das Essen schmeckt gleich. Aber Kochen wird einfacher, schneller und weniger frustrierend.
Martin Fowler dokumentierte Dutzende spezifischer Refactorings, jedes mit:
Hier sind einige, die du ständig verwenden wirst:
Extract Function: Nimm etwas Code und packe ihn in eine neue Funktion mit einem klaren Namen. Das ist wahrscheinlich das häufigste Refactoring.
Rename: Ändere den Namen einer Variable, Funktion oder Klasse, um ihren Zweck besser auszudrücken. Gute Namen sind überraschend wichtig.
Inline Function: Das Gegenteil von Extract – ersetze einen Funktionsaufruf durch seinen Inhalt. Verwende es, wenn eine Funktion keine Klarheit hinzufügt.
Extract Variable: Nimm einen komplexen Ausdruck und gib ihm einen Namen, indem du ihn einer Variable zuweist.
Move Function: Verschiebe eine Funktion zu einer Klasse, wo sie mehr Sinn ergibt.
Replace Conditional with Polymorphism: Ersetze komplexe if/else- oder switch-Anweisungen durch objektorientiertes Dispatch.
Das sind keine "fortgeschrittenen" Refactorings. Es sind alltägliche Werkzeuge. Lerne sie, bis sie automatisch sind.
Refactoring ist nur sicher, wenn du Tests hast. Ohne Tests könnte jede Änderung etwas kaputt machen, und du erfährst es erst in der Produktion.
Der Sicherheitsprozess:
Kleine Schritte sind entscheidend. Versuche nicht, fünf Dinge auf einmal zu refaktorieren. Extrahiere eine Funktion, führe Tests aus, committe. Benenne eine Variable um, führe Tests aus, committe. So weißt du genau, was es verursacht hat, wenn etwas kaputt geht.
Moderne IDEs haben automatisierte Refactorings, die sicherer sind als manuelle Änderungen. "Rename" in deiner IDE aktualisiert alle Referenzen. "Extract Function" erstellt die Funktion und aktualisiert die Aufrufstelle. Nutze diese Werkzeuge.
Die Pfadfinderregel: Hinterlasse den Code besser, als du ihn vorgefunden hast. Wenn du Code aus irgendeinem Grund anfasst, mache eine kleine Verbesserung. Mit der Zeit wird die Codebasis sauberer statt schmutziger.
Keine Tests = Keine Sicherheit
Refactoring ohne Tests ist nur Code ändern und hoffen. Es ist kein Refactoring – es ist Glücksspiel.
Refaktoriere ständig. Refactoring ist keine separate Phase oder Sprint. Es ist kontinuierlich.
Spezifische Auslöser zum Refaktorieren:
Vor dem Hinzufügen eines Features: Wenn die aktuelle Struktur das Feature schwer hinzuzufügen macht, refaktoriere zuerst. Mache die Änderung einfach, dann mache die einfache Änderung.
Nachdem ein Test besteht: Das ist das "Refactor" in Rot-Grün-Refactor. Räume auf, bevor du zum nächsten Test übergehst.
Wenn du einen Code Smell bemerkst: Duplizierter Code, lange Methoden, unklare Namen, komplexe Bedingungen – das sind Signale, dass Refactoring nötig ist.
Während Code Review: Wenn du etwas siehst, das du verbessern würdest, mache es entweder oder notiere es für später.
Wenn du Zeit hast: Habe ein "Refactoring-Backlog" bekannter Probleme. Wenn du Luft hast, nimm etwas von der Liste.
Refaktoriere nicht, wenn:
Technical Debt sind die akkumulierten Kosten von Abkürzungen. Jedes Mal, wenn du sagst "Ich räume das später auf" und es nicht tust, fügst du Schulden hinzu. Jedes Mal, wenn du kopierst und einfügst, statt zu extrahieren, fügst du Schulden hinzu.
Schulden sammeln Zinsen an. Unordentlicher Code braucht länger zum Ändern. Bugs verstecken sich in Komplexität. Neue Teammitglieder haben Schwierigkeiten zu verstehen. Die Kosten für Änderungen steigen.
Refactoring ist, wie du Schulden abbezahlst. Regelmäßiges Refactoring hält Schulden handhabbar. Refactoring zu vernachlässigen lässt Schulden sich aufschaukeln, bis die Codebasis unbrauchbar wird.
Die zentrale Erkenntnis: Refactoring ist kein Luxus. Es ist essentielle Wartung. Du fragst nicht um Erlaubnis, Schulden abzubezahlen – du machst es einfach als Teil deiner Arbeit.
XP baut Refactoring in den Prozess ein. Jedes Feature, jeder Bugfix, jede Aufgabe beinhaltet Zeit, den Code besser zu hinterlassen, als du ihn vorgefunden hast. Du brauchst keinen "Refactoring-Sprint" – du brauchst eine Refactoring-Gewohnheit.
Beim Beheben eines Bugs bemerkst du duplizierten Code in der Nähe. Du behebst zuerst den Bug (Verhaltensänderung), dann extrahierst du die Duplikation in eine Funktion (Refactoring). Zwei Commits: Bugfix, dann Refactoring.
Während du ein Feature hinzufügst, beschließt du auch, das Authentifizierungssystem zu refaktorieren, die Ordnerstruktur neu zu organisieren und das Datenbankschema zu aktualisieren. Du verlierst den Überblick, was sich geändert hat, Tests schlagen mysteriös fehl, und du verbringst Stunden mit Debugging.