Skip to content

代码评审实践

代码评审(Code Review)最大的价值不是抓几个 typo 或风格问题——那些 lint 工具能做。它真正的作用是:让设计决策被更多人理解、把隐式知识显式化、在合并前发现结构和风险层面的问题。评得好,团队整体水平一起涨;评得差,变成拖慢交付的形式主义。

评审看什么

把注意力分配到机器查不出、人最有价值的地方:

层次看什么例子
结构设计是否合理,职责是否清晰把业务逻辑塞进工具函数、跨层调用
边界异常、空值、并发是否处理只考虑正常路径,忘了失败和重试
风险安全、性能、数据完整性信任外部输入、N+1 查询、缺事务
命名是否准确传达意图data 的变量、叫 process 的函数
测试是否覆盖关键行为,是否测了不该测的没有失败路径测试、过度 mock

风格、格式、import 顺序这类问题,交给 lint 和格式化工具自动处理,不要在评审里反复提。评审者的时间是稀缺资源,要花在机器替代不了的地方。

怎么给反馈

反馈的质量决定评审是建设性的还是对抗性的:

text
差的反馈:
"这样写不好。"
"为什么不用 X?"

好的反馈:
"这里直接读 request.body 没有校验类型,
如果传入数组会让后面的 .trim() 报错。
建议在入口处加一层校验。"

几个原则:

  • 对事不对人:说"这段代码在并发时可能丢更新",而不是"你怎么又写了并发 bug"。
  • 说清为什么:不光指出问题,还解释为什么是问题、影响是什么。
  • 给方向而非命令:提建议和理由,而不是强令对方照你的写法改。除非是明确的错误,否则留空间让作者决策。
  • 区分必须改和建议:用"必须"和"建议"区分阻塞性问题和可选优化,别让作者猜哪些不改过不了。
  • 肯定好的部分:评审不是只找错,看到清晰的设计、好的命名、周全的测试,说出来,强化这些。

作者怎么准备评审

评审效率不只取决于评审者,也取决于提交者准备得怎么样:

  • PR 要小:一个 PR 聚焦一件事。几百行的混合改动没人能认真审,最后只能走个过场。
  • 写清楚背景:这个改动解决什么问题、采用了什么方案、为什么这么选。评审者没有你的上下文。
  • 自己先过一遍:提交前用自己的代码 diff 视角审一遍,常常能发现遗留的调试代码、注释掉的逻辑。
  • 标注重点:在复杂或有疑问的地方留注释,引导评审者关注关键部分。
text
好的 PR 描述:
修复用户重复提交导致订单重复创建的问题。
方案:在创建订单前用 Redis SETNX 加幂等锁,
锁 key 用 userId + 请求 traceId,TTL 5 分钟。
请重点看 lockKey 的生成和失败时的降级逻辑。

评审的节奏

评审不该成为交付的瓶颈,但也不能无限期搁置:

  • 当天响应:收到评审请求尽量当天处理,阻塞的 PR 拖着会迫使作者合并未经审的代码或闲置等待。
  • 控制单次评审量:一次审 200-400 行效果最好,超过这个量注意力下降、问题漏看。
  • 不要囤积:留一大堆 PR 周五集中审,质量一定差。分散到日常,每次专注。

当意见不一致时

技术分歧是正常的,处理不好会变成僵局或人情债:

  1. 先理解对方:复述对方的方案和理由,确认你理解对了再反驳。很多"分歧"其实是误会。
  2. 用事实和权衡:说清两种方案各自 tradeoff,而不是"我觉得这样更好"。
  3. 小范围验证:有争议时,写个 spike 或跑个数据,用证据说话。
  4. 知道何时升级:僵持不下时,找资深成员或负责人决策,而不是在评论里无限轮辩。
  5. 接受合理的不完美:不是每个分歧都要争出最优解。在不破坏核心约束的前提下,接受作者的选择,记录决策原因,比强求一致更健康。

务实的评审清单

  • 是否聚焦结构、边界、风险,而不是纠结风格?
  • 反馈是否说清了原因、区分了必须改和建议?
  • PR 是否足够小、背景是否写清楚?
  • 评审是否及时响应,没有成为交付瓶颈?
  • 分歧是基于权衡讨论,还是变成了立场之争?

代码评审是团队里最高频的知识传递场景。一次好的评审,让作者知道为什么这么改、让评审者理解这块业务、让后来的读者从讨论记录里看到决策脉络。把它当作"一起把事情做对"的协作,而不是"我审你"的关卡,它的价值才能真正发挥出来。

为复用而记录,为理解而整理。