代码评审(Code Review)是团队里少数几个”高杠杆”环节:花二十分钟看别人的改动,可能拦下一个线上故障,也可能让一个人少走半年弯路。但同样是评审,有的团队越评越顺,代码质量和信任度一起涨;有的团队越评越僵,作者拆小 PR 只为少挨骂,评审人敷衍点赞走流程。差别往往不在流程工具,而在参与者的默认心态。
一、评审到底在干什么
把评审的目的想清楚,很多争论会自动消失。评审真正的作用是两件事:
缺陷拦截。作者对自己的代码有”作者盲区”——逻辑是自己写的,每一步都在预期之内,很难察觉哪里漏了边界。评审人以新鲜视角看代码,捕捉盲区的效率远高于作者本人重读。
知识共享。代码库的变更在合入前扩散给至少一个同伴,避免”只有一个人懂这块”的单点。休假、离职、转岗时,这个价值会立刻兑现。
值得强调的是,评审不是对作者技术能力的评判。一段代码被提了十条意见,不代表作者水平差,只代表这段改动被认真看了。反过来,一个 PR 全程零意见合入,也未必是好事——可能只是评审人没看。把评审从”评判人”重新定义为”打磨产品”,是健康评审文化的起点:评论对准代码和设计,不对准人。”这个函数没有处理空指针”和”你怎么连空指针都不判”,内容相同,效果天差地别。
二、措辞是可以训练的
同样是指出问题,命令式和问题式的长期效果完全不同。命令式读起来像指令和指责,作者本能进入防御状态;问题式邀请作者解释,往往还能引出作者掌握但没写进代码的上下文。
几个常见的改写:
| 命令式 | 问题式/中性式 |
|---|---|
| 这里必须加锁 | 这个计数器在并发下会不会丢更新? |
| 这样写性能很差 | 这个查询走的是全表扫描,量级上去之后有预估吗? |
| 别用全局变量 | 这个状态放模块内局部变量是不是也能覆盖? |
| 拆成两个函数 | 这个函数承担了两件事,拆开是不是更好测? |
还有个低成本高收益的习惯:意见里带上”为什么”。只说”改成 X”,作者只能服从或反驳;说”改成 X,因为 Y”,作者能判断 Y 在他的场景下是否成立。带上理由的意见即使被驳回,也是高质量的技术交流。
回复评论也有措辞讲究:”这里因为 Z 所以没判空”是有效回复,”已改”两个字让评审人无法确认理解是否对齐。有些建议确实不需要采纳,但说明不采纳的理由,既是协作礼貌,也留下了决策痕迹。
三、区分”必须改”与”建议”
评审效率低下的一个常见原因是:所有意见长得一样重。作者看到十条评论,分不清哪条不改就合不了,只能全盘接受或全盘抵抗。把意见分级是解决这个问题最简单的办法:
- [必须] 正确性问题、安全漏洞、数据丢失风险、明确违反团队规范。不改不能合入。
- [建议] 设计偏好、可读性、可维护性。作者可以不采纳,但需要回应(采纳或说明理由)。
- [疑问] 评审人没看懂或想确认的地方。作者解释即可,可能什么都改。
很多团队用前缀标记([blocker]、[nit]、[question]),工具上没有强制约定也没关系,评论开头用括号写清楚就行。实践里有个反直觉的现象:意见一旦分级,必须改的条数通常比想象中少,作者的压力骤降,反而更愿意听建议类的意见。
对”建议”类意见,作者有一条底线:可以不改,不能不理。沉默是最伤协作的动作,评审人不知道你是没看见、不同意还是已经改了。
四、作者一侧的义务
评审是双向的,作者对评审质量的责任不比评审人小。几个作者侧的基本功:
小 PR。一次改动控制在几百行以内,评审人能维持注意力看完。上千行的 PR 换来的往往是”看不动了,就这样吧”——它通过评审,但没被评审。拆分的方式有讲究:按逻辑步骤拆,不要把”重构”和”新功能”混在一个 PR 里,两者混在一起会让评审人无法判断哪些变化是有意的。
描述动机。PR 描述写清”为什么改”,而不只是”改了什么”。改了什么是 diff 能看出来的,动机不写,评审人只能猜。一个实用模板:背景一行、方案一行、影响范围一行、自测情况一行。
自测证据。贴上测试结果、截图、压测数据,或者说明”如何本地复现验证”。作者说”我测过了”和贴出测试输出,对评审人的说服力完全不同。证据还有一层作用:它逼作者在提交前自己先过一遍验证流程,很多低级问题在这一步就被拦下了。
回应时效。意见提出来后,作者的跟进速度决定流程节奏,PR 因为不回复卡三天,再小也救不回效率。
五、争议怎么处理
再健康的团队也会有意见相持不下的时候:作者认为该用 A 写法,评审人坚持 B。争议的正确出口不是在评论区来回拉锯,拉锯超过三轮,几乎必然带上情绪。
比较有效的路径是:评论区摆事实,线下对齐。线上把各自的技术理由写清楚(往往写到第二条时就发现有一方理解错了),仍然僵持就约个十分钟的当面或语音沟通,把问题讲透。线下达成一致后,回到 PR 里补一条结论评论,把决策和理由沉淀下来——这是给未来维护者的礼物。
如果线下仍然僵持,就该引入第三层依据:以规范为准。团队有编码规范、设计原则的,按规范裁决;规范没覆盖的,记录分歧点,按其中一方的方案执行并标注”此处有争议,后续遇到同类问题时再定规则”。最怕的是每次争议都靠嗓门或资历解决,那样评审会退化成权威游戏,年轻人很快就不提意见了。
六、时效与阻塞管理
评审拖沓是团队协作里最隐蔽的效率杀手。PR 挂在那里没人看,作者上下文切换去做别的事,两三天后回来继续写,重新加载上下文的成本很高。整个团队的吞吐量就这样被零碎地吃掉了。
几个可操作的约定:
- 首轮响应时限。PR 提出后一个工作日内必须有首轮回应,哪怕只是”今晚看”。
- 评审轮次上限。超过三轮还在改的 PR,通常应该拆分或线下讨论,而不是继续在评论区消耗。
- 明确的合入条件。谁批准算通过(一人还是两人)、CI 必须绿、必须改项清零。规则透明,作者不用猜。
- 评审排班或轮值。避免所有 PR 都压给团队里最资深的一两个人,他们一旦忙起来,全队阻塞。
对评审人还有个心态上的提醒:评审是正经工作,不是挤出来的零碎时间。找一段不被打断的二十分钟,比碎片时间里扫五眼有效得多。看代码时顺手把整体设计、异常路径、测试覆盖都过一遍,比逐行抠格式有价值——格式问题应该交给 linter,让人来干机器的活是双输。
回到那句老话:代码是写给人看的,顺带让机器执行。评审就是这句话的日常实践。对事不对人不是一句礼貌口号,它是一套可以拆解成措辞、分级、时限、证据的具体习惯。习惯成型之后,评审会从压力事件变成一件平常的事——而这正是它该有的样子。
评论(3)
思路可以复用,已经在另一个项目里试了。
看到第二节就笑了,太真实了。
看完之后把自己的流程重新梳理了一遍。
请 登录 后参与评论。