代码评审真的能提高代码质量吗?我统计了3412条评审意见后发现了真相

🔑 关键词:代码评审, 静态分析, 工程效率, 缺陷检测, 开发流程

📖 摘要:作者基于两年间3412条代码评审评论和静态分析结果对比,指出代码评审在缺陷发现上的真实效率,并提出将设计评审与代码审查分离的落地策略。

2019年我在一家做工业网关的公司带数据采集模块,代码评审被写进了开发流程:任何变更要在Gerrit上凑齐两个+1才能合入。我那时还挺信这套,直到部门出现了三起线上事故,原因都埋在一个公共函数里,而那三个PR都通过了评审。这事让我开始系统地把过去两年的评审意见拉出来做分类统计。总共3412条评论,按“真正逻辑缺陷”“风格/命名/个人偏好”“疑问/反问”三类人工打标签。最终结果吓了我一下:“真正逻辑缺陷”只有38条,占1.1%;“疑问/反问”占差不多一半。也就是说,几百个小时的等待和沟通,最后挡不住什么问题。

图片

然后我用SpotBugs把同一批代码离线扫描了一遍,发现疑似NullPointerException路径有89个,其中后来事故里实锤的三处都在里面。工具扫描跑完十几分钟,而人工评审在相同代码上花的等待时间是平均每次变更5.2小时。这个对比让我不敢再把“提高代码质量”这个KPI压在代码评审上。如果你想找bug,静态分析工具的召回率远高于几个同事轮流看代码;如果你想要别人理解你的意图,那又是另一回事。可惜我们的流程把两件事混成了一个叫“评审”的动作,结果两边都没顾好。

图片

后来我把自己的观察分享给团队,被人说我在否定评审制度。其实不是。我主张把“设计评审”和“代码审查”切分开。设计评审在动工之前讨论方案,关注接口边界、并发模型、消息流;代码审查等实现完成后才开始,这时大家只能围绕“这里要不要判空”“函数名换成xx更贴切”来做文章。最致命的是发起时机太晚:错误的地基已浇好,人工审查只能帮忙挑点墙皮。从成本上看,设计评审发现问题损失一版草稿,代码评审发现问题则要补一个修修补补的PR和一轮回归测试。

图片

我现在带项目,只在三类情况留人工评审:变更触碰资金、状态机、安全等高危区域;修改牵扯两个以上子系统的接口;或者作者对某段实现有解释不清的不适感。普通小改走CI加静态分析加覆盖率门禁,合不进去再回头问作者。一年后我统计了内部项目数据:发布缺陷率从每季度7桩降到4桩,相关评审等待时间下降了一半。代码评审并没有消失,只是它终于回到了该待的位置——用来解释意图和分散知识域,而不是充当一个低效的缺陷探测器。

图片