Refactorings haben keine Symptome — du siehst nicht, wenn Claude falsch liegt. Drei Leitplanken: Tests, atomare Commits, manueller Klick.
Refactoring ist die Aufgabe, bei der Claude am gefährlichsten ist. Ein Bug hat Symptome — Button reagiert nicht, Wert ist undefined, Stacktrace — also kannst du beurteilen, ob Claudes Fix stimmt. Ein Refactoring hat keine. „Läuft immer noch" kann heißen „Tests sind immer noch grün", während sich das Verhalten still verändert hat, du es nicht bemerkt hast und die Produktion eine Woche später in Flammen steht.
Ich habe kürzlich mit Claude ein ziemlich großes Refactoring in how2claude gemacht: die x402-Krypto-Zahlungen von einem handgeschriebenen PaymentHandler + FacilitatorClient (139 Zeilen) auf das Gem x402-rails migriert, gleichzeitig das Feld-Mapping von Purchase.create! / Subscription.create! — in zwei Controllern dupliziert — in Model-Klassenmethoden extrahiert. Ein Commit, 4 Dateien geändert, 2 gelöscht, 2 hinzugefügt.
Mein Prompt war ein Wort: „refactor."
So kurz war er möglich, weil drumherum Leitplanken standen.
Als der Branch dort ankam, hatte er 221 Tests. Alle kritischen Pfade im Zahlungsfluss waren abgedeckt.
Claudes Default-Aktion vor einem Refactoring ist nicht „schau zuerst in die Tests." Also sagte ich ihm, er solle zuerst bin/rails test ausführen, Grün bestätigen, und danach etwas anfassen.
Nach dem Refactoring erneut laufen lassen. Immer noch grün. Das bedeutet nicht „keine Regression" — es bedeutet, bekanntes Verhalten ist nicht kaputt.
Wenn dein Codepfad keine Testabdeckung hat, lass Claude einen minimalen Test schreiben, der das aktuelle Verhalten festzurrt. Lauf lassen, commiten. Dann refactoren. Sonst ist das, was er macht, kein Refactoring, sondern Rewrite — und du hast keine Möglichkeit, Äquivalenz zu prüfen.
Dieses Refactoring waren eigentlich zwei Dinge:
Purchase / Subscription: Controller → Model-KlassenmethodenIm Frontend gab es ein drittes: den JS-seitigen Signing-Flow mit viem + x402-fetch neu schreiben.
Ich ließ Claude nach natürlichen Grenzen aufteilen: Backend + Model-Extraktion in einem Commit (9f3e239), Frontend in einem separaten (93746d8). Jeder Commit trägt eine vollständige Beschreibung, die Dateiliste und die Begründung der Änderung.
Vorteile:
- Diffs bleiben lesbar. Ein Commit, eine Sache.
- Rollback-Granularität. Wenn die Produktion einen Frontend-Bug hat, rollt git revert 93746d8 nur das Frontend zurück, das Backend bleibt.
- Claudes eigene Aufmerksamkeit bleibt fokussiert. Ein Commit, eine Sache — und seine Aufmerksamkeit deckt nur diese eine Sache ab.
Wenn das Refactoring fertig ist, lasse ich Claude stoppen und mir git diff --staged zeigen. Keine Tests laufen lassen, die App nicht starten, erst den Diff lesen.
Signale, die ich scanne:
app/services/x402/payment_handler.rb komplett gelöscht — gut, das ist der Sinn der Gem-Migration. Aber wenn er etwas löscht, was ich nicht angefasst haben wollte, halte ich an und frage nach.Purchase.create!(wallet_address: verify_result["payer"], ...) → Purchase.record_x402!(payment:, settlement:) liest jetzt payment[:payer]. Die Quelle hat sich geändert (request.env des Gems vs. Rückgabewert des alten Clients), aber die Felder müssen eins-zu-eins zusammenpassen.Falle 1: Die Stimulus-Controller des Gems wurden still nicht geladen
Das Gem x402-rails bringt eigene Stimulus-Controller mit. Claude schrieb den Code, die Tests liefen grün. Ich klickte manuell auf den Bezahl-Button — nichts.
Grund: In config/importmap.rb zeigte der Pin für @hotwired/stimulus auf eine nicht existierende Vendor-Datei, und importmap verwarf den Pin still. Die Controller des Gems wurden nie geladen. Tests können das nicht fangen, weil bin/rails test kein JS ausführt.
Falle 2: YAML parste 0x... als Integer
wallet_address: 0x833589... — keine Anführungszeichen. YAML sah das Präfix 0x, las es als hexadezimalen Integer. Der Facilitator bekam einen Nicht-String und lehnte ab. Claude hielt beim Schreiben der Config nicht inne, um über YAML-Parsing-Regeln nachzudenken.
Beide Fallen wurden erwischt, weil ich den echten Button geklickt habe. Grüne Tests sind nicht dasselbe wie eine funktionierende Feature. Manuelle Verifikation nach einem Refactoring ist nicht optional.
Refactoring ist das „Claude fahren lassen"-Szenario mit dem höchsten Risiko. Die Leitplanken sind nicht für Claude. Sie sind für dich — damit du, wenn Claude etwas falsch macht, es in 5 Minuten bemerkst, statt erst im Produktionsbrand.