——一场关于“代码洁癖”与“交付速度”的拉锯战
前言
代码评审(Code Review,简称 CR)大概是技术团队里最微妙的存在。
不做吧,心里发虚——谁知道那个刚毕业的小伙子又把什么祖传代码提交上来了;做吧,又怕变成“大家来找茬”,一个 if 语句的缩进能讨论半小时,需求上线的时间线就这么被一寸一寸地蚕食。
我带过团队,也被别人评审过。我见过因为 CR 太松,线上事故频发,整个组周末都在救火的;也见过因为 CR 太严,一个功能从周一拖到周五,最后产品经理冲到工位前拍桌子的。
这中间的度,到底怎么拿捏?
一、两个极端:洁癖患者 vs 摆烂选手
先说说我见过的两种典型“人效陷阱”。
陷阱 A:完美主义者的泥沼
老张是我们组的高级工程师,技术很好,但有个“毛病”——眼里容不得一粒沙子。
一次 CR,一个新功能提交上来,逻辑没问题,测试也通过了。老张开始评审:
“第 47 行的变量名
data太泛了,建议改成userOrderList。”“这个工具类我们组之前有个类似的,建议抽成公共的。”
“这里的注释不够详细,建议补充一下边界条件的说明。”
每一条都有道理。但问题是,这个需求明天就要上线,而这些修改跟业务逻辑一毛钱关系没有。
作者乖乖改完,重新提交。老张又来了:
“嗯,变量名改了,但这个地方的空指针校验是不是可以再提前一点?”
一圈下来,一个 2 天的需求,CR 环节花了 1.5 天。
团队里开始流传一句话:“千万别让老张审你的代码,他会跟你讨论花括号换行的哲学。”
结果是什么? 进度拖慢,大家开始“挑软柿子捏”——专找 junior 工程师互审,绕过老张。老张不高兴了,觉得团队不重视代码质量。团队也不高兴,觉得老张不接地气。
陷阱 B:走过场的灾难
另一边,小李的风格截然相反。
他的 CR 标准是:能跑就行。
“LGTM(Looks Good To Me)。”
“逻辑我看了,没啥问题,过吧。”
“测试通过了吧?那行,我点了。”
有一次,一个核心支付链路的逻辑被改了。小李审了 3 分钟,LGTM。结果上线后,因为少处理了一种异常分支,导致部分订单状态卡死。排查了一整夜,最后发现那个分支在代码里就少了一个 else。
太松的 CR,等于没 CR。 它给你一种“我们已经审查过了”的安全感,但实际上什么漏洞都没拦住。
二、为什么我们会掉进这两个坑?
说白了,CR 的困境在于:评审者不知道自己该对什么负责。
太严的人,潜意识里觉得“我要对每一行代码的质量负责”。他们害怕将来出问题,追溯起来是自己放行的,所以把标准拉到最高。
太松的人,潜意识里觉得“代码是作者写的,我只负责看看有没有明显的低级错误”。他们把 CR 当成一个流程节点,而不是一个质量关卡。
两种心态,都跑偏了。
CR 的目的不是“让代码完美”,也不是“让代码不出错”。CR 的目的是在合理的时间内,以合理的成本,把风险降到可接受的范围。
三、我的解法:分层评审
踩过几次坑之后,我给团队定了一套“分层评审”的规则。核心思路是:不是所有代码都值得用同一个标准去审。
第一层:必须拦住的(红线)
这些东西,不管多急,都必须指出,必须改:
- 安全漏洞:SQL 注入、越权访问、敏感信息明文打印
- 数据一致性风险:事务缺失、并发问题、边界条件未处理
- 性能隐患:N+1 查询、大循环里调 RPC、全表扫描
- 可回滚性:上线后如果出问题,能不能快速回滚
这些东西一旦漏到线上,代价远大于多花 30 分钟改代码。
第二层:建议优化的(黄线)
这些东西,指出,但给作者选择权:
- 命名不够清晰
- 代码结构可以更好(比如方法太长、职责不单一)
- 有重复代码可以抽公共
- 注释缺失或不够准确
怎么处理? 在评审里标注为“建议”,不阻塞合并。如果作者觉得有道理,顺手改了;如果觉得当前没时间,可以记一个 TODO,后续迭代优化。
第三层:纯风格问题(灰线)
这些东西,直接忽略:
- 缩进风格
- 花括号位置
- import 顺序
- 注释的标点符号
靠什么解决? 靠工具。EditorConfig + Checkstyle + Spotless + Pre-commit Hook。人不要浪费时间在格式化上,让机器去管。
四、流程上的几个关键设计
光有分层标准还不够,流程设计决定了 CR 的效率和体验。
1. 控制评审粒度:别一次审 2000 行
一个 PR 超过 400 行,评审质量断崖式下降。这不是评审者的问题,是人脑的带宽限制。
做法: 大功能拆成多个小 PR。每个 PR 只做一件事——要么加一个接口,要么改一个模块,要么修一个 bug。这样评审者可以在 15-20 分钟内审完,质量有保障。
如果实在拆不开(比如重构),那就提前跟评审者沟通,约个时间一起看,而不是甩一个 2000 行的 PR 到群里等人审。
2. 设定 SLA:评审不是无限期的
我们定了规矩:PR 提交后,2 小时内必须有人开始评审,8 小时内必须给出结论。
为什么?因为作者提交代码后,上下文还在脑子里。如果 2 天后才有人评审,作者可能已经切到别的需求了,再切回来改代码,上下文切换成本巨大。
紧急需求怎么办? 标 urgent 标签,评审者 30 分钟内响应。如果评审者不在,找 backup。
3. 评审者不超过 2 人
一个人审太片面,三个人审效率灾难。我们规定:每个 PR 最多 2 个评审者。 一个是模块负责人(懂业务),一个是轮值评审(交叉学习)。
4. 用"评论类型"区分优先级
在评审工具里,我们要求用前缀标注评论的优先级:
[block]—— 必须改,阻塞合并[suggest]—— 建议改,不阻塞[nit]—— 吹毛求疵,可忽略
这样作者一眼就知道哪些评论是"必须处理的",哪些是"有空再看"。评审者也会被这个约定反向约束——你标了 [block],就得想清楚它到底值不值得阻塞。
五、一个真实的对比
我们组实施这套规则前后,数据对比:
| 指标 | 之前 | 之后 |
|---|---|---|
| 平均 PR 评审耗时 | 1.5 天 | 4 小时 |
| 平均 PR 行数 | 800+ | 250 |
| 线上 Bug 率(CR 后漏出的) | 每两周 3-4 个 | 每两周 0-1 个 |
| 开发者对 CR 的满意度 | "又来了" | "还行,不怎么耽误事" |
最关键的变化是心态。 以前大家把 CR 当成一个"审判",现在当成一个"协作"。评审者不再纠结于缩进,作者也不再觉得被冒犯。
六、最后想说的
代码评审的本质,不是找错,也不是炫技。它是一个团队在"交付速度"和"代码质量"之间达成共识的过程。
太严,团队会绕过你;太松,系统会绕过你。
好的 CR 标准应该是:漏出去的 Bug 你愿意在凌晨三点爬起来修,同时评审的时间不会让你的需求延期到被产品经理骂。
