如果一套方法論宣稱自己什麼情境都適用,那通常代表它還沒被誠實檢驗過邊界在哪裡。這個系列講了 28 天的 Outside-In TDD/ATDD、架構測試、複雜度預算,今天要誠實承認:這些東西不是萬靈丹,有些情境下用了反而會拖慢速度,甚至產出比不用還糟的結果。
Outside-In TDD 的起點是先寫一條 Given-When-Then 驗收測試,用它逼出你需要的類別。這個方法論的隱藏假設是:你已經知道「行為」該長什麼樣子,只是還沒決定「用什麼結構去實現它」。但在真正的探索階段——例如你在驗證一個全新的產品構想,連「使用者到底要的是什麼」都還在猜——連「行為」本身都是不確定的,這時候先寫驗收測試反而會綁死一個可能明天就要整個推翻的假設。
複雜度預算在這個階段也一樣會幫倒忙。如果我在探索階段就要求「改一個欄位只能動 3 個檔案」,等於是在還沒確定系統長期形狀之前,就先用生產環境的紀律束縛住手腳。探索階段真正需要的是「改得動、丟得掉」的速度,過早引入嚴格門檻反而會讓工程師為了不觸發警報而綁手綁腳,浪費在探索階段最寶貴的資源——時間跟嘗試次數。
有些程式碼從一開始就注定活不過幾天——一次性的資料遷移腳本、一次性的分析工具、demo 用的展示程式。這類程式碼不會被長期維護,也不會有第二個人接手,套用架構邊界、寫驗收測試的成本,遠超過它能帶來的效益。這不代表可以完全不管品質,而是「品質」在這裡該優化的目標不一樣——優化的是「今天能不能跑完、結果對不對」,不是「三年後好不好維護」。
這裡要小心一個容易混淆的地方:「探索階段寫得亂一點」跟「過度設計」表面上看起來都是「程式碼比它該有的樣子複雜或凌亂」,但性質完全相反。過度設計是把還沒被需求逼出來的抽象,包裝成看起來永久、正式的架構(例如過度設計版本裡那些從未被呼叫過的六件套 Command/Handler/Validator);探索性程式碼則應該誠實標示自己是臨時的,不假裝自己是正式架構。真正的風險不是「探索階段寫得亂」,是「探索階段的產物,沒有被誠實標記,直接被當成正式架構繼續疊上去」——這時候複雜度預算、架構測試才應該正式介入,作為「這段程式碼要從探索轉正,該補上規則了」的分界點。
架構測試、複雜度預算這類機制要發揮效果,前提是團隊對「什麼樣的複雜度是合理的」已經有一定共識——不然機制寫出來的門檻,只是某一個人的主觀偏好被強加給所有人,反而會製造摩擦而不是共識。在團隊還在磨合技術方向、還沒有共同語言討論「這個抽象到底必不必要」的階段,過早把某個人的判斷寫死成強制檢查,容易變成團隊衝突的引信,而不是品質的護欄。
回到系列主題句:AI 沒有發明過度設計,它只是讓過度設計的速度追上了你按下 Enter 的速度;Review 要跟得上,審的就不能再是程式碼本身,而是產生程式碼的規則。 這句話講的是「當你已經在建構一個要長期維運的系統」這個前提下的道理。探索性原型、一次性腳本、團隊還沒共識的階段,本來就不在這個前提之內——不是這套方法論失靈了,是它本來就沒打算管到那裡。誠實劃出這條線,比含糊地說「什麼情境都適用」更能讓讀者正確判斷什麼時候該用。
你手上正在做的專案,現在是「已經知道行為只是還沒定案結構」的階段,還是「連行為本身都還在猜」的探索階段?如果是後者,你有沒有不小心把探索階段寫的程式碼,直接當成了正式架構繼續往上疊?
Day 30 是整個系列的總結:如果 code review 真的追不上 AI,我們該怎麼重新定義它到底在審什麼。
我自己也曾經在一個還在探索方向的小工具上,堅持要求自己寫驗收測試,結果因為需求隔天就整個推翻,那些測試變成純粹的沉沒成本。那次經驗讓我學到,紀律的價值來自於用對地方,不是來自於「無條件、任何情境都堅持套用」,後者反而是另一種形式的教條主義。