蜥蜴的尾巴
在生物學裡,autotomy 指的是動物主動捨棄已經不再有用的身體部位。蜥蜴會斷尾來逃離掠食者。那條尾巴曾經有用,但想活下來,就得放手。之後還會再長出一條新的。
這就是你應該如何看待 Vibe-coded React Native app 的重構。
在 AI-coded 的早期 MVP 裡,第一版 auth flow 往往比任何人預期都更快上線。真正的麻煩出現在幾週後:product 變了,team 開始小心翼翼地重構一套他們其實從未真正設計過的程式碼。這時 login 會壞,user state 會漂移,bug 數量也會上升。因為他們正在努力保留一段本來就應該被替換的程式碼。
重構 AI 生成的程式碼之所以昂貴,是因為它要求你去理解一個你從來沒有擁有過的意圖。Claude Code 建了不是你設計的抽象。它做了不是你批准的 coupling 決策。去重構這些程式碼,等於在逆向推斷一套靠機率形成、而不是靠意圖形成的架構決策。
替換,不要重構
另一個做法是:只要一個模組滿足相同的 interface,並且通過相同的測試,你就可以在不理解舊實作的前提下把它換掉。舊模組刪掉。新模組補上。只有 composition root 知道這件事。
// Module A (Auth v1) -> Interface Contract -> Module A' (Auth v2)
// The old auth module. You don't need to understand it.
// Claude Code generated it. It worked. Now it's done.
class SupabaseAuthService implements AuthService {
// ... implementation you inherited ...
}
// The new auth module. You designed it. Claude Code helps write it.
class CustomAuthService implements AuthService {
// ... your clean implementation ...
}
// The composition root is the ONLY place that changes:
const auth: AuthService = useSupabase
? new SupabaseAuthService()
: new CustomAuthService()
login screen 不用改。route guard 不用改。hooks 不用改。只有 composition root 知道發生過一次替換。這就是在 AI 生成程式碼的場景下,interface-driven architecture 的威力。interface 就是你對抗 technical debt 的保單。
安全刪除的四個前提
這套方法只有在四個前提成立時才有用。沒有它們,你只是在刪程式碼然後祈禱。具備它們,你才是在做手術:
- Defined interfaces — 每個模組都暴露一份 contract。TypeScript 型別、API schema、清楚的邊界。Cursor 會對著它們生成。Claude Code 會讀它們。這些 contract 是你擁有的。
- Boundary enforcement — 模組不能隨手伸進彼此的內部。dependency-cruiser、ESLint 或團隊慣例都可以用來防止這件事。
- Contract tests — 測試驗證的是 interface,不是 implementation。只要新模組通過同一批測試,它在行為上就是等價的。
- Clean dependency graphs — 沒有循環依賴。沒有透過 global 偷偷耦合。import graph 是 DAG,不是蜘蛛網。
不碰任何一個 screen,就把 analytics 換掉
一開始你用了 Segment,因為 Claude Code 建議你這麼做。現在你要換成 PostHog。舊模組直接刪掉。新模組實作同一個 interface。所有 call site 都保持不變:
// Before
const analytics = new SegmentAnalytics(writeKey)
// After — same interface, different implementation
const analytics = new PostHogAnalytics(apiKey)
// Every call site stays the same.
// Cursor-generated screens don't change.
analytics.track('purchase_completed', { productId: '123' })
analytics.identify(userId, { plan: 'premium' })
想保留既有程式碼的本能很強。我們總想小心翼翼地把所有行為一起搬過去。但當你面對的是 AI 生成的程式碼,最安全的路往往是放手。先把 interface 寫好。把邊界守住。然後願意刪除。
Autotomy Expo Starter Pack 就是圍繞這種哲學打造的:每個模組都是為了替換而設計,不是為了保留。當你的 Vibe-coded app 撞上規模化的牆,你不是去硬拆 Claude Code 當年做出的架構決策。你是直接把它們換掉。