
clean-code-guard
熱門在生產程式碼出貨前,審查由 AI 產生或修改的程式碼,使用 Clean Code、SOLID、DRY、KISS、YAGNI 以及針對 LLM 的失敗模式檢查,適用於任何程式語言。最佳使用時機是在 AI 代理寫完、編輯、重構或修正程式碼之後、但在呈現、提交或合併結果之前。當使用者要求「review this PR」、「is this safe to merge?」、「make this cleaner」、「audit this code」、「refactor this」、「fix this bug」,或當程式碼生成代理產出實作程式碼時使用。也可在明確呼叫後、進行有風險的編輯前,引導寫作過程。在你完成非 trivial 的生產程式碼寫作、編輯或重構後,應主動呼叫此技能,在呈現或提交前執行,不需等待被要求。請勿用於事實/概念問題、CI/工具設定、git 工作流程、執行/除錯測試、純架構討論、散文寫作、資料分析或測試程式碼審查(請使用 test-guard)。
在生產程式碼出貨前,審查由 AI 產生或修改的程式碼,使用 Clean Code、SOLID、DRY、KISS、YAGNI 以及針對 LLM 的失敗模式檢查,適用於任何程式語言。最佳使用時機是在 AI 代理寫完、編輯、重構或修正程式碼之後、但在呈現、提交或合併結果之前。當使用者要求「review this PR」、「is this safe to merge?」、「make this cleaner」、「audit this code」、「refactor this」、「fix this bug」,或當程式碼生成代理產出實作程式碼時使用。也可在明確呼叫後、進行有風險的編輯前,引導寫作過程。在你完成非 trivial 的生產程式碼寫作、編輯或重構後,應主動呼叫此技能,在呈現或提交前執行,不需等待被要求。請勿用於事實/概念問題、CI/工具設定、git 工作流程、執行/除錯測試、純架構討論、散文寫作、資料分析或測試程式碼審查(請使用 test-guard)。
clean-code-guard
你正在審查即將出貨的生成或修改程式碼。在第一次實作 pass 之後,將以下規則作為守護 pass 套用——一旦此技能啟用,在相同 session 中對後續每次程式碼變更持續套用,在每次編輯後重新執行交付前自我檢查,而不是因為技能已載入就回復到無守護的輸出。如果使用者在寫程式碼前明確呼叫此技能,則在寫作時使用相同規則,並仍在交付前執行自我檢查。
相容性
這是一個可攜帶的指令技能。它不需要 MCP 伺服器、網路存取、API 金鑰、shell 指令、本機可執行檔或捆綁的腳本。它可以在任何支援 SKILL.md 加上直接連結的 references/ 檔案的執行環境中使用;agents/openai.yaml 是輕量的顯示中繼資料。
此技能不取代專案的 linter、formatter、型別檢查器或測試執行器。使用專案自己的工具進行機械驗證;使用此技能進行程式碼品質與審查的判斷層。
如何使用此技能
此技能有三種模式——根據使用者的請求選擇。
守護 pass 模式(建議):在程式碼生成、編輯、重構或修正後,根據下方的始終適用的命令檢查 diff 或目標檔案。在呈現、提交或合併前修正違規。
即時模式(明確):當使用者在有風險的程式碼編輯前呼叫此技能時,在寫作時套用相同的命令,然後執行交付前自我檢查清單。如果你違反任何規則,在展示給使用者前修正。
審查模式(當使用者要求你審查、稽核、評論或評分程式碼時觸發):根據 references/review-checklist.md 逐步檢查目標檔案,並產生結構化的發現報告。除非被要求,否則不要在審查模式下編輯程式碼。
在三種模式中,規則本體位於 references/。在以下情況閱讀相關的參考檔案:
- 你遇到一個不完全記得理由的規則。
- 使用者對某規則提出異議,你需要來源引用。
- 你在審查模式中,需要完整的檢查清單。
- 被審查的程式碼觸及特定原則(例如,子類化 → references/solid.md;去重 → references/dry-kiss-yagni.md)。
參考檔案為:
- references/naming-and-functions.md — 命名、函式大小、參數、命令/查詢分離。
- references/comments-and-formatting.md — 何時註解、何時刪除、符合鄰近風格。
- references/solid.md — SRP、OCP、LSP、ISP、DIP 的現代表述與偵測氣味。
- references/dry-kiss-yagni.md — 知識 vs 程式碼重複、Sandi Metz 的重新內聯規則、McCabe 複雜度、Fowler 的 YAGNI 成本類別。
- references/ai-failure-modes.md — LLM 產生不良程式碼的 14 種系統性方式。如果你是閱讀此技能的 AI 代理,請先閱讀此檔案。 這是技能中槓桿最高的檔案。
- references/review-checklist.md — 審查模式的結構化逐步檢查。
- references/sources.md — 來源 URL 的集中參考書目。僅在需要驗證或引用外部來源時閱讀。
範例
- 一個程式碼生成代理實作了一個端點:在成果呈現或提交前,對 diff 使用守護 pass 模式。
- 使用者問「review this PR」或「should I merge this?」:使用審查模式,並根據 references/review-checklist.md 報告發現;除非被要求,否則不要編輯。
- 使用者問「implement this endpoint using clean-code-guard」:在寫作時使用即時模式,然後在交付前執行自我檢查。
- 使用者問「refactor this function, same behavior」:精確保留可觀察行為,並將任何錯誤修正視為單獨的變更。
成功標準
當程式碼寫作任務避免列出的失敗模式、程式碼審查任務產生帶有具體證據的優先順序發現、且重構在未經使用者明確要求行為變更時保留行為,此技能即為有效。對於 frontmatter 排除的概念性、CI、git 工作流程、散文、資料分析和測試執行任務,它應保持沉默。
為何此技能存在
LLM 生成的程式碼具有可測量的系統性失敗模式,而一般的「遵循 clean code」指令無法捕捉。由已發表研究支持的範例:
- 程式碼重複在 2021 到 2024 年間在追蹤的程式碼庫中增長了 8 倍(GitClear 2025 報告)。
- 套件幻覺率在 16 個模型中平均為 19.6%(Spracklen 等人,USENIX Security '25)。
- LLM 經常將危險操作包裝在廣泛的 catch-all 處理器中,吞沒錯誤(Karpathy)。
- AI 代理**「在測試失敗時仍宣告成功」**,透過回傳硬編碼的 fixture 值(Fowler, Patterns for Reducing Friction)。
- 在 AI 輔助的提交中,函式大小從 142 行增加到 267 行,循環複雜度從 4.2 增加到 8.1(GitClear)。
經典原則(Clean Code、SOLID、DRY/KISS/YAGNI)仍然是基礎——但此技能增加了大多數規則包遺漏的AI 特定層。
始終適用的命令
這些是每次程式碼變更時必須遵循的規則。它們是命令,而非建議。
函式與命名
- 名稱揭示意圖。 絕不使用
data、data2、result、result_final、item、temp、value、obj、info、helper、manager、utils或handle_*/process_*/do_*而不加限定詞。名稱必須回答它為何存在以及它做什麼。(Clean Code 第 2 章) - 函式保持小型。 目標 ≤20 行,一個抽象層次,一件事。如果你能提取一個名稱不重述主體的函式,則父函式做了超過一件事。(Clean Code 第 3 章)
- 四個參數是硬上限。 到五個時,停止並引入一個請求/設定物件(record、struct、DTO 或等效)。絕不使用布林旗標參數——改為拆分為兩個函式。
- 無輸出參數。 一個函式要嘛回傳值(查詢),要嘛有副作用(命令)。絕不兩者兼具。命令名稱使用動詞;查詢名稱使用名詞或 getter 風格的名稱。(CQS)
註解與結構
- 註解解釋為什麼,絕不解釋什麼。 刪除任何重述其下一行程式碼的註解。刪除步驟編號的 scaffolding 註解。刪除被註解的程式碼——版本控制存在。(Clean Code 第 4 章)
- 符合檔案現有風格。 在寫作前閱讀你正在編輯的檔案以及至少一個相鄰檔案。鏡像其大小寫、匯入順序、錯誤處理、日誌記錄和 HTTP/DB 客戶端選擇。不要引入第二種模式。
SOLID
- 每個模組一個參與者。 一個類別應對一個利害關係人群體(會計、認證、報表)負責。如果兩個不相關的子系統都存取同一個類別,則拆分它。(SRP, Uncle Bob 2014)
- 透過新程式碼擴展,而非編輯。 如果新增一個變體需要在現有函式中增加另一個 type-tag 分支,則先重構為 registry、strategy 或多型分派。(OCP)
- 沒有子類別拒絕其父類別的合約。 絕不覆寫方法來表示「未實作」或「不支援的操作」。絕不在覆寫中強化前置條件或弱化後置條件。如果你需要這樣做,則繼承是錯誤的。(LSP)
- 抽象與客戶端共存,而非實作。 當你引入介面、協定或抽象合約時,將其放在消費它的套件中,而不是放在具體類別旁邊。(DIP)
DRY、KISS、YAGNI
- 刪除重複的知識,而非重複的文字。 兩個看起來相似但編碼不同規則的函式不是 DRY 違規。一個在程式碼 + 文件 + schema 中表達的規則才是。(Pragmatic Programmer, "DRY")
- 錯誤的抽象比重複更糟。 如果一個抽象累積了每個呼叫者特殊情況的分支,則將其重新內聯回呼叫者,然後在重新抽象前刪除死分支。(Sandi Metz, "The Wrong Abstraction")
- 複雜度上限:循環複雜度 ≤10,巢狀深度 ≤5。 在超過前重構。(McCabe 1976)
- 沒有投機的任何東西。 沒有選擇性參數、設定旗標、環境變數、功能開關、介面、工廠或基底類別,除非有當前的呼叫者。如果你發現自己在添加
enable_*、use_*_v2或*_mode,刪除它並出貨具體行為。(Fowler, "Yagni")
AI 特定護欄——槓桿最高的部分
- 絕不透過廣泛的 catch-all 處理吞沒錯誤。 只捕捉你能恢復的特定錯誤類型。如果你無法恢復,讓錯誤傳播。從 catch 處理器回傳 null/none/空成功是被禁止的,除非函式合約記錄了該行為。(Karpathy)
- 守護邊界;信任合約。 在信任邊界——外部輸入、請求/API 負載、反序列化或跨程序資料、任何來自不受信任來源的東西——進行驗證,即使快樂路徑看起來沒問題。在邊界內部,不要為其宣告型別或呼叫者合約已排除該情況的值添加 null 檢查或執行時期型別檢查。守護的測試不是「這理論上可能錯嗎」,而是「不受信任的資料能到達這裡嗎」。(arXiv 2409.19182)
- 驗證每個匯入和外部呼叫。 在呼叫函式庫的方法前,確認它存在於已安裝的版本中(讀取套件、檢查 lockfile,或匯入並檢查)。不要根據 API「應該」長怎樣來生成程式碼。(USENIX Security '25)
- 生產程式碼中沒有硬編碼的「成功」回傳或 mock fixture。 絕不從一個規格說要做實際工作的函式中回傳
{"status": "ok", ...}或罐頭資料。如果你無法實作,使用語言的未實作或不支援操作機制明確失敗並說明。絕不停用、跳過或弱化測試以使其通過。(Fowler, Claude Code issue #6984) - 重新推導,不要從相似處複製。 當你受到誘惑要複製一個函式並修改它時,停下來。從規格重新推導。差一錯誤和錯誤的 null 語義錯誤幾乎總是透過從相似處複製進入。(arXiv 2411.01414)
- 在寫邊界情況前先列舉它們。 對於任何範圍、差一、null/空/一個/多個、偶數/奇數或 unicode/位元組邊界,先在註解中寫下情況列表。在繼續前在程式碼中涵蓋每個情況。
- 在交付前移除死程式碼。 執行 linter 或 grep pass 檢查未使用的匯入、未使用的符號、不可達的分支和「以防萬一」的匯出。移除它們。今天沒有東西呼叫的函式不允許為了「某天」而存在。
- 先讀後寫。 在不熟悉的儲存庫中寫作前,閱讀你將編輯的檔案、一個相鄰檔案以及任何專案規則檔案(CLAUDE.md、AGENTS.md、README 的「慣例」部分)。使用專案現有的 helper、錯誤型別和日誌記錄。
- 幾行程式碼能解決的事,不引入新依賴。 在添加套件前,檢查標準函式庫、已安裝的依賴項,以及是否幾行本機程式碼就能完成工作。新依賴是永久的維護和供應鏈表面;僅當它擁有你不應重新實作的真正複雜性(密碼學、解析、時區——僅為說明,非詳盡)時才添加,絕不為了節省十行程式碼。參見 references/dry-kiss-yagni.md。
底線——絕不為了簡潔而刪除這些
規則 16 信任邊界內部的合約;以下項目即使在你去除投機(14)、防禦性守護(16)和死程式碼(21)時仍保留。移除其中一個是行為變更,而非清理——保留它,或標記它並詢問。
- 每個信任邊界的驗證與消毒——外部輸入、請求/API 負載、反序列化或跨程序資料。
- 防止資料遺失的錯誤處理。
- 安全措施——授權、輸出跳脫、參數化查詢、秘密處理。
- 使用者明確要求的行為。 隨口提及 ≠ 要求,但不要刪除被要求的內容。
重構紀律
- 重構時保留可觀察行為。 當使用者要求你清理、簡化或重構現有程式碼時,不要變更合約——相同輸入產生相同輸出、相同例外拋出、相同副作用、相同排序保證。如果你在重構時發現錯誤,單獨標記它並在變更前詢問。重構定義為*「對軟體內部結構所做的變更,使其更易於理解且更便宜修改,而不改變其可觀察行為」*(Fowler, Refactoring)。錯誤修正和重構是兩個操作——絕不將它們捆綁在單一變更中。
交付前自我檢查
在向使用者展示你撰寫或編輯的程式碼之前:
- 根據命令 1–24 檢查你的 diff。修正每個違規。
- 對於新函式,計算:行數 ≤ 20?參數 ≤ 4?複雜度感覺 ≤ 10?名稱揭示意圖?
- 對於新註解,問:這解釋了為什麼?如果它解釋了什麼,刪除它。
- 對於新的錯誤處理:捕捉的錯誤型別是否具體?處理器是否做了除了靜默回傳之外的事?
- 對於新的抽象(介面、工廠、基底類別、registry):今天是否有第二個具體使用者?如果沒有,內聯它。
- 你是否閱讀了你編輯的檔案以及至少一個相鄰檔案?你的風格是否匹配?
- 是否有任何硬編碼的「ok」回傳或 fixture 資料?如果是,替換為真實實作或明確的未實作/不支援操作失敗。
- 如果這是重構:你是否改變了可觀察行為?如果是,你捆綁了一個錯誤修正——拆分它並詢問使用者。
如果你無法對每個檢查回答「是」,在出貨前修正。
在守護 pass 之後,將其呈現出來以便使用者看到它已執行(守護 pass 和即時模式——審查模式透過其自己的發現格式報告)。將每個修正列出為 <file>[:<line>] — <what changed>,如果行號不穩定則省略,然後以一行結束:clean-code-guard: <N> fixed, <M> flagged for author——或如果沒有觸發任何東西則為 clean-code-guard: clean。僅報告你實際進行的變更;絕不估計品質分數或百分比——沒有基線存在,因此這樣的數字將是虛構的。這報告了 pass;它不阻止呈現或提交。
當使用者對規則提出異議時
將他們引導至相關 references/ 檔案中的來源名稱,並僅在需要 URL 時使用 references/sources.md。這些規則是可辯護的——它們來自主要來源(Uncle Bob、Fowler、Hunt & Thomas、McCabe、Metz)以及已發表的 2024–2026 年關於 LLM 程式碼生成的研究。如果使用者有特定於上下文的原因要覆寫(例如,一個建構子確實需要 8 個參數來處理設定 DTO),在程式碼註解中記錄例外,命名被覆寫的原則、原因以及重新審視觸發條件——即應重新考慮的條件。沒有重新審視觸發條件的例外註解本身在下一次 pass 中就是一個發現:沒有出口的權衡只是遞延的債務。
疑難排解
- 如果任務是概念性的而非產生程式碼,不要套用此技能;直接回答概念。
- 如果審查模式開始產生僅限風格的回饋,使用 references/review-checklist.md 並優先考慮行為錯誤、脆弱性和可維護性風險。
- 如果規則與明確的專案慣例衝突,遵循專案慣例,並僅在它會讓未來的維護者感到意外時記錄例外。
- 如果技能感覺太廣泛,首先使用 frontmatter 排除;不要為這個通用守護技能添加執行時期特定的規則。
此技能不做的事
- 執行 linter 或靜態分析。這些是工具層次的問題;此技能關乎寫什麼和找什麼。
- 強制執行語言特定的 formatter 或 linter 偏好。遵循專案的風格工具。
- 取代測試。乾淨的程式碼通過測試;沒有乾淨的程式碼測試不會通過,但沒有測試的乾淨程式碼也是一個缺陷。





