可維護性審查
標準只有一個:下一個人(不管是人類還是 AI)修改這段程式碼時,需要打開多少個檔案。 不處理正確性錯誤,那是 code-review 或 pr-review 的職責。
0. 模式
| 模式 | 目標 | 比較基準 | blocking 對象 |
|---|---|---|---|
| 自我檢查 | commit 前的自己的 diff | 整個 repo | 直接修改(不回報,立即修正) |
| 變更審查 | PR diff | 整個 repo | 只有本次變更產生的問題 |
| 檢查 | 整個模組或目錄 | 整個 repo | 全部,依影響大小排序 |
在變更審查中,原本就存在的問題不應列為 blocking,而是另外記為「既有技術債」。
1. 讀取專案標準
- 尋找
docs/review/architecture.md。如果沒有,則使用 CLAUDE.md·AGENTS.md 指向的架構文件。 - 專案標準優先於本技能的通用標準。特別是從標準文件中取得:
- 模組地圖與依賴方向
- 應重複使用的抽象化清單(HTTP 客戶端、結果型別、測試輔助工具等)
- 已知的技術債清單。此清單中的模式不應作為新程式碼的遵循範例。
- 若沒有標準文件,則直接根據目錄結構與各模組的
indexexport 繪製模組地圖,並在報告第一行註明「沒有標準文件」。
2. 檢查項目
從最上層開始檢查。越上層的問題,未來修正時成本越高,且 AI Agent 經常忽略。
2-1. 是否繞過既有抽象化機制
AI Agent 通常只關注一個 issue,因此可能不知道先前 issue 所建立的模組,而重複建立相同功能。這是最常見且成本最高的失敗。
對於新增的函式、型別、錯誤類別、常數、外部呼叫,請在 repo 中尋找執行相同功能的程式碼。
git grep -nE "class \w+Error extends" # 錯誤類別
git grep -nE "https?://[a-z.]+\\.(com|io|dev)" # 外部 API 網址與標頭
git grep -nE "^(export )?type \w+ = \{" # 相似名稱的型別(例如:XxxEntry)
git grep -nF "<新程式碼的特徵字串或正則表達式>"
- 如果對同一個外部系統有兩個以上的包裝器,呼叫者將需要檢查不同類別的錯誤。也請一併尋找此類跡象(如
a instanceof X || b instanceof Y)。 - 如果相同的列表常數(副檔名、狀態值)存在於兩個地方,則一個被修改時另一個可能會被遺漏。
2-2. 依賴方向
- 是否違反了標準文件中的層級規則(例如:領域模組匯入了 UI 或外部 API)。
- 子模組是否匯入了父模組,或兩個模組是否互相匯入。
2-3. 單元
根據變更原因而非大小來分割。
- 如果一個檔案中有兩個以上的函式群組彼此不互相呼叫,則表示此檔案有多個變更原因(例如:表單對映 + 巢狀鍵存取 + 日期格式化)。
- 如果多個畫面檔案重複了相同順序的準備過程(認證 → 設定載入 → 錯誤分支),則該過程應提取為一個有名字的函式。
2-4. 抽象化品質
- 缺少的 API:如果兩個以上的呼叫者重複相同的預處理或後處理,則表示模組中缺少一個包含該處理的函式。例如:所有呼叫者在
doc.items.find((s) => s.kind === "x")之後都呼叫parseX(...),則應有一個readX(doc)函式。 - 過度的抽象化:只有一個使用者的介面、工廠、選項、泛型。這些是目前不需要的擴充點。
- 邊界型別:如果失敗必須由呼叫者處理,是否以結果型別(判別聯集)呈現?呼叫者是否在比較訊息字串來進行分支?
2-5. 模式
- 是否遵循了 repo 已使用的模式(結果型別、依賴注入、錯誤處理、模組匯出方式)。
- 新模式僅在既有模式無法滿足需求時才應被接受。如果 PR 或註解中沒有說明理由,則應指出。
2-6. 註解與命名
- 註解是否貼在錯誤的對象上。修改 commit 可能在函式之間插入新函式,導致 JSDoc 停留在其他函式上方,這是常見的錯誤。
- 名稱是否與其行為相符。如果看到名稱會讓人預期不同的行為,則應指出。
3. 判定
blocking(不應合併)
- 已經存在負責相同功能的程式碼,卻又新建立了一個。如果 PR 或註解中說明了無法使用既有程式碼的原因,則除外。
- 違反了標準文件中的層級規則。
- 新 API 導致兩個以上的呼叫者重複相同的處理。
- 註解貼在錯誤的對象上,誤導閱讀者。
suggestion(不阻止合併,但留下後續工作)
- 檔案分割、名稱改善、既有的重複。
不列入的項目:個人偏好(函數式或命令式、行長度)、linter 與 formatter 會處理的項目、超出 issue 範圍的新函式庫引入。
4. 驗證
每個指出問題的項目都必須用程式碼確認。不正確的指出會浪費實作 AI Agent 的時間。
- 如果是「重複」,則打開兩個位置,確認它們真的在做相同的事。即使外觀相似,如果遵守的規格不同,則應排除。
- 如果是「N 個地方」,則用 grep 計算。
- 如果是「本次變更產生的」,則檢查
git diff <base>...HEAD中是否有該行。
5. 報告
第一行:檢查範圍(模式、目標路徑、是否有標準文件)與數量(blocking N 個、suggestion N 個、既有技術債 N 個)。
每個項目:
- 標題:以結果說明是什麼造成了成本。("GitHub 401 被呼叫者以 3 個錯誤類別分別檢查" ○ / "錯誤處理改善" ×)
- 位置:所有相關位置以
檔案:行號表示。若是重複,則標示雙方。 - 成本:下次要修改什麼時,需要修改多少個檔案。("要修改 API 版本標頭時,需要修改 3 個檔案")
- 方向:一兩句話說明應朝哪個方向合併。
- 等級:blocking / suggestion / 既有技術債。
如果沒有要指出的問題,則寫「無」。不要為了湊數而指出問題。
不應該做的事
- 僅根據行數或檔案大小要求分割。
- 沒有方向的指出(如「最好能再多做抽象化」)。
- 將僅外觀相似的程式碼說成重複。
- 將原本存在的問題列為本次 PR 的 blocking。