Claude Code Refactoring: Legacy-Code modernisieren mit KI
Legacy-Code ist kein Unfall — er ist das Ergebnis von Entscheidungen unter Zeitdruck. Eine Funktion, die damals noch überschaubar war, hat über die Jahre dreißig Parameter bekommen. Ein Variablenname wie data2 war vor drei Jahren noch verständlich, weil man den Kontext im Kopf hatte. Und Testabdeckung hat gefehlt, weil das Feature schnell raus musste.
Das Problem: Wer solchen Code anfassen will, braucht erst Stunden, um ihn zu verstehen — bevor er überhaupt mit dem eigentlichen Refactoring beginnen kann. Genau hier greift Claude Code Refactoring an: nicht als Zauberstab, der Code von alleine schön macht, sondern als Partner der den Kontext versteht, Muster erkennt und konkrete Vorschläge macht.
Claude Code Mastery — Refactoring, Agents, Hooks auf Deutsch
Nicht nur Refactoring: der Kurs zeigt, wie du Claude Code wirklich produktiv einsetzt — für Codequalität, autonome Agents und professionelle Workflows. Einmalig bezahlt, kein Abo.
Zum Kurs — Jetzt starten → Einmalzahlung · Kein Abo · 14 Tage Rückgaberecht1. Warum Refactoring mit Claude Code anders ist
Beim klassischen Refactoring ist das größte Hindernis nicht das Schreiben des neuen Codes — es ist das Verstehen des alten. Was macht diese Funktion wirklich? Wo wird sie aufgerufen? Welche Seiteneffekte hat eine Umbenennung? Wer hat das geschrieben und warum?
Claude Code liest den gesamten Kontext auf einmal: die Funktion selbst, ihre Aufrufer, verwandte Typen, Tests, Konfigurationsdateien. Es versteht nicht nur die Syntax, sondern erkennt Muster — welche Teile einer langen Funktion zusammengehören, welche Namen irreführend sind, wo ein Design-Pattern passen würde.
Das bedeutet: Du musst nicht mehr stundenlang lesen, bevor du anfängst. Du beschreibst, was dich stört, und Claude Code gibt dir eine Analyse mit konkreten Schritten. Dann entscheidest du, was du umsetzt.
Wichtig: Claude Code schreibt keinen Code ohne dein Zutun um. Es schlägt vor, erklärt und wartet auf deine Entscheidung. Das Refactoring bleibt unter deiner Kontrolle — Claude Code beschleunigt die Analyse und den Entwurf, nicht die Entscheidung.
2. Beispiel 1: Große Funktion aufteilen
Das häufigste Legacy-Problem: eine Funktion, die über die Jahre gewachsen ist und heute 150 Zeilen hat. Sie macht Validierung, Datenbankzugriff, Businesslogik und Formatierung — alles in einem Block.
// Typischer Legacy-Code: eine Funktion macht alles
function processOrder(orderId, userId, items, coupon, shippingAddress) {
// 1. Validierung
if (!orderId || !userId) throw new Error('Missing IDs');
if (!items || items.length === 0) throw new Error('No items');
let discount = 0;
if (coupon) {
const couponData = db.query('SELECT * FROM coupons WHERE code = ?', [coupon]);
if (!couponData || couponData.expired) throw new Error('Invalid coupon');
discount = couponData.discount_percent / 100;
}
// 2. Preisberechnung (weitere 40 Zeilen)
// 3. Datenbankoperationen (weitere 30 Zeilen)
// 4. E-Mail versenden (weitere 20 Zeilen)
// 5. Logging (weitere 10 Zeilen)
}
Der Prompt an Claude Code:
claude "Analysiere processOrder() in src/orders/processor.ts.
Schlage vor, wie ich sie in kleinere, testbare Funktionen aufteilen kann.
Zeige die neuen Funktionssignaturen und erkläre die Aufteilung."
Claude Code liest die Funktion, erkennt die logischen Abschnitte und schlägt eine Aufteilung vor: validateOrder(), applyCoupon(), calculateTotal(), persistOrder(), notifyCustomer(). Für jede Teilfunktion zeigt es die Signatur und erklärt, welche Verantwortlichkeit sie übernimmt. Du siehst sofort: jede dieser neuen Funktionen ist einzeln testbar, hat eine klare Aufgabe, und die Orchestrierung in processOrder() wird zur übersichtlichen Abfolge von fünf Aufrufen.
3. Beispiel 2: Variablennamen verbessern
Schlechte Variablennamen sind subtiler als lange Funktionen — aber oft genauso teuer. data, result, temp, x, flag: jeder dieser Namen erzwingt mentalen Overhead, weil man immer erst zurückspringen muss, um zu verstehen, was die Variable enthält.
// Vor dem Refactoring: undeutliche Namen
async function calc(u, p, d) {
const res = await db.find(u);
const x = res.credits * p;
const flag = x > d;
const tmp = flag ? x - d : x;
return { val: tmp, ok: flag };
}
Der Prompt:
claude "Benenne alle Variablen und Parameter in calc() in src/billing/calculator.ts
so um, dass der Code selbstdokumentierend wird. Zeige vorher/nachher
und erkläre jeden neuen Namen."
Das Ergebnis von Claude Code:
// Nach dem Refactoring: selbstdokumentierender Code
async function calculateUserBilling(userId, pricePerUnit, creditLimit) {
const userAccount = await db.find(userId);
const totalCost = userAccount.credits * pricePerUnit;
const exceedsLimit = totalCost > creditLimit;
const billableAmount = exceedsLimit ? totalCost - creditLimit : totalCost;
return { amount: billableAmount, limitExceeded: exceedsLimit };
}
Derselbe Code — aber jetzt versteht jeder auf den ersten Blick, was er tut. Claude Code schlägt nicht nur bessere Namen vor, sondern erklärt auch, warum: flag ist kein guter Name, weil er nichts über den semantischen Inhalt sagt; exceedsLimit hingegen ist selbstdokumentierend.
4. Beispiel 3: If-Spaghetti in Strategy-Pattern umwandeln
Verschachtelte If-Ketten für unterschiedliche Verarbeitungspfade sind ein Klassiker im Legacy-Code. Jedes Mal wenn ein neuer Typ hinzukam, wurde ein weiterer else if-Zweig angehängt. Das Ergebnis ist Code, der schwer zu lesen, fast unmöglich zu testen und gefährlich zu ändern ist.
// If-Spaghetti: schwer zu testen, schwer zu erweitern
function processPayment(type, amount, data) {
if (type === 'credit_card') {
// 25 Zeilen Credit-Card-Logik
if (data.threeDsRequired) {
// weitere Verschachtelung
}
} else if (type === 'paypal') {
// 20 Zeilen PayPal-Logik
} else if (type === 'sepa') {
// 30 Zeilen SEPA-Logik
if (amount > 10000) {
// Sonderfall für große Beträge
}
} else if (type === 'crypto') {
// 15 Zeilen Crypto-Logik
} else {
throw new Error('Unknown payment type');
}
}
Der Prompt:
claude "Die processPayment()-Funktion in src/payments/processor.ts
hat tiefe If-Verschachtelung für verschiedene Zahlungsarten.
Schlage vor, wie ich das in ein Strategy-Pattern umwandeln kann,
das einfach erweiterbar ist und jeden Typ isoliert testbar macht."
Claude Code zeigt das Strategy-Pattern: ein PaymentProcessor-Interface mit einer process(amount, data)-Methode, separate Klassen für CreditCardProcessor, PayPalProcessor, SepaProcessor und CryptoProcessor, und eine PaymentProcessorFactory die den richtigen Processor zurückgibt. Die Hauptfunktion wird zu zwei Zeilen: Factory aufrufen, Processor aufrufen. Jede Zahlungsart ist jetzt isoliert, einzeln testbar — und einen neuen Typ hinzuzufügen bedeutet eine neue Klasse, nicht eine weitere else if-Zeile in einer bereits unübersichtlichen Funktion.
Hinweis: Strategy-Pattern erhöht die Dateizahl. Das ist ein bewusster Trade-off: mehr Dateien, aber jede mit einer klaren, einzelnen Verantwortlichkeit. Frage Claude Code explizit nach den Trade-offs, wenn du unsicher bist, ob das Pattern für deinen Kontext passt.
5. Beispiel 4: Fehlende Tests ergänzen
Refactoring ohne Tests ist Blindflug. Du veränderst Verhalten, ohne zu wissen, ob du dabei etwas kaputt gemacht hast. Das Ergänzen von Tests ist deshalb kein optionaler Schritt nach dem Refactoring — es ist Voraussetzung dafür.
Claude Code kann Tests für bestehenden Code schreiben — und das ist eine seiner stärksten Anwendungen beim Refactoring:
claude "Schreibe Jest-Tests für validateOrder() in src/orders/validator.ts.
Decke ab: gültige Bestellung, fehlende Pflichtfelder, ungültige Mengen,
leere Artikel-Liste, und den Grenzfall Menge = 0.
Nutze die bestehenden Test-Patterns aus src/__tests__/."
Claude Code liest validateOrder(), analysiert alle Code-Pfade (normale Ausführung, jeden throw-Zweig, jeden if-Zweig) und schreibt Tests die jeden Pfad abdecken. Es liest auch deine bestehenden Tests, um den Stil zu übernehmen: gleiche describe-Struktur, gleiche Assertion-Patterns, gleiche Mocking-Strategie.
Das Ergebnis: du hast eine Testsuite für die Funktion, bevor du sie anfasst. Wenn nach dem Refactoring ein Test rot wird, weißt du sofort, welches Verhalten sich unbeabsichtigt geändert hat.
// Generierte Tests (Auszug)
describe('validateOrder', () => {
it('akzeptiert eine gültige Bestellung', () => {
const order = { id: '123', userId: 'u1', items: [{ sku: 'A', qty: 2 }] };
expect(() => validateOrder(order)).not.toThrow();
});
it('wirft bei fehlender orderId', () => {
const order = { userId: 'u1', items: [{ sku: 'A', qty: 1 }] };
expect(() => validateOrder(order)).toThrow('Missing order ID');
});
it('wirft bei leerer Artikel-Liste', () => {
const order = { id: '123', userId: 'u1', items: [] };
expect(() => validateOrder(order)).toThrow('No items');
});
it('wirft bei Menge 0', () => {
const order = { id: '123', userId: 'u1', items: [{ sku: 'A', qty: 0 }] };
expect(() => validateOrder(order)).toThrow('Invalid quantity');
});
});
6. Tech-Debt systematisch abbauen
Einzelne Funktionen zu refactoren ist eine Sache. Tech-Debt systematisch abzubauen ist eine andere — denn dafür muss man erst wissen, wo der Tech-Debt tatsächlich liegt.
Claude Code kann eine Codebase analysieren und nach Mustern suchen, die auf Tech-Debt hinweisen:
claude "Scanne src/ und liste die fünf Dateien mit dem höchsten
wahrgenommenen Tech-Debt. Kriterien: Funktionslänge über 80 Zeilen,
Verschachtelungstiefe über 4, duplizierter Code, fehlende Typisierung.
Priorisiere nach Aufwand vs. Impact."
Das Ergebnis ist keine vollständige statische Analyse — dafür gibt es spezialisierte Tools. Aber es ist ein priorisierter Einstiegspunkt: welche Dateien lohnt es sich anzufassen, in welcher Reihenfolge, und warum. Claude Code erklärt jeden Befund mit konkretem Beispiel aus der Datei — nicht nur "Datei hat hohe Komplexität", sondern "Zeile 145–190: verschachtelte Fallunterscheidung die sich mit ähnlicher Logik in utils/pricing.ts überschneidet".
Zwei ergänzende Artikel die den Kontext vertiefen:
- Claude Code Debugging — wie du Bugs systematisch findest, bevor du Code veränderst
- Claude Code Git-Workflow — wie du Refactoring-Commits sauber strukturierst und reviewst
7. Refactoring-Workflow: Schritt für Schritt
Aus der Praxis hat sich ein klarer Ablauf bewährt, der das Risiko minimiert und den Fortschritt messbar macht:
- Tests zuerst schreiben — bevor du eine Zeile Code änderst. Claude Code hilft dir, Tests für den bestehenden Code zu generieren.
- Analyse anfordern — Claude Code liest die Datei und erklärt, was es sieht: Verantwortlichkeiten, Probleme, Verbesserungspotenzial.
- Einen Schritt auf einmal — nicht alles auf einmal refactoren. Funktion aufteilen, grün testen, committen. Dann nächster Schritt.
- Nach jedem Schritt testen — nicht erst am Ende. Ein roter Test nach einem kleinen Schritt ist leicht zu lokalisieren; nach zehn Schritten nicht mehr.
- Namen zuletzt — Umbenennungen sind einfach, aber weitreichend. Erst die Struktur verbessern, dann die Benennung.
Pragmatischer Einstieg: Wenn die Codebase groß ist und du nicht weißt, wo du anfangen sollst: fang mit der Funktion an, die du am häufigsten ändern musst. Die Teile mit dem höchsten Change-Rate profitieren am meisten von Refactoring — weil du dort am häufigsten zurückkehrst.
8. Was Claude Code nicht kann — und warum das wichtig ist
Claude Code Refactoring hat Grenzen, die man kennen sollte. Es versteht keinen impliziten Businesskontext, den du nicht erklärt hast. Wenn ein seltsamer Sonderfall in der Funktion steht und kein Kommentar erklärt warum — weiß Claude Code nicht, ob das ein Bug ist oder eine bewusste Entscheidung für einen Kundenspezialfall aus 2019.
Die Konsequenz: Erkläre den Kontext, wenn er nicht aus dem Code hervorgeht. "Diese Funktion hat diesen Sonderfall wegen Anforderung X" — dann kann Claude Code entscheiden, ob der Sonderfall beim Refactoring erhalten bleiben muss.
Außerdem: Claude Code schreibt keine Tests, die nicht durch den Code-Pfad motiviert sind. Wenn du Grenzfälle weißt, die aus dem Code nicht sichtbar sind (Kundendaten mit bestimmten Encoding-Problemen, Zeitzonenfehler die nur in Produktion auftreten), musst du sie nennen. Claude Code kann dann Tests dafür schreiben — aber es kann sie nicht aus dem Nichts erfinden.
Claude Code Mastery — von Refactoring bis zum produktiven Agenten
Refactoring ist eine Stärke von Claude Code — aber nicht die einzige. Im Kurs lernst du Agents, MCP-Server, Hooks, Multi-Agent-Workflows und mehr. Vollständig auf Deutsch, einmalig bezahlt.
Jetzt starten → Einmalzahlung · Kein Abo · 14 Tage RückgaberechtKurs · Claude Code Mastery
Von Refactoring zum produktiven AI-Agenten
Refactoring. Debugging. Agents. MCP. Hooks. Alles auf Deutsch, einmalig bezahlt — kein Abo, keine Plattformabhängigkeit.
Einmalzahlung · Kein Abo · 14 Tage Rückgaberecht