
代码审查指北
写代码的人,十有八九都干过一件事:把 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(提问)。不贴标签,作者会把每条都当成「必须改」
一个对比,感受一下:
反例:「你为什么在这里用线程?明显没有并发收益啊。」 正例:「这里的并发模型给系统增加了复杂度,但我看不到任何性能收益。既然没有收益,最好还是改成单线程。」
复杂一点的评论,可以用这个结构:严重程度 + 观察 → 为什么重要 → 请求的动作。小评论保持短就好;只有当你担心对方误解意图时,才把结构写全。
给提交者的几条建议
- 原子性提交:一个提交只包含一个不可分割的特性、修复或优化,并且尽可能小
- 遵守规范:代码风格交给工具,不要跟审查者打嘴仗
- 冲突当面聊:出现共识冲突时,视频或面对面沟通,而不是在评论区里来回拉扯
- 接住反馈:别急着辩解,先听懂对方的点。审查者的目标是代码健康,不是否定你这个人;有异议就当面讨论,别憋着,也别硬顶
找审查者也有讲究:优先找「能在合理时间内回复、并且能给到最彻底最正确审查」的人,不一定是文件所有者。如果心仪的审查者这会儿没空,至少抄送一下他们。另外,作者可以在审查开始前给代码做点标注,解释改了什么、为什么这么改——既引导审查者,也帮自己在交出去之前再自查一遍。
常见缩写速查
评论区里飞来飞去的黑话,这里一并收编:
| 缩写 | 全称 | 含义 |
|---|---|---|
PR | Pull Request | 把自己的分支合并到主干分支的请求 |
WIP | Work In Progress | 进行中,暂时不要合并 |
LGTM | Looks Good To Me | 看起来不错,批准 |
SGTM | Sounds Good To Me | 同上,表示赞许 |
CC | Carbon Copy | 抄送,希望某人也能看到 |
TL;DR | Too Long; Didn't Read | 太长懒得看,多用于摘要前提示 |
PTAL | Please Take A Look | 帮我看下,请别人 review 自己的 PR |
DNM | Do Not Merge | 不要合并 |
CL / CS | Changelist / Changeset | 修改的文件 |
ACK | Acknowledgement | 我确认了、我接受了 |
RFC | Request For Comments | 我觉得这想法不错,一起讨论 |
IIRC | If I Recall Correctly | 如果我没记错 |
NACK / NAK | Negative Acknowledgement | 我不同意 |
TBR | To Be Reviewed | 提示维护者进行 review |
TBD | To Be Done / Defined | 视语境而定,一般是「还没搞定」 |
IMO / IMHO | In My (Humble) Opinion | 依我看 / 以我的拙见 |
AFAIK | As Far As I Know / Can Tell | 据我所知 |
FYI | For Your Information | 供你参考 |
AFK | Away From The Keyboard | 稍后回来 |
IANAL | I Am Not A Lawyer | 我不是律师,但我闻到了许可问题 |
几个容易踩坑的细节:
WIP标注在标题里,GitHub 和 GitLab 都会自动禁用合并按钮;在开源项目里贡献代码时,最好一开始就建一个带WIP:前缀的 PR,把计划和目的写清楚,和你有同样想法的人就不会做重复工。LGTM/SGTM多是审核者或维护者对贡献者的鼓励,评论别人的 PR 时请斟酌一二。CC来自邮件里的「抄送」,用cc @某人就能让对方在自己的通知里看到这条消息。
结语
代码审查的收益,说到底还是那句话:花一点时间让代码被第二个人读一遍,换来的是更少的 Bug、更低的维护成本,和一个不会因为某人离职就当场瘫痪的团队。
再补一句:把机器能管的交给机器,把人的注意力,留给真正的对错。
下次丢 PR 之前,先问问自己:这段代码,值得被认真读一遍吗?
