業界這幾年有一句話越來越常聽到:「AI 產出再多程式碼都沒關係,交給 code review 把關就好。」這句話聽起來很負責任,也確實符合直覺——人一直都是軟體品質的最後一道防線。但我一直對這句話有一個沒有被驗證過的疑慮:這句話成立的前提,是人的審查速度追得上要被審查的東西的量,而這個前提,在 AI 產出速度暴增之後,還站得住腳嗎?
這個系列的真實動機,就是想具體驗證這句話到底站不站得住腳,而不是繼續停留在「感覺 AI 生成的程式碼比較亂」這種模糊印象上。我選擇的做法是做一個對照實驗:找一個業務邏輯極簡單的新聞發佈系統,用同一組驗收測試,分別做出一個遵循 Outside-In TDD/ATDD 紀律寫成的乾淨版本,跟一個模擬「AI 拿到一句模糊需求、自由發揮」會長出來的過度設計版本。兩個版本都通過一模一樣、一字未改的 10 條 Given-When-Then 測試。結果:乾淨版本 3 個檔案、249 行;過度設計版本 745 個檔案、21,727 行,其中真正會被核心流程呼叫到的只有 62 個檔案、1,738 行——92% 的程式碼,是逐行看得到,但要花很長時間才能確認「這些東西沒有被呼叫」的死碼。這組數字是這 30 天所有討論的起點,也是這篇總結想重新收攏的終點。
這一部的核心任務是把「AI 產出速度 vs 人眼審查速度」這個結構性落差講清楚,並且建立「測試通過不等於設計正確」這個貫穿全系列的關鍵區分。Day 1 用兩個版本的數字對比開場;Day 2 具體示範一句模糊需求怎麼讓 AI 腦補出一堆隱性架構決策;Day 3 正面拆解「測試都綠燈」為什麼不能證明設計沒問題;Day 4 把過度設計放回技術史脈絡,指出它不是 AI 帶來的新病;Day 5 講意外複雜度跟本質複雜度的分辨;Day 6 提出「改動範圍 vs 需求範圍」這個可以量化的指標;Day 7 收束成「Review 的舊模型為什麼追不上 AI 的產出速度」。
回頭看,這一部最重要的產出不是任何一個具體數字,而是把「落差」講成一個結構性問題,而不是「人不夠認真」的問題。這個定調直接決定了整個系列後面不會走向「教大家怎麼更認真 review」,而是走向「重新設計 review 該審的對象」。如果沒有先把這個結構性落差講清楚,後面談規則、談機制,很容易被讀成「多一道麻煩的檢查」,而不是「唯一追得上速度落差的辦法」。
這一部是整個系列的證據主體。Day 8 講案例本身怎麼設計;Day 9-10 分別展示乾淨版本跟過度設計版本各自長什麼樣子;Day 11-13 逐項拆解過度設計版本裡多出來的 Repository/UnitOfWork/Specification、Event/Listener、DTO/Mapper 各自在保護什麼(或者說,並沒有真的在保護什麼);Day 14 回到「兩者都通過測試,但只有一個設計對」這個核心矛盾;Day 15 誠實拆解了「逐行 review 到底要花多久」這個問題,說明為什麼給不出一個看起來很科學、實際上不可信的精確數字;Day 16 討論光讀程式碼找不出的認知負荷與維護成本問題。
回頭看這一部,最有說服力的不是「21,727 行」這個總數字,而是像 SqliteUnitOfWork 的 begin()/commit()/rollback() 全部是 no-op、RetryingArticleRepositoryDecorator 宣稱最多重試 3 次卻永遠只執行一次這類名不符實的具體案例。抽象的「過度設計」很容易被讀者當成修辭,但「這個類別的名字承諾了它沒有兌現的行為」是可以被具體驗證、也最容易讓人倒抽一口氣的證據。這一部教會我的事:要說服人相信一個結構性問題存在,光講統計數字不夠,要能指出「這一行程式碼騙了你」的具體時刻。
這一部從案例轉向解法。Day 17-18 回到 Outside-In TDD/ATDD 跟 GOOS 的核心洞察——用外層測試逼出你真正需要的類別;Day 19 講怎麼把「不要過度設計」寫成可執行的架構測試;Day 20 提出複雜度預算這個具體門檻;Day 21 講讓 AI 自己先跑一次 Outside-In 流程,而不是事後補救;Day 22 談 CLAUDE.md/Skill 怎麼把紀律變成 AI 每次都遵守的預設值;Day 23 收束成「人定規則,工具驗證,AI 產生」這個分工模型。
回頭看,這一部最容易被誤讀的地方,是把它讀成「只要建好這些機制,問題就解決了」——這正是我在第四部花了好幾天要澄清、也不打算在這篇總結文裡淡化掉的地方。機制解決的是執行落差:讓規則被貫徹的速度追上 AI 產出的速度。但機制解決不了判斷落差:規則本身該怎麼訂、門檻該設多少,這一步始終需要人的經驗判斷,機制只是判斷力的執行手臂,不是替代品。
這一部的任務,是把前三部的論點放到更嚴苛的檢驗下,看它還能不能撐住。Day 24 用推演的方式檢驗「複雜度預算」套用到更複雜的功能(分類、留言)會不會失靈,結論是框架本身沒有失靈,但需要先分清楚需求的本質複雜度,而分辨本質複雜度這一步,機制幫不上忙。Day 25 正面回答「這套方法論解決不了什麼」——機制檢查的是有沒有守規則,不是規則對不對,語意層次的重複(同一條規則寫在三個地方)是結構性檢查天生抓不出來的。Day 26 換成第一人稱,誠實回顧自己從「相信人眼 review」走到「相信可執行規則」的轉折,承認自己也曾經對「預先多包一層比較安全」有過不對稱的信任。Day 27 反過來質疑這套方法論自己——規則清單會不會腐化成另一套沒人維護的技術債,答案是會,但緩解的辦法不是疊加更多機制,是把規則的維護放進跟程式碼維護一樣的紀律裡。Day 28 把格局拉到最高,指出 AI 加速的不是寫程式,是每一種舊毛病的發作速度。Day 29 誠實列出這套方法論的邊界——探索性原型、一次性程式碼、團隊還沒共識的階段,都不適合套用。
回頭看這一部,它存在的理由不是「補完系列篇幅」,而是給前三部的論點補上「這套東西不是萬能的」這個誠實的但書。一個方法論如果不敢誠實面對自己的邊界,讀者遲早會在某個踩坑的時刻,對整套論點失去信任——與其等讀者自己發現邊界,不如自己先講清楚。
Day 26、27 各自誠實談過轉折跟規則維護成本,這裡想再往深一層講一件事:這整個系列寫到後半,讓我最不安的段落不是拆解那個 21,727 行的怪物系統——那個案例雖然規模驚人,但道理其實很直觀,多數有經驗的工程師看一眼就懂問題出在哪。真正讓我心裡不踏實的是 Day 27 那篇——我很清楚,只要我自己團隊裡有任何一條複雜度預算或架構測試規則,超過半年沒有人回頭檢視過,它遲早會變成跟過度設計版本裡那些死碼一樣的東西:曾經有存在的理由,現在只是佔著位置,沒有人敢動它,也沒有人真的知道它還在保護什麼。
這個不安沒有辦法靠寫更多規則來解決,因為問題本身就是「規則太多、沒人回頭看」,再加一條規則只是讓這個問題更嚴重。我目前沒有一個完美的答案,能誠實講的只是:把規則的回顧,當成跟程式碼重構一樣的例行工作,而不是一次性的基礎建設,是目前我認為唯一誠實的方向。這件事需要的紀律,某種程度上比寫測試更反直覺——寫測試至少有立即的回饋(紅燈變綠燈),回頭檢視一條沉睡半年的規則,通常沒有任何立即的回饋,很容易被排到永遠不會被執行的待辦清單底部。
另外一個誠實要講的心得是:這 30 天下來,我對「AI」這個詞在系列裡的角色定位,其實比我一開始想的更明確了。一開始我以為這個系列是在講「怎麼審查 AI 生成的程式碼」,寫到後面(尤其是 Day 28)才確定:這個系列真正在講的是「怎麼審查任何速度快到人眼追不上的程式碼生成方式」,AI 只是目前最極端、也最普及的那一種。如果將來出現另一種更快的程式碼生成方式,這套判斷框架應該一樣適用——因為它從來就不是針對 AI 本身設計的,是針對「產出速度超過審查速度」這個結構性問題設計的。
如果要把 30 天的內容濃縮成一組讀者拿到手上就能用的判斷框架,我會建議在任何一次 code review(不管是 review 人還是 review AI)時,依序問這四個問題,取代單純看「測試有沒有過」:
這四個問題沒有一個需要靠讀完全部 30 天才能理解,但它們背後都有一整篇(甚至好幾篇)具體案例支撐,這也是我希望這篇總結能提供的價值——不是重複內容,是把內容變成一個可以隨手拿出來用的檢查清單。
如果你讀完這個系列,只能做一件事,我會建議從第 1 個問題開始,因為它成本最低、最容易立刻套用:下一次 review 一個 AI 生成或人寫的 PR 時,先不要看程式碼內容,只看「改動了幾個檔案、幾行」,然後問自己「這跟需求描述的複雜度,直覺上對得起來嗎」。這個問題不需要任何工具、不需要說服團隊導入新機制,任何人都可以今天就開始問。如果你在多次這樣做之後,發現這個直覺屢屢被印證,那就是你可以進一步導入 Day 19-20 講的架構測試跟複雜度預算的時機——先用最便宜的方式驗證這套框架對你的專案有沒有用,再決定要不要投入建立機制的成本,這本身也是 Outside-In 精神的一種體現:先讓一個最小的驗證跑起來,再逼出你真正需要的下一步。
Day 1 我用「老派工程師」這個身份開場,那時候這個詞帶著一點自嘲——覺得自己對「多包一層比較安全」的直覺,可能只是跟不上時代的老派習慣。寫完這 30 天,我想重新定義這個詞:老派,不是抗拒新工具,是在工具的產出速度加快之後,更堅持問「這個東西存在的理由講得清楚嗎」這個從來沒有過時的老問題。 Outside-In TDD、ATDD、GOOS 這些方法論,在 AI 出現之前就已經存在了十幾年,它們老派,但它們解決的問題,恰恰是 AI 時代被放大到最尖銳的問題。
回到這個系列從頭到尾沒有動搖過的那句話:AI 沒有發明過度設計,它只是讓過度設計的速度追上了你按下 Enter 的速度;Review 要跟得上,審的就不能再是程式碼本身,而是產生程式碼的規則。 如果這 30 天有留下一件事,希望是這句話——不是當成一句口號記住,而是下一次你 review 任何程式碼時,真的先問一句:我現在審的,是程式碼本身,還是產生這段程式碼的規則?