Refaktoring nie ma objawów — błędów Claude'a nie widać. Trzy barierki: testy, atomowe commity, ręczne klikanie.
Refaktoring to zadanie, w którym Claude jest najbardziej niebezpieczny. Bug ma objawy — przycisk nie reaguje, wartość undefined, stack trace — więc możesz powiedzieć, czy fix Claude'a zadziałał. Refaktoring nie ma. „Wciąż działa" może oznaczać „testy wciąż przechodzą", gdy tymczasem zachowanie cicho się zmieniło, nie zauważyłeś, a tydzień później produkcja płonie.
Zrobiłem niedawno z Claude'em dość duży refaktoring w how2claude: przeniosłem płatności krypto x402 z ręcznie napisanych PaymentHandler + FacilitatorClient (139 linii) na gem x402-rails, a jednocześnie wyciągnąłem mapowanie pól Purchase.create! / Subscription.create! — zduplikowane w dwóch kontrolerach — do metod klasowych modelu. Jeden commit, 4 pliki zmienione, 2 usunięte, 2 dodane.
Mój prompt miał jedno słowo: „refactor."
Mógł być tak krótki, bo wokół stały barierki.
Gdy branch doszedł do tego punktu, miał 221 testów. Wszystkie krytyczne ścieżki flow płatności były pokryte.
Domyślne działanie Claude'a przed refaktoringiem to nie „najpierw zajrzyj w testy." Więc kazałem mu uruchomić bin/rails test najpierw, potwierdzić zielone, i dopiero wtedy czegokolwiek dotykać.
Po refaktoringu puścić jeszcze raz. Wciąż zielone. To nie znaczy „brak regresji" — znaczy, że znane zachowanie nie jest złamane.
Jeśli twój codepath nie ma pokrycia testowego, każ Claude'owi napisać minimalny test, który utrwala obecne zachowanie. Puść go, zacommituj. Dopiero wtedy refaktoring. Inaczej to, co on robi, to nie refaktoring, tylko przepisywanie — i nie masz sposobu zweryfikować ekwiwalencji.
Ten refaktoring w rzeczywistości był dwoma rzeczami:
Purchase / Subscription: kontroler → metody klasowe modeluNa froncie była trzecia: przepisać flow podpisu po stronie JS z viem + x402-fetch.
Kazałem Claude'owi dzielić po naturalnych granicach: backend + ekstrakcja modelu w jednym commicie (9f3e239), frontend w osobnym (93746d8). Każdy commit nosi pełny opis, listę plików i uzasadnienie zmiany.
Korzyści:
- Diffy pozostają czytelne. Jeden commit, jedna rzecz.
- Granularność rollbacku. Jeśli produkcja złapie buga frontendu, git revert 93746d8 cofa tylko front, zostawiając backend.
- Uwaga samego Claude'a pozostaje skupiona. Jeden commit, jedna rzecz — i jego uwaga pokrywa tylko tę jedną.
Gdy refaktoring jest skończony, zatrzymuję Claude'a i każę pokazać git diff --staged. Nie uruchamiaj testów. Nie odpalaj aplikacji. Najpierw czytaj diff.
Sygnały, które skanuję:
app/services/x402/payment_handler.rb wywalony w całości — ok, to sens migracji na gem. Ale jeśli usunął coś, czego nie prosiłem dotykać, zatrzymuję się i pytam.Purchase.create!(wallet_address: verify_result["payer"], ...) → Purchase.record_x402!(payment:, settlement:) teraz czyta payment[:payer]. Źródło się zmieniło (request.env z gema vs wartość zwracana przez stary klient), ale pola muszą mapować się jeden do jednego.Pułapka 1: Stimulus controllers gema cicho się nie załadowały
Gem x402-rails przychodzi z własnymi Stimulus controllers. Claude napisał kod, testy przeszły zielone. Kliknąłem ręcznie przycisk płatności — nic.
Powód: w config/importmap.rb pin dla @hotwired/stimulus wskazywał na nieistniejący plik vendor, a importmap cicho wyrzucił ten pin. Controllers gema nigdy się nie załadowały. Testy tego nie łapią, bo bin/rails test nie wykonuje JS.
Pułapka 2: YAML sparsował 0x... jako integer
wallet_address: 0x833589... — bez cudzysłowów. YAML zobaczył prefiks 0x, odczytał jako szesnastkową liczbę całkowitą. Facilitator dostał non-stringa i odrzucił. Claude nie zatrzymał się, żeby pomyśleć o regułach parsowania YAML, gdy pisał config.
Obie pułapki zostały złapane, bo kliknąłem prawdziwy przycisk. Zielone testy to nie to samo, co działająca funkcjonalność. Ręczna weryfikacja po refaktoringu nie jest opcjonalna.
Refaktoring to scenariusz „puść Claude'a za kierownicę" o najwyższym ryzyku. Barierki nie są dla Claude'a. Są dla ciebie — żebyś, kiedy Claude coś spierniczy, złapał to w 5 minut, a nie w pożarze na produkcji.