iT邦幫忙

2026 iThome 鐵人賽

DAY 8
0
Software Development

當 AI 寫得比你讀得快:Code Review 該審什麼系列 第 8 篇

Day 8:案例設計——一個新聞發佈系統,同一組驗收測試,兩種寫法

  • 分享至 

  • xImage
  •  

前言:「這種對照案例,是不是特意做出來嚇人的?」

看到「87 倍行數落差」「92% 死碼」這種數字,很自然會懷疑:這是不是刻意做出一個極端案例,用來製造戲劇效果?真實世界的過度設計,會有這麼誇張嗎?

我想老實回答:是的,這是我刻意做出來的示範案例,但刻意的地方不是「灌水製造效果」,而是刻意控制業務複雜度極簡單、刻意讓兩個版本共用同一組一字未改的驗收測試——目的正是要排除「業務本來就複雜」這個變數,讓兩個版本唯一的差異只剩下「寫法」。今天就把這個案例的設計方式講清楚,讓接下來幾天的拆解有一個扎實的地基。

今日目標

  • 認識 ai-news-test(recca0120/ai-news-test)這個示範專案的整體設計方式
  • 理解為什麼要刻意控制業務邏輯極簡單,而不是找一個複雜的真實系統來對照
  • 認識驗收測試在這個案例設計裡扮演的「不變量」角色
  • 知道兩個版本(main 與 over-engineered-demo)分別是用什麼方式產生的
  • 建立對接下來 Day 9-16 逐日拆解的期待——知道之後會分別看到什麼

案例設計的核心原則:控制變因

做這個案例最重要的一個決定,是刻意選一個業務邏輯極簡單的題目——一個新聞發佈系統,只有草稿、發佈、下架、編輯限制、列表查詢這幾個動作,核心規則只有 4 條:

  1. 標題不可為空
  2. 已發佈的文章不能重複發佈
  3. 已發佈的文章要先下架才能編輯
  4. 其餘動作(建立草稿、編輯草稿、列表查詢)屬於基本 CRUD,沒有額外規則

選一個簡單題目,不是因為簡單題目比較好寫,而是要排除「業務複雜度不同」這個變數。如果拿兩個業務規則本來就不一樣的系統來比較,行數跟檔案數的差異可能真的只是反映了業務本身的差異,沒有辦法拿來說明「寫法造成的差異」。控制業務邏輯簡單、固定,才能讓後面的數字對照有意義。

不變量:同一組驗收測試,一字未改

案例設計的第二個核心決定,是用驗收測試(Given-When-Then 形式,共 10 個測試案例,寫在 tests/Feature/PublishArticleTest.php)當作兩個版本共同的「行為契約」,而且從頭到尾一行都沒有改過。

這個設計的用意,是讓「兩個版本行為完全相同」這件事不是靠事後檢查、靠人工比對確認的,而是靠同一份測試強制保證的——只要兩個版本都通過同一組測試,就代表它們在驗收測試涵蓋的範圍內行為一致。這樣一來,剩下的所有差異(檔案數、行數、架構複雜度)就只能來自「怎麼寫」,而不是「做了不一樣的事」。這也是本系列第 3 天強調過的重點的另一面:測試是行為契約,兩個版本行為契約相同,不代表設計契約相同——這個案例正是用來具體展示這個落差。

兩個版本怎麼產生

  • main branch:用 Outside-In TDD/ATDD 的方式,從 10 個驗收測試出發,一步步往內建立「測試逼出來的」類別,沒有先畫架構藍圖再回頭補測試。這個版本的原則是:如果一段程式碼不是被某個測試逼出來的,它就不應該存在。 最終結果是 3 個檔案、249 行。
  • over-engineered-demo branch:從同一組驗收測試出發,但刻意模擬「AI 拿到一句模糊需求後自由發揮」會產生的樣子——不限制自己只寫測試逼出的東西,而是用常見的專業架構模式(Domain Aggregate、CQRS 的 Command/Query/Handler/Bus、多層 Repository 裝飾器、Specification Pattern、Event-Driven 機制)把整個系統包裝起來,同時預先建好各種「未來可能需要」的功能與欄位。最終結果是 745 個檔案、21,727 行,同樣通過那 10 個一字未改的驗收測試。

為什麼這樣設計能公平對照

這個設計最重要的價值,是把「同一份需求,兩種寫法」這件事變成一個可以重現、可以驗證的對照組,而不是一個口耳相傳的印象或個案抱怨。任何人都可以實際 clone 這個 repo、切換兩個 branch、跑一次測試,親眼確認「兩者確實都通過同一組測試」,而不需要相信我口頭轉述的數字。

這正是本系列想強調的東西:與其空談「AI 容易過度設計」這種印象式的說法,不如做出一個可以重現的具體案例,讓抽象的論點有紮實的證據支撐。 這也呼應本系列的主題句:AI 沒有發明過度設計,它只是讓過度設計的速度追上了你按下 Enter 的速度;Review 要跟得上,審的就不能再是程式碼本身,而是產生程式碼的規則。 而這個案例,正是想具體示範「速度差多少」跟「差在哪裡」。

接下來幾天會看到什麼

  • Day 9:具體看 main 版本的 3 個檔案長什麼樣,Outside-In TDD 怎麼一步步逼出這個結果
  • Day 10:具體看 over-engineered-demo 版本自由發揮出的架構全貌
  • Day 11-13:分別拆解過度設計版本裡最典型的三組手法——多餘的 Repository/UnitOfWork/Specification、用不到的 Event/Listener 機制、讓一次修改要動好幾個檔案的 DTO/Mapper 轉換鏈
  • Day 14-16:回到「兩者都通過測試,但只有一個設計對」這個核心命題,並且討論光讀程式碼、光靠人眼,能不能真的抓出這些問題

今日思考題

如果讓你現在去 review over-engineered-demo 這個版本的一個 PR(假設它是一次性提交,而不是像現在這樣拆成 745 個檔案攤在你面前),你覺得自己在多短的時間內,能不能發現「92% 的程式碼從未被呼叫過」這件事?

今日重點回顧

  • ai-news-test 案例刻意選擇業務邏輯極簡單的題目,目的是排除「業務複雜度不同」這個變數
  • 兩個版本共用同一組 10 個 Given-When-Then 驗收測試、一字未改,把「行為一致」變成可驗證的保證,而不是事後的人工比對
  • main 版本用 Outside-In TDD 只建立測試逼出的類別,over-engineered-demo 版本模擬 AI 自由發揮,用專業架構模式包裝並預先建好假設性功能
  • 這個案例可以被任何人重現驗證,不是口耳相傳的印象或個案抱怨
  • 從明天開始進入逐日拆解,具體看兩個版本的內部結構差異

明日預告

Day 9 要具體攤開 main 版本的 3 個檔案,看 Outside-In TDD/ATDD 是怎麼從 10 個驗收測試,一步步逼出這個乾淨結果的。

老派工程師的心得

做這個案例的過程中,我自己最大的收穫其實不是「證明了 AI 容易過度設計」——這件事我早就在真實工作中隱約感覺到了。真正的收穫是把一個模糊的印象,變成一個可以重複驗證、可以指著具體數字說話的東西。以前跟同事討論「這個系統是不是設計得太複雜」,常常變成各自憑經驗各說各話;現在至少可以指著「業務規則沒變、行數差 87 倍」這種具體對照,讓討論有一個雙方都認的基準線,而不是比誰的架構品味比較高明。


上一篇
Day 7:Code Review 的舊模型為什麼追不上 AI 的產出速度
下一篇
Day 9:版本 A——用 Outside-In TDD/ATDD 寫出來的乾淨版本長怎樣
系列文
當 AI 寫得比你讀得快:Code Review 該審什麼 共 13 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言