錯誤的衡量標準

大多數關於 AI 生成程式碼品質的討論,都聚焦在生成當下的正確性。輸出能編譯嗎?能通過測試嗎?符合規格嗎?

這些只是基本門檻。它們無法告訴你真正的成本。

真正的衡量標準是可替換性:當需求改變時,你能以多低的成本刪除這個 module 並在相同的 contract 背後重新實作?

如果答案是「輕而易舉」,AI 的速度優勢就能持續累積。如果答案是「我們需要先追蹤六個隱含的依賴關係」,那麼你以為買到的速度優勢早已消失。

為什麼 AI 程式碼傾向於耦合

大型語言模型為即時需求最佳化,而非為未來的變更最佳化。

當你提示要一個登入流程,你得到的是一個能運作的登入流程。你得到的不是一個位於 auth interface 背後、可以在不觸及任何使用它的畫面的情況下從 Firebase 換成 Supabase 或自訂 JWT 服務的登入流程。

這不是模型的失敗,而是上下文的失敗。模型沒有被要求為可替換性最佳化,所以它沒有這麼做。

結果是:AI 生成的程式碼預設傾向於緊密耦合。不是因為模型不好,而是因為隔離性永遠不是下一個 token 預測器的阻力最小路徑。

可替換性是架構決策

可替換性不會偶然發生。它是刻意的結構選擇:

  • 每個外部依賴都位於應用程式擁有的 interface 背後。
  • 每個生成的 module 暴露的是 contract,而非實作。
  • 每個可選功能都是注入的,而非直接匯入。
  • 每個組合決策都在一個 composition root 中,而非散佈在五十個檔案裡。

這不是什麼新概念。這就是基本的 dependency inversion。新的是,AI 生成的程式碼讓違反這些原則變得毫不費力且不可見——直到你需要改變什麼的時候。

複合效應

當每個 module 都可替換時:

  • 失敗的生成只花幾分鐘的代價,而非幾天。
  • 廠商變更只是 interface 置換,而非 rewrite。
  • AI 的速度在迭代過程中保持線性,而非對數遞減。
  • 團隊可以說「在相同的 contract 背後重新生成這個」,而且是認真的。

當 module 之間糾纏不清時:

  • 每次變更都需要理解完整的依賴圖。
  • 每次 AI 輔助的 refactor 都有破壞無關系統的風險。
  • 團隊逐漸不再信任 AI 輸出,因為爆炸半徑無法預測。
  • 速度回落到 AI 之前的水準,但現在有更多程式碼需要維護。

實務測試

在接受任何 AI 生成的 module 進入 codebase 之前,執行一個測試:

我能否刪除這個檔案,並僅使用它暴露的 interface 從頭重新實作,而不需要修改任何使用者?

如果可以,就交付。如果不行,先修好 boundary 再交付。

這很容易 enforce。一個 composition root 加上 interface 優先的設計,在結構上就能賦予你這個特性。你不需要精巧的治理機制。你只需要一條架構規則被一致地執行。

與 AI-Native 架構的關聯

我在 Stanford CS146S 對 AI 程式開發的見解是對的——缺少的科目是架構 中討論了這個更廣泛的問題。可替換性原則是讓 AI-native codebase 在第一版之後仍能存活的具體機制。

Stanford 正在教開發者如何有效地使用 AI 工具。這很重要。但缺乏可替換性的工具熟練度是一個陷阱:你會更快地交付,直到 codebase 變得昂貴難以改變,然後你的交付速度會比從未使用 AI 的團隊還慢。

這門紀律不是「更好地提示」。這門紀律是「架構設計讓提示錯誤的修正成本很低」。

常見問題

「可替換架構」對 AI 生成程式碼意味著什麼?

可替換架構意味著每個 AI 生成的 module 都位於一個 interface 背後,系統的其餘部分依賴的是這個 interface——而非實作本身。當需求改變或生成有誤時,你可以刪除該 module 並重新實作,而不需要觸及使用者。

如何在 AI 生成的 codebase 中 enforce 可替換性?

三個機制:由應用程式(而非依賴)擁有的 interface、一個將所有實作連接在一起的單一 composition root,以及一個在任何 module 直接匯入另一個 module 內部時會失敗的 CI 檢查。

可替換性會拖慢初始開發嗎?

不會。在生成實作之前定義 interface 只需幾秒鐘。不這麼做的代價會在幾週後顯現——當廠商置換或 refactor 變成完整的 rewrite 時。

這跟依賴注入一樣嗎?

依賴注入是實現可替換性的一種機制,但不是全貌。可替換性還需要 contract tests、boundary 驗證,以及 composition root——而不僅僅是建構函式參數。