BrainPad股份有限公司產品開發部中負責開發 Rtoaster GenAI 的依田。
讓 Claude Code 撰寫 Design doc 或 PR 時,你是否曾覺得「資訊量很多,卻很難看出最後決定了什麼」?我有很多次這種感受。只要讀的時候稍微分心,就會漏掉最想知道的結論。那種獨特的疲勞感究竟從何而來,我實際用 GitHub PR 來驗證了一下。
內容並不是錯的。相反地,大多數時候都寫得沒問題。即便如此還是會累,我認為原因可歸納為以下 4 點。
不區分完整性與重要度。人類寫 Design doc 時,會在腦中不自覺地做取捨:「這個應該寫」「這個可以省略」。生成式 AI 不太會做這種篩選,會把想到的觀點全部用同樣的權重列出來。結果就是關鍵的判斷與理所當然的前提被用同等篇幅說明,讀者得自己負責分辨重要程度。
結論放在最後。人類作者常會先直接說「結論來說~」,但生成式 AI 往往會先依序重現檢討過程,最後才在總結裡寫出結論。讀者在抵達結論之前,必須把所有資訊一直留在腦中。
老實填滿模板標題。像是「背景」「目的」「用語定義」「未來擴充性」這類固定標題,一旦使用過,即使內容很薄也會很認真地補滿。標題越多,讀者就越有「非讀不可」的壓力。
連顯而易見的項目也要正反並列。一旦採用「優點/缺點」這種格式,對於根本沒被採用的方案,也會機械式套用同樣格式。即使是從需求一看就知道不成立的方案,也會附上很完整的說明。
光用文字說明不太容易有感,所以我實際動手確認了一下。
題材是 EC 網站購物車的折扣優惠券套用邏輯。需求如下:
只指定要以 DDD(領域驅動設計)/OOP(物件導向)的方式實作,並沒有指定 Design doc 的寫法。
我會讓同一個需求分別以「沒有特別優化的 Skill」與「有調整 Design doc 寫法的 Skill」來實作,比對實際的 PR。
Skill 的內容只是把「讀 Issue、寫 Design doc、實作、建立 PR」這個流程排起來而已。
請在 Design doc 中詳細記載你所檢討過的設計方針及其背景、優點與缺點。
請寫得即使不是實作者的人也能看懂設計意圖。
這個 Skill 產生的 Design doc、實作與 PR 如下。
連適用條件採用 Specification pattern(將條件表現為物件的設計模式)這一個判斷,都會以這種方式把優點與缺點並列。
### 以 Specification pattern 表現適用條件
將優惠券的適用條件(最低消費金額、有效期限、適用分類)分別實作成獨立的 Specification
類別,並以 `AndSpecification` 組合。
**優點**:
- 每個條件都是獨立的類別,因此可以遵守單一職責原則
- 新增新的適用條件時,不需要修改既有條件類別,因此可以遵守開放封閉原則
- 可以彈性表現條件組合(AND/OR)
**缺點**:
- 會因條件數量增加而導致類別變多,檔案數與程式碼量也會增加
- 相較於單純的 if 敘述串接,間接參照變多,可能提高追蹤程式碼的成本
甚至還老老實實列出 4 個沒被採用的替代方案,其中一個如下:
### 替代方案 4:在可否併用的判定中導入優先順序欄位
讓每張優惠券帶有優先順序(priority)欄位,在不可併用時採用優先順序
最高的優惠券。
**優點**:
- 不論折扣金額大小,營運端都能明確指定希望優先套用的優惠券
**缺點**:
- 本 Issue 的需求明確寫著要「採用折扣金額最大的優惠券」,導入優先順序欄位會與需求產生落差
- 會產生管理優先順序這項新的營運成本
這個替代方案因為不符合需求中明訂的「採用折扣金額最大的優惠券」規則,所以不採用。
連從需求一看就知道不成立的方案,也分配了和採用方案同樣篇幅的說明。這正是前面提到的「對顯而易見的項目也要正反並列」的直接體現。就這樣,「用語定義」「未來擴充性」等章節也一路排下去,Design doc 膨脹到 284 行、8521 字、32 個標題。PR 說明文也有 1232 字,還很老實地列出了實作檔案清單。
程式碼本身是正確運作的。實際上,生成的程式碼透過了 pytest 的 24 個測試,全數 PASS,功能上沒有問題。這次真正想討論的是,讓人類去追理解設計判斷的文件分量。
讀起來會累,原因不是資訊錯誤,而是「到底採用了哪個方案、為什麼」這個最想知道的資訊,被沒採用的選項說明,以及顯而易見的優缺點列表給埋掉了。即使讀完,也還是得花時間才能撿出結論。
我在同一個 Skill 裡,加入了關於 Design doc 與 PR 寫法的指南。對應前面提到的 4 個原因,逐一處理。
## Design doc 的寫法
- 在開頭 3 行內先寫結論(採用的設計與理由),細節之後再補
- 將檢討過的替代方案用表格比較(方案、淘汰理由兩欄就夠了,不要每次都用文章把優點/缺點寫一遍)
- 沒採用的選項,只保留能傳達淘汰理由的最小必要長度
- 寫出「不做什麼(Non-goals)」,不要羅列範圍外的一般論或未來擴充可能性
- 只有在讀者可能不知道該技術名詞時,才寫用語定義、背景、目的、對象讀者這類固定章節;若屬理所當然則省略
- 只在有意義的單位建立標題,不要用多個標題重複相同內容
- 不確定時就刪減。寫完後先問自己:「即使沒有這個段落,審查者是否仍能理解決策?」若可以,就刪掉
「Non-goals」是為了避免把完整性與重要度混為一談;「結論先寫」是對應結論放最後的問題;「只在必要時才寫用語定義等固定章節」是為了抑制老實填滿模板標題的傾向;「替代方案用表格」則是為了避免對顯而易見的項目也正反並列。
同一個 Issue、同一個實作內容,重做之後的結果如下(實作與 #5 完全相同,方便只比較 Design doc 和 PR 的寫法)。
原本 4 個替代方案,被整理成 1 個表格。
## 檢討過的替代方案
| 方案 | 淘汰理由 |
|---|---|
| 直接用 if-else 判定適用條件 | 條件越多,單一函式越容易膨脹,而且難以對每個條件做單元測試 |
| 驗證函式集合(不使用 Specification) | 無法持有條件的狀態(例如最低金額的數值),需要 closure,反而更難閱讀 |
| 規則引擎(用外部 DSL 定義條件) | 雖然非工程人員可以修改條件,但對這次的需求規模來說過度設計 |
| 透過優先順序欄位判定可否併用 | 需求明確寫著要「採用折扣金額最大的優惠券」,優先順序欄位與需求不符 |
只要讀「結論」,3 行內就能知道採用了什麼設計與理由;看替代方案表格,也能一眼看出淘汰理由。像用語定義、對象讀者這些固定章節則省略了。雖然有用到 Specification pattern、Strategy pattern 這些詞,但因為判斷這篇文章的讀者應該不用額外解釋也看得懂,所以就省略了說明。
以下整理在相同需求、相同實作內容下,Design doc 與 PR 說明文有多大的變化。
項目Before(#5)After(#6)Design doc 行數284 行41 行Design doc 字數8521 字1239 字Design doc 標題數32 個6 個PR description 字數1232 字396 字Design doc 在行數與字數上都變成了約 7 倍,PR 說明文也大約差了 3 倍。實作內容一字不差,因此這些差異全部來自「文件寫法」。
根據這次比較,我整理出在讓 AI 撰寫 Design doc/PR 的 Skill 裡,值得加入的內容。若依照前面提到的「疲憊原因」來重新整理,會變成以下幾項:
這些都不是特別高明的技巧。只是,如果不明確寫進 Skill 裡,生成式 AI 就會傾向往「盡量完整」的方向寫。這是這次實驗得到的感受。
讀生成式 AI 的文章會疲憊,原因不在於內容正確與否,而是它有 4 個習慣:不篩選重要度、把結論往後放、老實填滿模板、以及對顯而易見的項目也要正反並列。即使是同一個需求,只要在 Skill 中明確指定如何處理這些問題,Design doc 的篇幅就能變成將近 7 倍的差距。當你覺得不想再讀 AI 的輸出時,與其先懷疑 AI 的內容,不如先檢視 Skill 或 prompt 是否有指定「不要寫什麼」。
這次使用的 Issue 和兩個 PR 都保留在原始倉庫中。有興趣的人可以實際比對 Design doc 與 PR 說明文。
這裡是 Before/After 各自實際使用的 SKILL.md 全文。
Before(未優化版)
After(改善版)