跳转到正文

第七章:代码审查

代码审查是质量把关——而非形式、表演,也非社交仪式。Superpowers 将代码审查视为一项严谨的技术活动,对请求和接收反馈都有明确的规范。


第一部分:请求代码审查

为什么结构很重要

无结构的代码审查请求("嘿,能帮我看看这个吗?")只会产生无结构的反馈。审查者不知道代码应该做什么、解决什么问题,或做出了哪些权衡。结果是表面化的评论,错过了重要问题。

有结构的请求能给审查者提供真正有用反馈所需的一切信息。

准备上下文

在派遣审查者之前,请准备以下三类信息:

WHAT — 这次变更做了什么?用 2–4 句话描述:

  • 正在解决的问题
  • 采用的方案
  • 关键设计决策及其原因
  • 没有做什么以及原因

PLAN — 实现计划是什么?链接或总结指导本次工作的计划。这让审查者能够验证实现是否符合意图。

BASE_SHA → HEAD_SHA — 被审查的精确 commit 范围:

# 获取 base(你的分支从 main 分叉的位置)
git merge-base main HEAD

# 获取当前 HEAD
git rev-parse HEAD

这确保审查者查看的是正确的 diff——不包含无关 commit,也不是完整历史记录。

派遣审查 subagent

准备好上下文后,按以下结构派遣代码审查 subagent:

REVIEW REQUEST
--------------
WHAT: [2-4 句话描述变更内容]

PLAN: [实现计划的链接或摘要]

DIFF RANGE: [BASE_SHA]..[HEAD_SHA]

FOCUS AREAS: [可选:你希望重点审查的具体区域]

Subagent 将检查 diff、核对计划、运行相关测试,并返回结构化反馈。

按严重性处理审查反馈

并非所有反馈都具有相同的紧迫性。每个严重级别的处理方式不同:

严重性定义处理方式
Critical(严重)Bug、安全问题、数据丢失风险、broken contract阻塞完成。 在任何其他工作之前立即修复。
Important(重要)重大质量问题、缺少测试、性能问题在开始下一个任务前修复。不要积累。
Minor(次要)风格偏好、命名建议、可选改进记录下来。 创建后续 ticket。不要对当前 PR 过度完善。

最常见的错误是将所有反馈视为同等紧迫。严重问题阻塞进度。次要问题记录存档。混淆两者会导致要么因琐碎的风格反馈而延误,要么忽视真正的 bug。


第二部分:接收代码审查

核心问题:表演性认同

AI agent——以及许多开发者——在代码审查中有一种倾向于表演性认同的习惯。这是当审查者提出建议时,实现者立即说"你说得完全正确!我马上修复!"并在没有真正评估建议是否正确的情况下做出修改。

表演性认同是有害的,因为:

  • 它将错误的建议应用到正常运行的代码上
  • 它训练审查者期望无条件服从
  • 它通过积累错误建议使代码质量随时间下降
  • 它提供了审查正在发现真实问题的虚假信心

禁用语

以下短语表明表演性认同,不允许使用:

禁用语原因替代表达
"你说得完全正确!"未经评估就认可"已修复。将 X 改为 Y,原因是 [理由]。"
"好发现!"社交奉承,无实质内容"已核实。问题是 Z。"
"我马上修复"在理解之前做出承诺"正在阅读这段内容。"
"这完全说得通"未经分析就认同"我理解这个顾虑。以下是我的评估:……"
"你是对的,我本应该……"无行动的自我批评"已实现。以下是具体变更。"

替代语言聚焦于事实:什么发生了变化、为何变化、以及核实了什么。

正确的响应模式

收到代码审查评论时,请严格按照以下顺序操作:

READ → UNDERSTAND → VERIFY → EVALUATE → RESPOND → IMPLEMENT

READ(阅读): 阅读完整评论,包括任何引用的代码或文档。阅读期间不要响应。

UNDERSTAND(理解): 你能用自己的话解释审查者的顾虑吗?如果不能,提出澄清问题。不要猜测意图。

VERIFY(核实): 通过查看实际代码来检查顾虑是否成立。如适用,运行相关测试。查看真实行为,而非你对它的心理模型。

EVALUATE(评估): 应用 YAGNI 检验(You Aren't Gonna Need It,你不会需要它):

  • 这个变更对当前需求是必要的吗?
  • 它解决了一个真实的、已被证明的问题吗?
  • 它增加了代码库目前不需要的复杂性吗?
  • 这是合理的最佳实践还是个人风格偏好?

RESPOND(响应): 基于你的评估而非本能认同来撰写响应。

IMPLEMENT(实现): 如果建议有效,实现它。如果无效,解释你的理由。

对审查建议的 YAGNI 检验

审查者建议"你应该在这里添加缓存"或"你应该将这个抽象为通用接口"可能是对的——但必须进行 YAGNI 检验:

  • 当前需求真的需要缓存吗?是否有性能问题的实测证据?
  • 现在是否有超过一个具体的抽象使用场景?

如果答案是否,正确的回应是:"已记录为潜在的未来改进。对于当前需求,更简单的方案已经足够。我已将其记录为后续事项。"

有效的反驳场景

你不仅被允许反驳审查反馈——在以下情况下你必须反驳:

  1. 建议引入了 bug。 用测试或具体示例证明为什么建议的变更会产生错误行为。

  2. 建议违反了既定计划。 如果实现计划已经过审查和批准,偏离需要明确的重新批准,而不是在代码审查期间单方面更改。

  3. 建议超出范围。 建议可能是好的,但它属于单独的任务。现在实现它会扩大范围、延迟交付,并创建混合用途的 commit。

  4. 建议是风格偏好,对正确性没有影响。 风格偏好应该属于 linter 配置,而不是代码审查反馈。如果它无法自动化,可能不值得阻塞 PR。

  5. 你已经核实代码是正确的,而审查者是错误的。 清晰、礼貌地提供你的证据。你可能是错的——但你必须陈述理由。

反驳模板

反驳时,使用以下结构:

I've evaluated this suggestion. My assessment:

CONCERN: [准确重述审查者的顾虑]
INVESTIGATION: [我检查了什么来评估它]
FINDING: [我发现了什么]
DECISION: [实现 / 记录以备后用 / 不同意,因为……]
EVIDENCE: [测试输出、参考资料或具体示例]

这使你的推理可被审计,并使审查对话聚焦于事实。


总结

做好的代码审查是最强大的质量工具之一。做得差的代码审查——无论是走形式还是合规表演——比没有审查更糟糕,因为它消耗时间却不产生质量。

Superpowers 规范确保审查的双方都是严格的:审查者获得所需的上下文,而实现者以技术诚实而非社交顺从来评估反馈。