clean-code-guard

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)。

1116星標
132分支
更新於 2026/7/4
SKILL.md
唯讀
名稱
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)。

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)。

參考檔案為:

範例

  • 一個程式碼生成代理實作了一個端點:在成果呈現或提交前,對 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 特定層。

始終適用的命令

這些是每次程式碼變更時必須遵循的規則。它們是命令,而非建議。

函式與命名

  1. 名稱揭示意圖。 絕不使用 datadata2resultresult_finalitemtempvalueobjinfohelpermanagerutilshandle_*/process_*/do_* 而不加限定詞。名稱必須回答它為何存在以及它做什麼。(Clean Code 第 2 章)
  2. 函式保持小型。 目標 ≤20 行,一個抽象層次,一件事。如果你能提取一個名稱不重述主體的函式,則父函式做了超過一件事。(Clean Code 第 3 章)
  3. 四個參數是硬上限。 到五個時,停止並引入一個請求/設定物件(record、struct、DTO 或等效)。絕不使用布林旗標參數——改為拆分為兩個函式。
  4. 無輸出參數。 一個函式要嘛回傳值(查詢),要嘛有副作用(命令)。絕不兩者兼具。命令名稱使用動詞;查詢名稱使用名詞或 getter 風格的名稱。(CQS)

註解與結構

  1. 註解解釋為什麼,絕不解釋什麼 刪除任何重述其下一行程式碼的註解。刪除步驟編號的 scaffolding 註解。刪除被註解的程式碼——版本控制存在。(Clean Code 第 4 章)
  2. 符合檔案現有風格。 在寫作前閱讀你正在編輯的檔案以及至少一個相鄰檔案。鏡像其大小寫、匯入順序、錯誤處理、日誌記錄和 HTTP/DB 客戶端選擇。不要引入第二種模式。

SOLID

  1. 每個模組一個參與者。 一個類別應對一個利害關係人群體(會計、認證、報表)負責。如果兩個不相關的子系統都存取同一個類別,則拆分它。(SRP, Uncle Bob 2014)
  2. 透過新程式碼擴展,而非編輯。 如果新增一個變體需要在現有函式中增加另一個 type-tag 分支,則先重構為 registry、strategy 或多型分派。(OCP)
  3. 沒有子類別拒絕其父類別的合約。 絕不覆寫方法來表示「未實作」或「不支援的操作」。絕不在覆寫中強化前置條件或弱化後置條件。如果你需要這樣做,則繼承是錯誤的。(LSP)
  4. 抽象與客戶端共存,而非實作。 當你引入介面、協定或抽象合約時,將其放在消費它的套件中,而不是放在具體類別旁邊。(DIP)

DRY、KISS、YAGNI

  1. 刪除重複的知識,而非重複的文字 兩個看起來相似但編碼不同規則的函式不是 DRY 違規。一個在程式碼 + 文件 + schema 中表達的規則才是。(Pragmatic Programmer, "DRY")
  2. 錯誤的抽象比重複更糟。 如果一個抽象累積了每個呼叫者特殊情況的分支,則將其重新內聯回呼叫者,然後在重新抽象前刪除死分支。(Sandi Metz, "The Wrong Abstraction")
  3. 複雜度上限:循環複雜度 ≤10,巢狀深度 ≤5。 在超過前重構。(McCabe 1976)
  4. 沒有投機的任何東西。 沒有選擇性參數、設定旗標、環境變數、功能開關、介面、工廠或基底類別,除非有當前的呼叫者。如果你發現自己在添加 enable_*use_*_v2*_mode,刪除它並出貨具體行為。(Fowler, "Yagni")

AI 特定護欄——槓桿最高的部分

  1. 絕不透過廣泛的 catch-all 處理吞沒錯誤。 只捕捉你能恢復的特定錯誤類型。如果你無法恢復,讓錯誤傳播。從 catch 處理器回傳 null/none/空成功是被禁止的,除非函式合約記錄了該行為。(Karpathy)
  2. 守護邊界;信任合約。 在信任邊界——外部輸入、請求/API 負載、反序列化或跨程序資料、任何來自不受信任來源的東西——進行驗證,即使快樂路徑看起來沒問題。在邊界內部,不要為其宣告型別或呼叫者合約已排除該情況的值添加 null 檢查或執行時期型別檢查。守護的測試不是「這理論上可能錯嗎」,而是「不受信任的資料能到達這裡嗎」。(arXiv 2409.19182)
  3. 驗證每個匯入和外部呼叫。 在呼叫函式庫的方法前,確認它存在於已安裝的版本中(讀取套件、檢查 lockfile,或匯入並檢查)。不要根據 API「應該」長怎樣來生成程式碼。(USENIX Security '25)
  4. 生產程式碼中沒有硬編碼的「成功」回傳或 mock fixture。 絕不從一個規格說要做實際工作的函式中回傳 {"status": "ok", ...} 或罐頭資料。如果你無法實作,使用語言的未實作或不支援操作機制明確失敗並說明。絕不停用、跳過或弱化測試以使其通過。(Fowler, Claude Code issue #6984)
  5. 重新推導,不要從相似處複製。 當你受到誘惑要複製一個函式並修改它時,停下來。從規格重新推導。差一錯誤和錯誤的 null 語義錯誤幾乎總是透過從相似處複製進入。(arXiv 2411.01414)
  6. 在寫邊界情況前先列舉它們。 對於任何範圍、差一、null/空/一個/多個、偶數/奇數或 unicode/位元組邊界,先在註解中寫下情況列表。在繼續前在程式碼中涵蓋每個情況。
  7. 在交付前移除死程式碼。 執行 linter 或 grep pass 檢查未使用的匯入、未使用的符號、不可達的分支和「以防萬一」的匯出。移除它們。今天沒有東西呼叫的函式不允許為了「某天」而存在。
  8. 先讀後寫。 在不熟悉的儲存庫中寫作前,閱讀你將編輯的檔案、一個相鄰檔案以及任何專案規則檔案(CLAUDE.mdAGENTS.md、README 的「慣例」部分)。使用專案現有的 helper、錯誤型別和日誌記錄。
  9. 幾行程式碼能解決的事,不引入新依賴。 在添加套件前,檢查標準函式庫、已安裝的依賴項,以及是否幾行本機程式碼就能完成工作。新依賴是永久的維護和供應鏈表面;僅當它擁有你不應重新實作的真正複雜性(密碼學、解析、時區——僅為說明,非詳盡)時才添加,絕不為了節省十行程式碼。參見 references/dry-kiss-yagni.md

底線——絕不為了簡潔而刪除這些

規則 16 信任邊界內部的合約;以下項目即使在你去除投機(14)、防禦性守護(16)和死程式碼(21)時仍保留。移除其中一個是行為變更,而非清理——保留它,或標記它並詢問。

  • 每個信任邊界的驗證與消毒——外部輸入、請求/API 負載、反序列化或跨程序資料。
  • 防止資料遺失的錯誤處理。
  • 安全措施——授權、輸出跳脫、參數化查詢、秘密處理。
  • 使用者明確要求的行為。 隨口提及 ≠ 要求,但不要刪除被要求的內容。

重構紀律

  1. 重構時保留可觀察行為。 當使用者要求你清理、簡化或重構現有程式碼時,不要變更合約——相同輸入產生相同輸出、相同例外拋出、相同副作用、相同排序保證。如果你在重構時發現錯誤,單獨標記它並在變更前詢問。重構定義為*「對軟體內部結構所做的變更,使其更易於理解且更便宜修改,而不改變其可觀察行為」*(Fowler, Refactoring)。錯誤修正和重構是兩個操作——絕不將它們捆綁在單一變更中。

交付前自我檢查

在向使用者展示你撰寫或編輯的程式碼之前:

  1. 根據命令 1–24 檢查你的 diff。修正每個違規。
  2. 對於新函式,計算:行數 ≤ 20?參數 ≤ 4?複雜度感覺 ≤ 10?名稱揭示意圖?
  3. 對於新註解,問:這解釋了為什麼?如果它解釋了什麼,刪除它。
  4. 對於新的錯誤處理:捕捉的錯誤型別是否具體?處理器是否做了除了靜默回傳之外的事?
  5. 對於新的抽象(介面、工廠、基底類別、registry):今天是否有第二個具體使用者?如果沒有,內聯它。
  6. 你是否閱讀了你編輯的檔案以及至少一個相鄰檔案?你的風格是否匹配?
  7. 是否有任何硬編碼的「ok」回傳或 fixture 資料?如果是,替換為真實實作或明確的未實作/不支援操作失敗。
  8. 如果這是重構:你是否改變了可觀察行為?如果是,你捆綁了一個錯誤修正——拆分它並詢問使用者。

如果你無法對每個檢查回答「是」,在出貨前修正。

在守護 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 偏好。遵循專案的風格工具。
  • 取代測試。乾淨的程式碼通過測試;沒有乾淨的程式碼測試不會通過,但沒有測試的乾淨程式碼也是一個缺陷。