ל-refactor אין תסמינים — טעויות של Claude לא נראות. שלושה מעקות: טסטים, קומיטים אטומיים, קליק ידני.
Refactor היא המשימה שבה Claude מסוכן ביותר. לבאג יש תסמינים — כפתור לא מגיב, ערך undefined, stack trace — אז אפשר להבין אם התיקון של Claude נכון. ל-refactor אין תסמינים. "זה עדיין רץ" יכול להיות שווה ערך ל-"הטסטים עדיין עוברים" בזמן שהתנהגות השתנתה בשקט, לא שמת לב, ושבוע אחר כך הפרודקשן בוער.
לאחרונה עשיתי עם Claude refactor גדול יחסית ב-how2claude: העברתי את תשלומי הקריפטו של x402 מ-PaymentHandler + FacilitatorClient שנכתבו ידנית (139 שורות) אל ה-gem x402-rails, ובמקביל חילצתי את מיפוי השדות של Purchase.create! / Subscription.create! — שהיה כפול בין שני controllers — למתודות מחלקה על ה-model. קומיט אחד, 4 קבצים השתנו, 2 נמחקו, 2 נוספו.
הפרומפט שלי היה מילה אחת: "refactor."
הוא יכול היה להיות קצר כל כך כי היו מעקות מסביב.
כשהענף הגיע לנקודה הזאת היו בו 221 טסטים. כל הנתיבים הקריטיים בפלואו התשלום מכוסים.
פעולת ברירת המחדל של Claude לפני refactor איננה "הסתכל קודם בטסטים." אז אמרתי לו להריץ קודם bin/rails test, לוודא ירוק, ואז לגעת במשהו.
אחרי ה-refactor, להריץ שוב. עדיין ירוק. זה לא אומר אפס רגרסיות — זה אומר שההתנהגות הידועה לא שבורה.
אם לנתיב הקוד שלך אין כיסוי בטסטים, תן ל-Claude לכתוב טסט מינימלי שמקבע את ההתנהגות הנוכחית. תריץ, תעשה commit. אחר כך refactor. אחרת מה שהוא עושה זה לא refactor אלא rewrite — ואין לך דרך לאמת שוויון.
ה-refactor הזה היה למעשה שני דברים:
Purchase / Subscription: controller → מתודות מחלקה על ה-modelבצד הפרונט היה דבר שלישי: לשכתב את פלואו החתימה בצד ה-JS עם viem + x402-fetch.
הכרחתי את Claude לפצל לפי גבולות טבעיים: backend + חילוץ model בקומיט אחד (9f3e239), frontend בקומיט נפרד (93746d8). כל קומיט נושא תיאור מלא, רשימת קבצים, והסבר למה השינוי.
יתרונות:
- ה-diffs נשארים קריאים. קומיט אחד, דבר אחד.
- גרנולריות של rollback. אם פרודקשן תופס באג פרונט, git revert 93746d8 מחזיר רק את הפרונט ומשאיר את ה-backend.
- תשומת הלב של Claude עצמו נשארת ממוקדת. קומיט אחד, דבר אחד — ותשומת הלב שלו מכסה רק את הדבר הזה.
כשה-refactor מושלם, אני עוצר את Claude ומבקש להראות git diff --staged. אל תריץ את הטסטים. אל תריץ את האפליקציה. תקרא את ה-diff קודם.
אותות שאני סורק:
app/services/x402/payment_handler.rb נמחק לגמרי — אוקיי, זו הפואנטה של המעבר ל-gem. אבל אם הוא מחק משהו שלא ביקשתי לגעת בו, אני עוצר ושואל.Purchase.create!(wallet_address: verify_result["payer"], ...) → Purchase.record_x402!(payment:, settlement:) עכשיו קורא payment[:payer]. המקור השתנה (request.env של ה-gem לעומת ערך ההחזרה של ה-client הישן), אבל השדות חייבים להתאים אחד לאחד.מלכודת 1: ה-Stimulus controllers של ה-gem לא נטענו בשקט
ה-gem x402-rails מגיע עם Stimulus controllers משלו. Claude כתב את הקוד, הטסטים עברו ירוקים. לחצתי ידנית על כפתור התשלום — שום דבר.
סיבה: ב-config/importmap.rb ה-pin עבור @hotwired/stimulus הצביע על קובץ vendor לא קיים, ו-importmap השמיט את ה-pin הזה בשקט. ה-controllers של ה-gem מעולם לא נטענו. הטסטים לא יכולים לתפוס את זה כי bin/rails test לא מריץ JS.
מלכודת 2: YAML פרש את 0x... כמספר שלם
wallet_address: 0x833589... — בלי מרכאות. YAML ראה את הקידומת 0x וקרא אותה כמספר שלם הקסדצימלי. ה-facilitator קיבל ערך שאינו מחרוזת ודחה. Claude לא עצר לחשוב על חוקי הפריסור של YAML כשכתב את הקונפיג.
שתי המלכודות נתפסו כי לחצתי על הכפתור האמיתי. טסטים עוברים זה לא אותו דבר כמו פיצ'ר עובד. אימות ידני אחרי refactor הוא לא אופציונלי.
Refactor הוא התרחיש הכי מסוכן מבין "תן ל-Claude לנהוג." המעקות לא בשביל Claude. הם בשבילך — כדי שכש-Claude טועה, תתפוס את זה בחמש דקות ולא בשריפה בפרודקשן.