mcpField
C
clean-code-guard

clean-code-guard

github.com/sickn33测试与质量48.7k44 次安装今天更新
代码仓库

关于 clean-code-guard

clean-code-guard 是用于代码变更审查的便携式技能,面向编码 Agent 和开发者,在交付前检查代码质量,并针对 AI 生成代码列出专门防护规则。

主要功能

  1. 01提交前检查代码变更
  2. 02支持守护、实时和审查模式
  3. 03提供结构化审查清单
  4. 04针对 AI 代码失误设防
  5. 05强调保留既有行为

适用场景

  1. 01检查编码 Agent 生成的代码
  2. 02审查合并请求并报告问题
  3. 03在修改代码时应用质量规则
  4. 04重构时确认行为保持不变

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/sickn33/agentic-awesome-skills --skill clean-code-guard

安装后在 Claude Code 中输入/clean-code-guard确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
comments-and-formatting.md
dry-kiss-yagni.md
review-checklist.md
naming-and-functions.md
sources.md
solid.md
ai-failure-modes.md

详细介绍

clean-code-guard

你正在代码发布前审查生成或变更的代码。在首次实现完成后,将以下规则作为一次防护检查来应用——并且一旦此技能处于激活状态,就在同一会话中持续将其应用于之后的每一次代码变更,在每次编辑后、交付前重新运行自检,而不是因为该技能是较早加载的就退回到无防护的输出。如果用户在编写代码前明确调用此技能,则在编写时使用相同规则,并且仍在交付前运行自检。

何时使用

在代码发布前审查生成或变更的代码时使用此技能。在 Agent 编写、编辑或重构生产代码后被动激活它——尤其是在首次实现完成后。在每次编辑后、交付前重新运行防护检查。

兼容性

这是一个可移植的指令技能。它不需要 MCP 服务、网络访问、API key、shell 命令、本地可执行文件或捆绑脚本。它可用于任何支持 SKILL.md 以及直接链接的 references/ 文件的运行时;agents/openai.yaml 是轻量级展示元数据。

此技能不能替代项目 linter、格式化工具、类型检查器或测试运行器。使用项目自身的工具进行机械性验证;使用此技能处理围绕代码质量和审查的判断层。

如何使用此技能

此技能有三种模式——根据用户的请求选择。

防护检查模式(推荐):在代码已生成、编辑、重构或修复后,对照下方的始终适用的强制性要求检查 diff 或目标文件。在展示、提交或合并工作成果之前修复违规项。

实时模式(显式):当用户在 risky 的代码编辑前调用此技能时,在编写时应用相同的强制性要求,然后运行交付前自检清单。如果你违反了任何规则,在向用户展示前修复它。

审查模式(当用户要求你审查、审计、点评或评分代码时触发):对照目标文件逐一执行 references/review-checklist.md,并生成结构化的发现报告。除非被要求,否则不要在审查模式中编辑代码。

在所有三种模式中,规则正文位于 references/。在以下情况下阅读相关参考文件:

  • 你遇到一条不完全记得其理由的规则。
  • 用户对某条规则提出异议,而你需要来源引用。
  • 你处于审查模式,需要完整清单。
  • 被审查的代码涉及某个特定原则(例如,子类化 → references/solid.md;去重 → references/dry-kiss-yagni.md)。

参考文件包括:

示例

  • 编码 Agent 实现一个端点:在成果被展示或提交之前,对 diff 使用 guard-pass 模式。
  • 用户问"审查这个 PR"或"我应该合并这个吗?":使用审查模式,并报告来自 references/review-checklist.md 的发现;除非被要求,否则不要编辑。
  • 用户问"用 clean-code-guard 实现这个端点":在编写过程中使用实时模式,然后在交付前运行自检。
  • 用户问"重构这个函数,保持行为不变":完全保留可观察行为,并将任何缺陷修复视为单独的变更。

成功标准

当编写代码的任务避开了所列的失败模式,代码审查任务产出带有具体证据的按优先级排序的发现,并且重构在用户未明确要求行为变更时保持行为不变,此技能即为生效。对于 frontmatter 排除项所涵盖的概念性、CI、git 工作流、散文、数据分析和测试运行任务,它应保持沉默。

此技能为何存在

大模型生成的代码具有可衡量的、系统性的失败模式,通用的"遵循整洁代码"指令无法捕捉到。以下是有已发表研究支持的示例:

  • 代码重复增长了 8 倍,在被跟踪的代码库中,2021 年至 2024 年间(GitClear 2025 报告)。
  • 包幻觉率平均为 19.6%,跨越 16 个模型(Spracklen 等,USENIX Security '25)。
  • 大模型经常将高风险操作包裹在宽泛的 catch-all 处理程序中,从而吞掉错误(Karpathy)。
  • AI Agent "尽管测试失败仍宣称成功",通过返回硬编码的 fixture 值(Fowler,Patterns for Reducing Friction)。
  • 在 AI 辅助的提交中,函数规模从 142 增至 267 LoC,圈复杂度从 4.2 增至 8.1(GitClear)。

经典原则(Clean Code、SOLID、DRY/KISS/YAGNI)仍然是基础——但此技能增加了大多数规则包所遗漏的AI 专属层。

始终适用的强制要求

以下是每次代码变更时都要遵循的规则。它们是强制性的,而非建议。

函数与命名
  1. 名称揭示意图。 在没有限定词的情况下,绝不使用 data、data2、result、result_final、item、temp、value、obj、info、helper、manager、utils 或 handle_*/process_*/do_*。名称必须回答它为何存在以及它做什么。(Clean Code 第 2 章)
  2. 函数保持小巧。 目标 ≤20 行,一个抽象层级,只做一件事。如果你能提取出一个名称不会重述其函数体的函数,那么父函数就在做不止一件事。(Clean Code 第 3 章)
  3. 四个参数是硬性上限。 到了五个,停下来并引入请求/配置对象(record、struct、DTO 或等效物)。绝不使用布尔标志参数——改为拆分成两个函数。
  4. 没有输出参数。 一个函数要么返回值(查询),要么有副作用(命令)。绝不两者兼有。命令名称使用动词;查询名称使用名词或 getter 风格的名称。(CQS)
注释与结构
  1. 注释解释为什么,绝不解释是什么。 删除任何对其下方代码行进行转述的注释。删除步骤编号脚手架注释。删除被注释掉的代码——版本控制是存在的。(Clean Code 第 4 章)
  2. 匹配文件现有的风格。 在编写之前,阅读你正在编辑的文件以及至少一个相邻文件。镜像其大小写、导入顺序、错误处理、日志记录以及 HTTP/DB 客户端的选择。不要引入第二种模式。
SOLID
  1. 每个模块只服务一个参与者。 一个类应当只对一个利益相关方群体(会计、认证、报表)负责。如果两个不相关的子系统都伸手进入同一个类,就把它拆开。(SRP,Uncle Bob 2014)
  2. 通过新增代码扩展,而非修改代码。 如果新增一个变体需要在现有函数中再加一个类型标签分支,那就要先重构成注册表、策略或[多态]分派。(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 处理程序中返回 null/none/空成功,除非函数契约明确记载了该行为。(Karpathy)
  2. 守住边界;信任契约。 在信任边界处 —— 外部输入、请求/API 载荷、反序列化或跨进程数据、任何来自不可信来源的内容 —— 都要校验,即使正常路径看起来没问题。在边界内部,不要为声明类型或调用方契约已排除该情况的值添加 null 检查或运行时类型检查。判断是否需要防护的标准不是“这理论上会不会出错”,而是“不可信数据能否到达这里”。(arXiv 2409.19182)
  3. 验证每一个导入和外部调用。 在调用某个库的方法之前,确认它存在于所安装的版本中(阅读包源码、检查 lockfile,或导入并检查)。不要基于 API “应该”长什么样来生成代码。(USENIX Security '25)
  4. 生产代码中不得硬编码“成功”返回或 mock 数据。 绝不要从规格说明其执行真实工作的函数中返回 {"status": "ok", ...} 或预制数据。如果无法实现,就用该语言的未实现或不受支持操作机制显式失败,并如实说明。绝不要为了让测试通过而禁用、跳过或削弱测试。(Fowler,Claude Code issue #6984)
  5. 重新推导,不要从相似代码复制。 当你想复制一个函数再修改时,停下来。从规格说明重新推导。差一错误和错误 null 语义的缺陷几乎总是通过从相似代码复制引入的。(arXiv 2411.01414)
  6. 在编写之前先枚举边界情况。 对于任何范围、差一、null/空/单元素/多元素、奇偶或 unicode/字节边界,先在注释中写出情况列表。在继续之前,在代码中覆盖每一种情况。
  7. 交付前清除死代码。 运行 linter 或 grep 检查未使用的导入、未使用的符号、不可达分支和“以防万一”的导出。移除它们。今天没有任何东西调用的函数不能为了“将来某天”而保留。
  8. 先读后写。 在不熟悉的仓库中写入之前,阅读你将编辑的文件、一个相邻文件,以及任何项目规则文件(CLAUDE.md、AGENTS.md、README 的“约定”部分)。使用项目现有的辅助函数、错误类型和日志。
  9. 几行代码能覆盖的,不要新增依赖。 在添加包之前,检查标准库、已安装的依赖,以及几行本地代码能否完成任务。新依赖是永久的维护和供应链暴露面;只有当它承载你不应重新实现的真正复杂性(密码学、解析、时区 —— 仅为示例,并非穷举)时才添加,绝不要为了省十行代码而添加。参见 references/dry-kiss-yagni.md。
底线 —— 绝不要为了简单而削减这些

第 16 条规则在边界内部信任契约;即使你删除了推测(14)、防御性防护(16)和死代码(21),以下条目仍然保留。移除其中任何一条都是行为变更,而不是清理 —— 保留它,或标记出来并询问。

  • 每个信任边界处的校验与净化 —— 外部输入、请求/API 载荷、反序列化或跨进程数据。
  • 防止数据丢失的错误处理。
  • 安全措施 —— 授权、输出转义、参数化查询、密钥处理。
  • 用户明确要求的行为。 随口提及 ≠ 要求,但不要丢弃已被要求的内容。
重构纪律
  1. 重构时保持可观察行为不变。 当用户要求你清理、简化或重构现有代码时,不要改变契约——相同的输入产生相同的输出,抛出相同的异常,产生相同的副作用,保持相同的顺序保证。如果你在重构时发现了一个 bug,单独标记出来,并在修改前先询问。重构的定义是*“对软件内部结构的修改,使其更易于理解、修改成本更低,同时不改变其可观察行为”*(Fowler,《重构》)。Bug 修复和重构是两种操作——绝不要把它们捆绑到同一次修改中。

交付前自检

在向用户展示你编写或编辑的代码之前:

  1. 将准则 1–24 逐条对照你的 diff 检查。修正每一处违规。
  2. 对于新函数,清点:行数 ≤ 20?参数 ≤ 4?复杂度感觉 ≤ 10?命名是否揭示意图?
  3. 对于新注释,问自己:它解释的是为什么吗?如果它解释的是是什么,删掉它。
  4. 对于新的错误处理:捕获的错误类型是否具体?处理逻辑除了静默返回之外,是否还做了别的事情?
  5. 对于新的抽象(接口、工厂、基类、注册表):今天是否存在第二个具体的使用者?如果没有,就内联它。
  6. 你是否阅读了你所编辑的文件以及至少一个相邻文件?你的风格是否匹配?
  7. 是否存在任何硬编码的 "ok" 返回值或桩数据?如果有,替换为真实实现,或显式返回未实现/不支持操作的失败。
  8. 如果这是一次重构:你是否改变了可观察行为?如果是,你捆绑了一个 bug 修复——把它拆分出来并询问用户。

如果你无法对每项检查都回答“是”,请在交付前修正。

在守卫检查通过后,将其展示出来,让用户能看到它已运行(守卫通过模式和实时模式——review 模式通过其自身的发现格式报告)。将每项修正列为 <file>[:<line>] — <what changed>,如果行号不稳定则省略行号,然后以一行收尾:clean-code-guard: <N> fixed, <M> flagged for author——如果没有任何触发,则为 clean-code-guard: clean。只报告你实际做出的修改;绝不要估算质量分数或百分比——不存在基准,因此这样的数字是凭空捏造的。这只是在报告本次检查;它不会阻止展示或提交。

当用户对某条规则提出异议时

引导他们查看相关 references/ 文件中的来源名称,仅在需要 URL 时才使用 references/sources.md。这些规则是站得住脚的——它们来自一手来源(Uncle Bob、Fowler、Hunt & Thomas、McCabe、Metz),以及 2024–2026 年关于大模型代码生成的已发表研究。如果用户有特定于其情境的理由要覆盖某条规则(例如某个构造函数确实需要 8 个参数来处理一个配置 DTO),请在代码注释中记录该例外,注明被覆盖的原则、原因以及重新审视的触发条件——即应重新考虑它的情形。没有重新审视触发条件的例外注释,本身就会成为下一次检查中的一项发现:没有出口的权衡只是被推迟的债务。

故障排除

  • 如果任务是概念性的而非产出代码的,不要应用此技能; 直接回答该概念。
  • 如果 review 模式开始产生仅针对风格的反馈,请使用 references/review-checklist.md,并优先关注行为 bug、脆弱性 和可维护性风险。
  • 如果某条规则与某个明确的项目约定冲突,请遵循项目 约定,并且仅当该例外会让未来的维护者感到意外时,才记录它。
  • 如果该技能感觉过于宽泛,请优先使用 frontmatter 中的排除项;不要向这个通用守卫技能中添加 特定于运行时的规则。

本技能不做什么

  • 运行 linter 或静态分析。这些是工具层面的关注点;本技能关注的是写什么和看什么。
  • 强制执行特定语言的格式化工具或 linter 偏好。以项目的样式工具为准。
  • 替代测试。整洁的代码能通过测试;没有整洁的代码测试就无法通过,但没有测试的整洁代码同样是一种缺陷。

评论

支持 Markdown