Warum pauschale Refactoring-Aufträge an KI gefährlich sind
Wer Cursor, Claude Code oder ChatGPT einfach auffordert, Code aufzuräumen, erhält oft eine kaum überprüfbare Neuschreibung, die Struktur und Verhaltensänderungen vermischt. Ein sicherer Refactoring-Loop mit klaren Schritten verhindert solche stillschweigenden Änderungen.

Wenn man Cursor, Claude Code oder ChatGPT bittet, etwas „aufzuräumen“ oder zu „refaktorieren“, bekommt man meistens irgendetwas: neue Ordner, umbenannte Symbole, ein modisches Muster, vielleicht ein Dependency-Upgrade. Manchmal ist das sogar eine Verbesserung.
Oft ist es eine nicht mehr reviewbare Neufassung. Der Diff vermischt Struktur mit stillen Verhaltensänderungen. Die Tests sind grün, weil sie nun die neue Welt behaupten, nicht weil das Verhalten von gestern abgesichert wurde. Reviewer segnen die Stimmung ab und übersehen die Logikänderung im Rauschen.
KI ist nicht schlecht im Refactoring. „Räum das auf“ überspringt einfach jeden Schritt, der eine strukturelle Änderung sicher macht, und verlangt eine fertige Architektur auf einen Schlag. Hier ist eine Schleife, die ich stattdessen verwende, und zwei vollständige Prompts, die man heute direkt einfügen kann.
map → safety net → small slice → prove → describe Enter fullscreen mode Exit fullscreen mode Map: konkrete Code-Smells mit Stellenangaben inventarisieren; einen ersten, PR-großen Ausschnitt wählen; festhalten, was außerhalb des Umfangs liegt. Safety net: Characterization-Tests (oder vorhandene Tests), die das heutige Verhalten fixieren, bevor Code verschoben wird. Small slice: eine Extraktion, eine Verantwortungstrennung, eine Umbenennungs-Batch, kein Redesign.
Prove: dieselben Tests sind danach grün; öffentliche Verträge bleiben unverändert, es sei denn, dieser PR ist ausdrücklich eine Migration. Describe: ein PR-Text, der den Verhaltensvertrag, die Lesereihenfolge und das Restrisiko benennt. Wenn man sich nur eine Regel merkt: Lass das Modell keinen Produktionscode bearbeiten, bevor etwas Grünes das Verhalten absichert, das du gerade verschieben willst.
Füge das ein, wenn du auf ein chaotisches Modul starrst und in Versuchung bist, „schreib es neu“ zu sagen.
You are a senior engineer planning a safe refactor. Do not change any code yet. ## Context - Paths in scope: {{TARGET_PATHS}} - Goal (one sentence): {{GOALS}} - Hard constraints (API freeze, no new deps, deadline): {{CONSTRAINTS}} - Time / PR budget for the first pass: {{TIME_BUDGET}} - What I know about tests here: {{TEST_COVERAGE_NOTES}} ## Process 1. Inventory concrete smells with file:line or a short quote.
Decke verschiedene Kategorien ab (lange Funktion, Duplikation, vermischte Verantwortlichkeiten, toter Code, leckende Abstraktion, versteckte Seiteneffekte). Maximal 12. 2.
Bewerte jeden: Nutzen (H/M/L), Risiko (H/M/L), Testsicherheit (none/thin/adequate), Umfang (S/M/L). 3. Ordne nach (Nutzen ÷ Risiko), dann nach Größe.
Bevorzuge zuerst hohen Nutzen / niedriges Risiko / S. 4. Schlage GENAU einen ersten Ausschnitt vor: Done-When-Kriterium, enthaltene Smells, erforderliches Sicherheitsnetz vor Änderungen, explizit außerhalb des Umfangs, vorgeschlagener PR-Titel.
5. Stopp. Keine Änderungen.
Kein Neufassungsvorschlag. ## Output ### Smell inventory (table) ### Ranking ### First slice ### Open questions (max 5) ## Rules - Every smell needs a location. "This is messy" is not a smell. - Do not invent coverage % or hours saved. Unknown → say unknown, raise risk. - Prefer surgery over rewrite.
Enter fullscreen mode Exit fullscreen mode Zwei Details sind entscheidend. Stellenangaben verhindern Stimmungs-basiertes Aufräumen. Die Abgrenzung des Umfangs im ersten Ausschnitt hindert das Modell daran, im selben Atemzug wie die Planung das ganze Ozeanschiff umzubauen.
Sobald du einen Ausschnitt gewählt hast, fixiere das Verhalten, bevor du Code verschiebst:
You are building a characterization safety net before a refactor. Do not change production code. ## Context - Code under edit: {{TARGET_CODE}} - Behaviours that must stay the same: {{PUBLIC_BEHAVIOURS}} - Known quirks / edge cases: {{KNOWN_EDGE_CASES}} - Existing tests: {{EXISTING_TESTS}} - Test command: {{TEST_COMMAND}} ## Process 1. List observable contracts (returns, errors, side effects, ordering).
Markiere jeden als MUST-PRESERVE oder ALLOWED-TO-IMPROVE. 2. Führe eine Lückenanalyse gegen die vorhandenen Tests durch.
3. Ergänze die kleinstmöglichen Tests, die das aktuelle Verhalten fixieren, einschließlich der Eigenheiten. Wenn etwas wie ein Bug aussieht, characterisiere es trotzdem und markiere den Test mit CHARACTERIZATION.
Korrigiere es in diesem Schritt nicht. 4. Führe {{TEST_COMMAND}} auf dem AKTUELLEN Code aus.
Alle neuen Tests müssen bestehen, bevor irgendeine strukturelle Änderung erfolgt. ## Rules - No production edits. - Do not weaken or delete existing assertions. - Prefer outputs/side effects over mock call-order tests. - If you can't run tests here, label them UNVERIFIED and give exact commands. Enter fullscreen mode Exit fullscreen mode Characterization ist absichtlich langweilig. Genau das ist der Punkt.
Man kauft sich damit eine Fallmine für die Extraktion, die man gleich durchführen will.
Ein nützlicher Interrupt, wenn der Agent anfängt, neu zu gestalten:
Liste jede Dateiänderung auf, die der genehmigte Ausschnitt nicht erfordert. Mache diese rückgängig. Hat sich ein nutzersichtbares Verhalten, ein Wire-Format, ein Fehlercode oder ein Log-Feld geändert? Ja/Nein pro Punkt. Bei Ja: trenne es aus diesem Refactoring-PR heraus. Enter fullscreen mode Exit fullscreen mode Umbenennungen: expand/contract, nicht der große Tag Repo-weite Umbenennungen sind der Bereich, in dem KI am stärksten und zugleich am gefährlichsten ist. Ein einzelnes Replace-all fühlt sich produktiv an und erzeugt einen Diff, den niemand reviewen kann, und dabei übersieht sie die dynamische Aufrufstelle in einem anderen Paket, den Config-Key oder den alten Mobile-Client.
Lass das Modell zuerst eine Inventartabelle erstellen (Definition / intern / öffentlich / Tests / Config / generiert) und führe dann in dieser Sitzung nur Schritt eins aus. Füge die verbleibenden Zählwerte in die nächste Sitzung ein. Diese Übergabe schlägt einen Mega-Chat, der es „einfach zu Ende bringt.“
Fiktiv und vereinfacht, keine echten Kennzahlen.
Du hast einen 1.200 Zeilen langen PricingService, der Listenpreis, Rabatte, Steuer, FX und Rechnungsformatierung vermischt. Randbedingung: price(cart) bleibt für eine Release-Version erhalten.
Nichts Magisches ist passiert. Die Prompts hielten die erste Änderung klein genug, dass ein Mensch den Merge noch überblicken konnte.
Verzichte auf KI-geführtes Aufräumen, wenn du das Ziel nicht in einem Satz formulieren kannst, wenn keine Zeit für ein Sicherheitsnetz bleibt, während eines Freezes oder Vorfalls, oder wenn das eigentliche Bedürfnis ein Bugfix ist, der sich als „Refactoring“ einschmuggelt. Bricht die Sitzung ab, wenn der Diff über den Ausschnitt hinauswächst, wenn Tests durch Löschen von Assertions „grün“ werden, oder wenn du die Änderung selbst nicht erklären könntest.
Lege die Arbeit außerdem beiseite, wenn du das Modul nicht besitzt und keinen Reviewer findest, der es tut, oder wenn der erste Vorschlag des Modells eine Komplettneufassung ist. Kehre zur Smell-Map zurück und wähle stattdessen eine Blatt-Extraktion.
Probier es an einem Aufräumen aus, das du bereits abgeschlossen hast: Gib dem Modell nur die ursprünglichen chaotischen Dateien und die Randbedingungen, führe den Smell-Map-Prompt aus und prüfe, ob der erste Ausschnitt etwas ist, dem du immer noch zustimmen würdest, mit einem vor den Änderungen genannten Sicherheitsnetz.
Ich habe die acht Refactoring-Prompts, die ich verwende (Smell Map, Characterization Net, Extract, God-Class Split, Rename/Migration, Dead-Code Cleanup, Strangler Fig, PR Guide), zusammen mit zwei Checklisten, einer Cursor-Regel und einem PDF-Leitfaden als AI Refactoring Prompt Pack gepackt: https://lirenplr.gumroad.com/l/ypcsuc. Alles oben genannte funktioniert auch ohne dieses Paket.
Automatisch übersetzt. Das Original auf Englisch ist unten aufklappbar.
Original (Englisch) anzeigen
Ask Cursor, Claude Code or ChatGPT to “clean this up” or “refactor this,” and you’ll usually get something: new folders, renamed symbols, a fashionable pattern, maybe a dependency bump. Sometimes it’s even an improvement.
Often it’s an unreviewable rewrite. The diff mixes structure with silent behaviour changes. Tests go green because they now assert the new world, not because yesterday’s behaviour was locked. Reviewers approve the vibe and miss the logic edit in the noise.
AI isn’t bad at refactoring. “Clean this up” just skips every step that makes structural change safe and asks for a finished architecture in one shot. Here’s a loop I use instead — and two full prompts you can paste today.
map → safety net → small slice → prove → describe Enter fullscreen mode Exit fullscreen mode Map — inventory concrete smells with locations; pick one PR-sized first slice; write what’s out of scope. Safety net — characterization (or existing) tests that pin today’s behaviour before you move code. Small slice — one extract, one responsibility split, one rename batch — not a redesign. Prove — same tests green after; public contracts unchanged unless this PR is explicitly a migration. Describe — PR text that states the behaviour contract, reading order, and residual risk. If you only remember one rule: don’t let the model edit production code until something green locks the behaviour you’re about to move.
Paste this when you’re staring at a messy module and tempted to say “rewrite it.”
You are a senior engineer planning a safe refactor. Do not change any code yet. ## Context - Paths in scope: {{TARGET_PATHS}} - Goal (one sentence): {{GOALS}} - Hard constraints (API freeze, no new deps, deadline): {{CONSTRAINTS}} - Time / PR budget for the first pass: {{TIME_BUDGET}} - What I know about tests here: {{TEST_COVERAGE_NOTES}} ## Process 1. Inventory concrete smells with file:line or a short quote.
Cover different categories (long function, duplication, mixed responsibilities, dead code, leaky abstraction, hidden side effects). Cap at 12. 2.
Score each: payoff (H/M/L), risk (H/M/L), test safety (none/thin/adequate), size (S/M/L). 3. Rank by (payoff ÷ risk), then size.
Prefer high-payoff / low-risk / S first. 4. Propose ONE first slice: done-when, smells included, safety net required before edits, explicit out-of-scope, suggested PR title.
5. Stop. No edits.
No rewrite proposal. ## Output ### Smell inventory (table) ### Ranking ### First slice ### Open questions (max 5) ## Rules - Every smell needs a location. "This is messy" is not a smell. - Do not invent coverage % or hours saved. Unknown → say unknown, raise risk. - Prefer surgery over rewrite.
Enter fullscreen mode Exit fullscreen mode Two details matter. Locations stop vibes-based cleanup. Out of scope on the first slice stops the model from boiling the ocean in the same breath as the plan.
Once you’ve picked a slice, pin behaviour before moving code:
You are building a characterization safety net before a refactor. Do not change production code. ## Context - Code under edit: {{TARGET_CODE}} - Behaviours that must stay the same: {{PUBLIC_BEHAVIOURS}} - Known quirks / edge cases: {{KNOWN_EDGE_CASES}} - Existing tests: {{EXISTING_TESTS}} - Test command: {{TEST_COMMAND}} ## Process 1. List observable contracts (returns, errors, side effects, ordering).
Mark each MUST-PRESERVE or ALLOWED-TO-IMPROVE. 2. Gap-analyze against existing tests.
3. Add the smallest tests that pin current behaviour — including quirks. If something looks like a bug, still characterize it and label the test CHARACTERIZATION.
Do not "fix" it in this step. 4. Run {{TEST_COMMAND}} on the CURRENT code.
All new tests must pass before any structural edit. ## Rules - No production edits. - Do not weaken or delete existing assertions. - Prefer outputs/side effects over mock call-order tests. - If you can't run tests here, label them UNVERIFIED and give exact commands. Enter fullscreen mode Exit fullscreen mode Characterization is deliberately boring. That’s the point.
You’re buying a tripwire for the extract you’re about to do.
A useful interrupt when the agent starts redesigning:
List every file change not required by the approved slice. Revert those. Did any user-visible behaviour, wire format, error code or log field change? Yes/No per item. If Yes, split it out of this refactor PR. Enter fullscreen mode Exit fullscreen mode Renames: expand/contract, not flag day Repo-wide renames are where AI is both strongest and most dangerous. A single replace-all feels productive and produces a diff nobody can review — and it misses the dynamic call site in another package, the config key, or the old mobile client.
Ask the model for an inventory table first (definition / internal / public / tests / config / generated), then execute step one only in that session. Paste remaining counts into the next session. That handoff beats one mega-chat that “just finishes it.”
Fictional and simplified — no real metrics.
You have a 1,200-line PricingService that mixes list price, discounts, tax, FX and invoice formatting. Constraint: keep price(cart) for one release.
Nothing magical happened. The prompts kept the first change small enough that a human could still own the merge.
Skip AI-led cleanup when you can’t state the goal in one sentence, when there’s no time for a safety net, during a freeze/incident, or when the real need is a bug fix smuggled as “refactor.” Stop mid-session when the diff grows past the slice, when tests are “fixed” by deleting assertions, or when you couldn’t explain the change yourself.
Also park the work when you don’t own the module and can’t get a reviewer who does, or when the model’s first suggestion is a rewrite. Return to the smell map and pick a leaf extraction instead.
Try it on a cleanup you already finished: give the model only the original messy files and constraints, run the smell-map prompt, and see whether the first slice is something you’d still approve — with a safety net called out before edits.
I packaged the eight refactoring prompts I use (smell map, characterization net, extract, god-class split, rename/migration, dead-code cleanup, strangler-fig, PR guide) plus two checklists, a Cursor rule and a PDF guide, as the **AI Refactoring Prompt Pack: https://lirenplr.gumroad.com/l/ypcsuc. Everything above works without it.