1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
title: "从 /simplify 到绝地委员会:如何与 Kent Beck、Martin Fowler 和 Mike Acton 一起进行代码审查"
date: 2026-03-09T18:00:00+01:00
draft: false
slug: "simplify-jedi-council-ai-code-review"
slug_en: "simplify-jedi-council-ai-code-review"
description: "/simplify 是 Claude Code 提供的自动代码审查工具,使用三个通用代理检查代码。虽然有亮点,但也带来了不少噪音。我换用绝地委员会:Kent Beck、Martin Fowler 和 Mike Acton 基于真实决策规则的模式。发现更少的问题,无误报,还找到一个原工具漏掉的 bug。"
tags: ["claude-code", "代码审查", "生产力", "AI", "重构"]
categories: ["观点"]

translation:
  hash: ""
  last_translated: ""
  notes: |
    - "绝地委员会": 是 Star Wars(星球大战)的典故,保持英文 "Jedi Council"。
    - "dicho en cristiano": 翻译为 "用简单直白的语言说出"。
    - "cosplay superficial": 译为 "表面角色扮演" 或 "肤浅模仿"。
    - "no se trata de vibes": 直译为 "这不是氛围问题,而是基于明确规则的决策"。

Claude Code 提供了一个名为 /simplifyslash command,可以自动审查你的代码。我用它检查了一个大幅变更——大约 8 个文件、500 行代码——结果让人有些意外。它确实发现了些我可能漏掉的点,但也带来了不少无用信息,让我浪费了不少时间。

所以我把它拆解了,然后又重新像拼图一样组装回来。

/simplify 是如何工作的

这是 Claude Code 内置的一项功能(无需额外安装)。它会并行运行三个代理,分别从三个不同的角度来审查代码变更:

  1. 代码复用(Code Reuse) —— 是否有可以替换新代码的现有工具?
  2. 代码质量(Code Quality) —— 冗余状态、复制粘贴、不良抽象stringly-typed code 等。
  3. 效率(Efficiency) —— 不必要的 I/O、未充分利用的并发、内存泄漏等。

这三个代理会各自给出发现的问题,之后系统尝试直接修复它们。

找到的亮点

代码复用代理发现我在测试代码的两处重复了一个完全相同的辅助函数:相同的名字、相同的代码内容,但分布在两个不同的文件中。我把它提取到一个共享模块里,干净利落。

效率代理指出了一个处理循环中不必要的磁盘操作:每次迭代都加载状态、修改后存储、读取数据、重新加载、再存储。写操作重复了两次,而实际上只需要一次。我没注意到这些隐患,但工具发现了。

还发现了一个内存缓冲区在错误路径中没有清除。如果在分配和释放之间发生错误,会产生内存泄漏。这种问题在主路径上已经被处理到了,但显然 copy-paste 草率遗漏了某些细节。

到这里为止,还算满意。三个发现,全都合法且可操作。但 /simplify 的问题并不在于它发现了什么,而是在于它发现了太多不重要的东西。

存在的缺陷

低级别的问题噪音过多。 它建议我删除一个 struct 的字段,因为 “它与一个计算属性是重复的”。这个字段占用 8 个字节,但被代码和测试中的十多处引用使用。做这个改动带来的代码修改工作量,远远超过了省下这几个字节的好处。

缺乏对项目上下文的理解。 它标记了一个并发模式为 HIGH 严重性,并且的确指出这是一个潜在风险。这一点没错,书面上看是合理的。但实际上,这个问题已经在项目的 CLAUDE.md 文档中记录了,工具链中专门配置了 lint 来应对,并且项目内还有一个相关的 issue 在处理。而 /simplify 并不知道这些,因为它只能基于代码变更的 diff 操作,缺乏项目整体的视角。

无法分辨“错误”和“可优化”。 上文提到的双磁盘操作的确效率低下,但并不是错误。而并发模式的问题就是真正的潜在炸弹。这两者的严重性却都被标记为 MEDIUM,优先级看上去一样,这种扁平的优先级划分很难起到实际帮助。

对外部数据强行推荐 enums。 它建议把某些 DTO 中的字段从字符串转换为枚举,但这些字段只是从外部 API 拉取后用于显示。把它们改成枚举需要自定义解码逻辑,却提供不了任何实际好处——如果对方 API 增加了新值,这样的枚举反倒会导致解析出错。枚举在这种情况下,不如保持字符串更稳妥。

以上这些,都是任何有项目背景知识的开发者一眼就能过滤掉的噪音。然而,/simplify 并不知道这些上下文。它只有代码变更的 diff 和一腔好意。

我做的三个改进

在看到 simplify 的结果后,我识别出了三个结构性问题,并开发了一个自定义 skill,命名为 /improve,修正了这些问题。

1. 注入项目上下文

让每个代理在发出评估之前,都可以接收项目的 CLAUDE.md 文档、权限设置、问题追踪工具中的未解决 issue 以及 linter 的结果。如果某些问题已经在处理中了,代理会提及而不是把它们重新标记为问题。

这一步削减了最让人头疼的一类 false positives:那些你早已知晓且已在管理范围之内的问题。

2. 引入成本/收益过滤器

在报告一个问题之前,每个代理都会预估修复所需的文件数量。如果修复的成本/收益比是负数(比如,改一个字段要动 10 多个地方却只带来很小的收益),则直接丢弃这个问题。

这一点看似直观,但 /simplify 并没有做到。目前,它会把 1 行的小改动和涉及 15 个文件的重构用同样的优先级报告出来。

3. 区分“自动修复”和“创建 backlog issue”

将发现的问题分为两类:

  • auto-fix(自动修复):简单机械化,影响文件 ≤3 个,无明显风险,立即修复。
  • issue(创建 backlog issue):需要设计决策,影响文件 >3 个,或涉及接口改动。在任务跟踪器中记录,稍后由开发者处理。

通过这种方式,代码审查不会尝试去修复那些需要深度思考的问题。

放弃的一些尝试(及原因)

引入第二个 LLM 作为复审工具。 听上去很酷——模型间互相验证,多角度分析。但实际情况是,瓶颈从来不是“眼睛够多”,而是“上下文不够”。第二个模型如果依然无法访问 CLAUDE.md 或任务追踪工具,得到的结果完全一样:依旧是毫无新意的“最佳实践”建议。

按 4 种优先级分类。 我最初尝试过按 CRITICAL / HIGH / MEDIUM / LOW 四个级别分类问题。但在成本/收益过滤器开启后,几乎所有通过过滤器的发现都落在了 MEDIUM 或 HIGH 上,CRITICAL 和 LOW 这两个级别有些鸡肋。更多的分类并没有带来更有效的优先级管理。

绝地委员会的转折点

接下来,是让我彻底改变审查结果的一大创意。

几周前,我写过一篇文章关于如何召唤专家当导师,让 LLM 从 Tufte、Munger 等专家的角度进行思考。这个方法在设计领域的应用效果非常显著。

那么,与其用三个通用的通用型代理(复用、质量和效率)评估代码,为什么不试着让三个“代理”化身为既有名字、哲学,又有具体决策规则的专家?

这个灵感来源于《星球大战》里的 绝地委员会:三位大师用不同的视角分析同一个问题。但需要注意,不是让 LLM 做“表面角色扮演”(比如复述名言警句),而是让每位“智者”运用他们独特的决策规则,有效过滤问题,避免一般性结论。

绝地委员会三位大师(以及为什么是他们)

Kent Beck —— 简洁至上

“Make it work, make it right, make it fast — in that order.”

Kent Beck 是那个会提醒你:“复制三次才需要抽取公共逻辑,只有两次就先别动。” 他的关键规则是:三次法则。在相同代码块出现三次之前,不要建议提取公共代码。两次可能是偶然,三次才是模式。此外,如果修复代码需要改动的范围比解决的问题更大,那这可能不值得动。这也是一个“放下”改动的信号。

Kent Beck 的视角也包括寻找 语义错误:那些表面上看似正确,实则却可能在特定情况下出问题的代码。比如一个看似无害的 async 调用,其实继承了不符合预期的执行上下文;或者某些在测试中正常运行,而上线后会崩溃的默认值设置。

Martin Fowler —— 设计美学

“Code smells are just symptoms, not the actual problem. And refactoring is a discipline, not a hobby.”

Martin Fowler 的核心指导是:设计上的“坏味道”往往只是表面现象,而重构的前提必须是具体的目标。 他的关键规则是:只有在实际需求发生变更时,才能建议实施重构。换句话说,除非有明确需要改动的场景,否则重构只是徒增代码库的干扰。

Mike Acton —— 性能权威

“The purpose of all programs is to transform data from one form to another.”

Mike Acton 聚焦于数据路径优化。当你没有具体数据证明问题时,那没有性能问题的说法就只是“感觉”而已。他的关键准则:I/O 是大多数应用程序中的主要性能瓶颈。 CPU 通常不是问题的根源,但磁盘 I/O 和网络可就是了。

Acton 的行动:用数字说话

Mike Acton 不仅局限于静态分析,他有两项绝招会在下结论之前亲自验证:

  1. 静态 I/O 溯源分析:扫描代码 diff,列出所有读写磁盘、网络或数据库的操作,并分析这些操作是否在循环或关键路径上。基于其上下文生成频率表。

  2. 实际性能 Profiling:如果 diff 修改了关键路径上的代码,并且项目可被编译,则运行性能分析工具,记录数据后再评论问题是否实际存在。

这些分析结果甚至还包括对 I/O 延迟时间的订单近似估测:SSD 读取约 0.5ms,写入约 1ms,持久化 2-5ms,网络操作约 100-500ms。尽管这些数据并不精确,但在识别有问题的“大块时间消耗”上非常有效。

风险与解决方案

你可能会想,直接将这样一个绝地委员会用于每次 Pull Request 是否现实?我们不能忽视LLM 可能会陷入表面角色扮演的问题——它能把“派对猫”包装成有哲学深度的样子,“像 Beck 一样”提出的建议也许只是另一个普普通通提示,换了个人名挂上去而已。

为避免这种情况,规则说明不依赖哲学描述,而是强制植入具体规则——比如要运用“三次法则”,或者明确哪些情况不应该触碰。

同时,每个大师一定要附加一段**“已被过滤但未报告的问题”清单**,展示它们为什么被丢弃。有了这些,整个审查过程透明化,用户看到的是多一步慎密的决策。

最后,一个额外的处理:如果两位“智者”意见针锋相对(比如 Beck 说“不必修改”,Fowler 却说需要重构),那么一个中立的AI被召唤以协调整合意见,并给出最终选择。如果仍然分歧难解,默认方案是丢弃建议。比做错强。

万事俱备,虽然它不能取代真正的 Kent Beck,但它远胜于人人兢兢“人云亦云”那种模糊回馈——尤其是规则有依据且透明时!

最终成效对比

传递给两个不同工具的同一数据对比如下:

| | /simplify | /improve | …..(可后缀表单匹配同Markdown打印对比)