代码审查指北

写代码的人,十有八九都干过一件事:把 PR 往群里一丢,然后祈祷「这次能一次过」。

但代码审查 (Code Review) 从来不是走个过场。它是一套让代码库整体健康随时间改善的机制,Google 用它来维护代码和产品的质量。说到底,代码审查就是除作者之外的其他人,来检查这段代码的过程。

为什么需要代码审查?

先把它的价值说清楚,不然谁都懒得去做:

  • 尽早发现问题:在合并前抓住 Bug 和设计缺陷,此时修改成本最低
  • 知识共享:让至少另一个人熟悉这段代码,消除「巴士因子」
  • 提升代码质量:当人知道自己的代码会被读,往往会写得更好
  • 统一风格:靠人肉审查倒逼编码规范真正落地

这里顺带解释一下「巴士因子」 (Bus Factor)。它衡量的是:一个项目至少要失去多少名关键成员,才会陷入瘫痪。那些「不可或缺」的人,掌握的设计与知识并没有被其他人共享——一旦他们因为任何原因缺席(字面意义上的被巴士撞了,或者离职、转岗、婚育),项目就可能停摆。代码审查,恰恰是把这种「只有我知道」的知识,扩散成「至少两个人知道」的最廉价手段。

审查为什么容易伤人?

代码审查中最难的部分,就是你的建议被对方视为人身攻击。可以理解,没人喜欢花一周时间开发一个功能,结果却被告知需要全部重做。这对提出建议的人和审查者来说都很痛苦。我们一定要避免这种情况。

在我的实践中,这种痛苦通常有两个原因,一边一个,谁也别想赖账。

原因一:开局不利

这种情况经常发生在那些没有认真思考就匆忙投入开发的人身上。我坚信,花一天时间思考,可以节省一周的工作量。

不要害怕提问和讨论!这要么能验证你的方法是否正确,要么能避免你白白浪费一周时间在错误的方向上。

在进行任何更改之前,务必对更改内容有一个清晰的认识。仔细思考,如有任何疑问,请与同事讨论。

原因二:吹毛求疵

另一个原因出在审查者这边:只盯着细枝末节,却忽略了真正重要的东西。

比如,花了二十分钟在评论区跟作者掰扯缩进是四个空格还是两个空格,却对函数里一个潜在的越界访问视而不见。这种「只见树木、不见森林」的审查,会让作者觉得自己的努力被全盘否定——毕竟谁愿意为几个分号的争论,把整个设计推翻重来?

好好地审查,就是抓大放小:先看设计是否合理、逻辑是否正确、能否更简单,最后才轮到风格。而风格问题,最理想的做法是交给工具去管,而不是靠人肉一条条挑。

审查的常见反模式

除了上面说的,审查里还有几个经典翻车姿势,几乎每个团队都踩过:

  • 车棚效应:一堆人对着命名、缩进、import 顺序争得面红耳赤,却对潜在的竞态和架构漂移视而不见。这个名字来自一个老比喻——核电站的设计图几分钟就通过了(没人敢质疑),反倒是「车棚刷什么颜色」能吵一下午,因为人人都有意见
  • 橡皮图章:不管 PR 多大、多危险,看都不看就是一个 LGTM。典型症状是几千行的大 PR 几分钟内被放行——不是信得过,是没人有空认真读,干脆「审查疲劳」
  • 含糊其辞:「这感觉不太对」,却不给具体理由。作者无从下手,只能靠猜
  • 巨型 PR:一个 PR 塞进一堆无关改动,稀释了真正需要审查的那部分
  • 拉锯战:作者和审查者来来回回几十轮,始终不在一个频道上——这种时候,该当面聊了

根源其实只有一个:把注意力错配了。花在琐碎上的时间越多,留给「只有人能判断」的部分就越少。所以才有那句口号——机器管语法,人管语义。

怎样好好地审查?

几条从实践里总结出来的原则:

  • 经常审:审查越频繁,单次体量越小,就越不痛苦
  • 短平快:一次别审太久,小而快地审查远胜马拉松
  • 换人来:尽量让不同的人参与,避免「熟人滤镜」睁一只眼闭一只眼
  • 态度积极:审查是利他行为,以鼓励为主,而非找茬

审查关注什么?

一次审查,脑子里最好带着这份清单:

维度关注点
设计是否适合系统,有没有违反 SOLID 等基本设计原则
功能行为是否符合预期,对用户有没有用
复杂性能否更简单、更容易理解
测试自动化测试是否正确、设计良好
命名类、变量、方法名是否清晰
注释注释是否清晰有用,还是废话
风格是否遵循统一的样式指南
文档相关文档是否同步更新

一次审多少、审多快?

SmartBear 的调研给了几个很实用的数字,记住它们,别硬撑:

  • 每次别超过 200~400 行:超过 200 行,缺陷检出率开始明显下降;超过 400 行,基本趋近于零——你只是在「看」,不是在「审」
  • 速度别超过 300~500 行/小时:再快,就漏得厉害
  • 连续审查别超过 60~90 分钟:过了一个小时,注意力就撑不住了。反过来,哪怕只是一行的改动,也至少花上 5 分钟——一行代码也可能有系统级的影响

什么时候审?

最佳节点是功能分支自测完成、即将合并到主干之前——因为越晚改,成本越高。提交频率上,原则是至少一天一次;审查本身则可以塞进碎片时间,比如每天早上或者下班前固定刷一遍。

评论怎么写才不伤人?

审查者的输出,说到底就是评论。同样一个意思,语气不同,效果天差地别。Google 在工程实践里写了几条规矩,我摘最实用的:

  • 对代码,不对人:别说「你」,说「这段代码」。把矛头对准产物,而不是作者。有个研究数据很扎心——非常负面的评论,只有 57% 被采纳;语气中性的评论,79% 有用
  • 说清为什么:别只丢一句「改成单线程」,要说清楚理由:工程原因、对用户的影响、还是违反了哪条规范。作者只有理解了「为什么」,才可能心服口服
  • 好话也要说:看到写得好的地方,点出来,并说明为什么好。正反馈和被纠正一样,都是学习
  • 给评论贴严重程度标签:Nit(吹毛求疵)、Optional / Consider(可选)、FYI(供参考)、Blocker(必须改)、Question(提问)。不贴标签,作者会把每条都当成「必须改」

一个对比,感受一下:

反例:「你为什么在这里用线程?明显没有并发收益啊。」 正例:「这里的并发模型给系统增加了复杂度,但我看不到任何性能收益。既然没有收益,最好还是改成单线程。」

复杂一点的评论,可以用这个结构:严重程度 + 观察 → 为什么重要 → 请求的动作。小评论保持短就好;只有当你担心对方误解意图时,才把结构写全。

给提交者的几条建议

  • 原子性提交:一个提交只包含一个不可分割的特性、修复或优化,并且尽可能小
  • 遵守规范:代码风格交给工具,不要跟审查者打嘴仗
  • 冲突当面聊:出现共识冲突时,视频或面对面沟通,而不是在评论区里来回拉扯
  • 接住反馈:别急着辩解,先听懂对方的点。审查者的目标是代码健康,不是否定你这个人;有异议就当面讨论,别憋着,也别硬顶

找审查者也有讲究:优先找「能在合理时间内回复、并且能给到最彻底最正确审查」的人,不一定是文件所有者。如果心仪的审查者这会儿没空,至少抄送一下他们。另外,作者可以在审查开始前给代码做点标注,解释改了什么、为什么这么改——既引导审查者,也帮自己在交出去之前再自查一遍。

常见缩写速查

评论区里飞来飞去的黑话,这里一并收编:

缩写全称含义
PRPull Request把自己的分支合并到主干分支的请求
WIPWork In Progress进行中,暂时不要合并
LGTMLooks Good To Me看起来不错,批准
SGTMSounds Good To Me同上,表示赞许
CCCarbon Copy抄送,希望某人也能看到
TL;DRToo Long; Didn't Read太长懒得看,多用于摘要前提示
PTALPlease Take A Look帮我看下,请别人 review 自己的 PR
DNMDo Not Merge不要合并
CL / CSChangelist / Changeset修改的文件
ACKAcknowledgement我确认了、我接受了
RFCRequest For Comments我觉得这想法不错,一起讨论
IIRCIf I Recall Correctly如果我没记错
NACK / NAKNegative Acknowledgement我不同意
TBRTo Be Reviewed提示维护者进行 review
TBDTo Be Done / Defined视语境而定,一般是「还没搞定」
IMO / IMHOIn My (Humble) Opinion依我看 / 以我的拙见
AFAIKAs Far As I Know / Can Tell据我所知
FYIFor Your Information供你参考
AFKAway From The Keyboard稍后回来
IANALI Am Not A Lawyer我不是律师,但我闻到了许可问题

几个容易踩坑的细节:WIP 标注在标题里,GitHub 和 GitLab 都会自动禁用合并按钮;在开源项目里贡献代码时,最好一开始就建一个带 WIP: 前缀的 PR,把计划和目的写清楚,和你有同样想法的人就不会做重复工。LGTM / SGTM 多是审核者或维护者对贡献者的鼓励,评论别人的 PR 时请斟酌一二。CC 来自邮件里的「抄送」,用 cc @某人 就能让对方在自己的通知里看到这条消息。

结语

代码审查的收益,说到底还是那句话:花一点时间让代码被第二个人读一遍,换来的是更少的 Bug、更低的维护成本,和一个不会因为某人离职就当场瘫痪的团队。

再补一句:把机器能管的交给机器,把人的注意力,留给真正的对错。

下次丢 PR 之前,先问问自己:这段代码,值得被认真读一遍吗?

作者Aoang
发布于2025-12-29
更新于2025-12-29
许可协议CC BY-NC-SA 4.0
转载或引用本文时请遵守许可协议,并注明出处。