這句話你大概率聽過,甚至自己講過。邏輯聽起來很合理:以前工程師手動寫程式碼很貴,一行都要斤斤計較;現在 AI 幾秒鐘就能生出幾百行,多包幾層架構、多留幾個擴充點,反正「打字」不再是成本,那寫多一點又何妨?
我想先請你想一個問題:如果 AI 產出程式碼的速度是你閱讀速度的 100 倍,你打算怎麼 review 它?
多數人的答案是「還是要靠人審啊,AI 生成的東西本來就要人把關」。這句話沒有錯,但它迴避了一個更根本的現實:人的閱讀速度是固定的,不會因為 AI 進步就變快;AI 的產出速度卻是指數成長的。如果 review 的方法論沒有跟著變,這句「靠人把關」聽起來很負責任,實際上只是把一個追不上的問題往後拖延而已。
這個系列要做的事情很具體:我拿一個業務邏輯極簡單的小系統(一個新聞發佈系統,規則只有「草稿可以編輯、發佈後不能重複發佈、下架回草稿、已發佈需先下架才能編輯」這幾條)當白老鼠,用同一組驗收測試,做出兩個版本——一個是遵循 Outside-In TDD 紀律寫出來的乾淨版本,另一個是模擬「AI 拿到一句模糊需求、自由發揮」會長出來的過度設計版本。兩個版本都通過一模一樣、一行都沒改的測試。
結果:乾淨版本 3 個檔案、249 行;過度設計版本 745 個檔案、21,727 行。業務規則完全沒變,程式碼量差了 87 倍。
這個系列的主題句是:AI 沒有發明過度設計,它只是讓過度設計的速度追上了你按下 Enter 的速度;Review 要跟得上,審的就不能再是程式碼本身,而是產生程式碼的規則。
先講一個具體的數字對比,這是我在準備這個系列時,親自動手做出來的兩個版本:
| 指標 | 乾淨版本 | 過度設計版本 | 倍數 |
|---|---|---|---|
| 檔案數 | 3 | 745 | 248 倍 |
| 總行數 | 249 | 21,727 | 87 倍 |
| 業務規則數量 | 4 條 | 4 條(完全相同) | 1 倍 |
| 驗收測試數 | 10 | 10(一字未改) | 1 倍 |
業務規則沒有變、測試沒有變,程式碼量卻差了 87 倍。這個過度設計版本不是我隨便亂寫湊數的,裡面有一組真正會被測試呼叫、邏輯正確的核心架構(Domain Aggregate、CQRS 的 Command/Query Bus、四層 Repository 裝飾器),剩下的 92% 是「以防萬一」預先建好、從來沒被任何測試碰過的類別——假設性的未來功能(封存、標籤、排程發佈、批次操作……)、沒有業務規則用到的欄位(SEO 標題、封面圖網址、瀏覽次數……)、多餘的快取/日誌後端。
這正是 AI 自由發揮時最常見的樣貌:不是寫錯,是寫多。 每一段程式碼單獨看都合理、都能編譯、都符合某種「最佳實踐」的直覺,但合在一起,就是一個要花掉你半天時間才能搞懂「這裡到底在幹嘛」的迷宮。
如果這只是一個孤立的示範案例,倒也還好。但把這個現象放大到真實的專案規模——不是 745 個檔案,而是 7,000 個;不是 21,727 行,而是 200,000 行——你會發現「交給人 review 就好」這句話開始站不住腳。不是人不夠認真,是閱讀速度本來就追不上。
這裡有一個容易被忽略、卻是整個系列最關鍵的認知落差:測試驗證的是「行為」,不是「設計」。
我這兩個版本用的是同一組驗收測試,兩者都 100% 通過。如果你只看 CI 的綠燈畫面,你完全看不出這兩個版本有任何差異。測試告訴你的是「輸入 X,會得到輸出 Y」,它不會告訴你「這個輸出是用一行程式碼算出來的,還是繞過八層抽象才算出來的」。
這個落差在 AI 生成程式碼的情境下特別危險,因為 AI 非常擅長讓測試變綠——這正是它被訓練、被評估的方式。你越是只看「測試過了嗎」,越容易忽略「這個實作方式合不合理」這個完全不同維度的問題。
❌ 常見但不夠的檢驗方式:
$ php artisan test
Tests: 10 passed
看到這個畫面,很多人(包含很多資深工程師)的直覺反應是「好,過了,可以合併」。但這只回答了「AI 有沒有理解需求的行為規格」,完全沒有回答「AI 有沒有用一個合理的方式實現它」。
✅ 更完整的檢驗,至少要再多問一個問題:
這個功能只有 4 條業務規則,
為什麼我要改一個欄位,得動到 10 個檔案?
測試通過只證明程式碼「能動」,不證明程式碼「該長這樣」。 這句話值得貼在每一個 code review checklist 的最上面。
我想先在系列一開始就把立場講清楚,避免後面的內容被讀成「吐槽 AI 很蠢」:AI 在我這個過度設計版本裡做的每一件事,都不是隨機亂來,而是在「我只給了一句模糊需求、沒有講清楚 constraints」的情況下,用它認為「專業」「完整」「有擴充性」的預設值去填空。這跟一個資淺工程師被要求「幫我做一個新聞系統」、然後自己腦補出一堆架構,本質上是同一件事,只是 AI 的手速快了幾百倍。
過度設計從來就不是 AI 時代才有的問題。往前推十幾年,Steve Freeman 跟 Nat Pryce 那本《Growing Object-Oriented Software, Guided by Tests》(業界簡稱 GOOS)講的核心方法論之一,就是用 Outside-In 的驗收測試去逼出你「真正需要」的類別,而不是讓工程師憑空想像未來可能需要什麼。ATDD(Acceptance Test Driven Development)存在的理由,某種程度上就是在對抗這個人類工程師早就有的老毛病。
我這個系列要講的,不是「AI 又搞砸了」,而是一套十幾年前就存在的紀律,在 AI 產出速度暴增的今天,重要性不是降低了,是被放大了。這也是為什麼我這個系列不會停在「展示一個 21,727 行的怪物讓大家笑一笑」,而是會花後半段的篇幅,回到 Outside-In TDD/ATDD 這套方法論,講清楚它具體怎麼變成擋住過度設計的護欄。
回想你最近一次 review 別人(或 AI)寫的程式碼:你是先看「測試有沒有過」,還是先問「這個改動範圍,跟這個需求的複雜度成不成比例」?如果你的團隊有 AI 生成的程式碼進到主幹,你們現在的 review 流程,抓得出「跑得動但不必要」的程式碼嗎?
Day 2 會實際示範這個過度設計版本是怎麼「長出來」的——用一句刻意模糊的需求描述,看 AI 會自己腦補出哪些「看起來很專業」的架構決策,並具體點出哪些是它自己補上的隱性假設。
我自己過去在推動測試文化的過程中,一直有一種說不清楚的不安:明明測試都寫了、覆蓋率也不低,但程式碼還是會演變成沒有人敢動的樣子。以前我以為問題出在「測試寫得不夠多」,這幾年帶著 AI 一起寫程式碼之後,我才比較確定:問題從來不是測試的數量,是測試回答不了「這個設計合不合理」這個問題,而這個問題,以前靠資深工程師的經驗跟直覺硬撐過去,現在 AI 把產出速度拉高之後,這個靠經驗硬撐的方式,撐不住了。這個系列,某種程度上是我想把這件事講清楚給自己聽。