Begriff
Refactoring
Warum wichtig?
Dieser Begriff ist ein Knoten im SengakujiWorks-Wissensnetz. Nutze Level 0 für die erste Einordnung, Level 1 für Praxis, Level 2 für technische Struktur und Level 3 für Grenzen, Fallstricke und Expertenkontext.
Stell dir vor, du schreibst einen Aufsatz. Der Inhalt ist fertig. Aber die Sätze sind holprig, Absätze sind zu lang. Du gehst nochmal drüber und formulierst um, damit es sich besser liest. Der Inhalt (Sinn) bleibt gleich. Genau das ist Refactoring beim Programmieren. Du änderst die Struktur des Codes, damit er verständlicher und wartbarer wird. Du änderst nicht das Verhalten (keine neuen Features, keine Bugfixes). Ziel: "Code Rot" (Schulden) abbauen.
Merksatz: Der Prozess der Änderung eines Softwaresystems, der die interne Struktur verbessert, ohne das externe Verhalten zu verändern.
Die Pfadfinder-Regel (Boy Scout Rule): "Verlasse den Campingplatz sauberer, als du ihn vorgefunden hast." Wenn du eine Datei anfasst, um einen Bug zu fixen, räume auch gleich ein bisschen auf (Variablen umbenennen, Funktion aufteilen).
Wann?
- Red: Schreibe einen test, der fehlschlägt.
- Green: Schreibe Code, damit der Test besteht (egal wie hässlich).
- Refactor: Mach den Code schön. (Test muss weiter bestehen!).
1. Code Smells
Woran erkennst du, dass du refactorn musst? Code "stinkt".
- Long Method: Funktion hat 200 Zeilen. -> Extract Method.
- Large Class: Klasse macht 10 Dinge. -> Extract Class.
- Duplicated Code: Copy-Paste. -> Extract Variable/Method.
- Magic Numbers:
if (x > 86400). Was ist 86400? ->const SECONDS_IN_DAY = 86400.
2. Sicherheitsnetz (Unit Tests)
Refactoring ohne Tests ist Harakiri. Woher weißt du, dass du nichts kaputt gemacht hast? Nur wenn du eine grüne Test-Suite hast, traust du dich, große Änderungen zu machen. Ohne Tests hat man Angst ("Never touch a running system") -> Code verrottet (Legacy Code).
3. Strangler Fig Pattern
Wie refactort man einen gigantischen Monolithen (10 Jahre alt)? Nicht neu schreiben (Big Bang Rewrite scheitert immer). Sondern: Neue Features daneben bauen (als Microservice). Den alten Code Stück für Stück ersetzen ("erdrosseln"), bis er stirbt.
1. Cyclomatic Complexity und AST Parsing
Woher weiß man objektiv, dass Refactoring fällig wird, ohne "Bauchgefühl"? Moderne CI-Pipelines messen statisch die zyklomatische Komplexität (McCabe Metric). Sie baut den Code während Build in einen Abstract Syntax Tree (AST) auf. Knoten sind if-else Trees, Loops, Switch-Cases. Jeder logische Entscheidungsweg (Branch) im Funktionsbaum der App inkrementiert den Zähler. Eine Funktion mit Zähler 26 ist nachweislich ein Labyrinth und unmöglich mit Unit Tests voll abzudecken. SonarQube oder ESLint forcieren harte Schwellenwerte. Ab Komplexität > 10 schlägt der CI-Pipeline Job "rot" an und verweigert zwingend den Git-Merge, bis der Entwickler die gigantische Pipeline via "Extract Method Pattern" zwingend refactored und entschachtelt ausgedünnt hat.
2. Die Feature-Flag Refactoring Migration
Gefahr-Sektor: Du willst den Core-Processing-Algorithmus der Rechnungsstellung refactoren. Unit Tests fangen viel, aber nicht reale Edge-Cases von Kunden-Datenbanken (Production Drift). Der Profi-Move ist das parallele Science/Simulation Refactoring via Feature Flags. Im Code laufen für 3 Wochen beide Funktionen parallel: Der alte Legacy-Code rechnet und retourniert gnadenlos das Ergebnis zum Kunden. Aber im Hinterzimmer jagt das Backend exakt dieselben Echtzeit-Requestdaten feuernd in deinen neuen refactormäßigen Code. Die Pipeline vergleicht ("diffed") asynchron beide Return-Werte für Analytics, ohne dass der Kunde das Resultat des neuen Codes sieht. Wenn nach 2 Millionen Rechnungen absolut kein Mismatch der Outputs im Metrik Logging aufploppt, wird das Feature-Flag (Routing Switch) von Alt auf Neu endgültig umgelegt.
3. "Primitive Obsession" Anti-Pattern (DDD)
Ein subtiler Code-Smell, den Tausende Programmierer dulden.
Methoden-Signaturen lauten User(string name, string email, string phone).
Im Code wimmelt es von Validierungs-"Ifs", weil jeder Typ blind als String übergeben wird. Dies führt zu Spaghetti-Code und Validierungs-Streusel (Duplikaten).
Das Domain Driven Design (DDD) Refactoring rät strikt davon ab (Value Objects). "Email" ist kein String! Eine E-Mail hat exakte Semantik (Muss @ enthalten, Maximalzeichen).
Refactoring-Ziel: Wir kreieren dedizierte Klassen/Typen User(Name n, EmailAddress e, PhoneNumber p).
Die Validierungslogik ("Ist E-Mail gültig?") wandert vom Controller hart gekapselt als Konstruktor-Guard in die neue Value-Object-Klasse EmailAddress auf Typebene hinab. Fehler greifen extrem früh am Compile-Zeit Rand. Das Domain Model zentriert sich atomar (Rich Domain).
Quick-Check
Ist Bugfixing Refactoring?
Nein! Bugfix ändert Verhalten (Kaputt -> Ganz). Refactoring ändert Struktur (Hässlich -> Schön). Man macht beides oft zusammen, aber es sind zwei verschiedene Hüte.Kostet es nicht Zeit?
Kurzfristig ja. Langfristig spart es Zeit. In schlechtem Code dauert jedes Feature 3x so lange. Refactoring ist eine Investition in die Geschwindigkeit von morgen.IDE Support?
Jede gute IDE kann Refactoring automatisch ("Extract Variable", "Rename Symbol"). Nutze das! Es ist sicherer als manuelles Tippen.