2006年5月,SmartBear Software完成了一项为期10个月的研究。他们在Cisco Systems的MeetingPlace产品组跟踪了2500次代码评审,涉及320万行代码和50名开发者。这是有史以来规模最大的轻量级代码评审案例研究。

研究团队在分析数据时发现了一个令人困惑的现象:评审者的审查速度没有任何规律可言。有人花15分钟审阅一行代码,有人用5分钟扫过200行。更关键的是,当评审的代码量超过400行时,缺陷发现率几乎归零。

这揭示了代码评审的一个根本性悖论:它既是软件工程中被引用最多的最佳实践,也是实际效果偏离预期最远的环节。

从会议室到异步工具:代码评审的五十年变形

1976年,IBM的Michael Fagan在《IBM Systems Journal》上发表了一篇论文,正式提出了"代码检查"(Code Inspection)的概念。这套方法极其正式:需要专门的准备阶段、正式的检查会议、详细的缺陷记录和后续跟踪。Fagan报告称,这种方法可以发现60-90%的缺陷。

但这套方法有一个致命缺陷:太慢了。研究显示,正式检查会议本身只占整个流程时间的20%,其余80%浪费在调度和准备上。Votta在1993年的一项研究发现,传统检查方法中有20%的时间纯粹是在等待。

到1990年代末,软件开发进入了互联网时代。快速迭代成为常态,正式的检查会议逐渐被轻量级的异步评审取代。Rigby和Bird在2013年研究了多个开源项目和工业项目,发现了五个趋同的实践:轻量级流程、早期频繁评审、小规模变更、两名评审者、从缺陷发现转向群体问题解决。

这就是"现代代码评审"(Modern Code Review)——基于工具、异步、聚焦于代码变更的评审方式。今天,几乎所有使用Git的开发团队都在实践这种评审。

但问题在于:当形式简化后,效果是否也被稀释了?

微软的发现:评审评论的真实构成

2013年,微软研究院的Alberto Bacchelli和Christian Bird在ICSE会议上发表了一篇论文,题为《现代代码评审的期望、结果与挑战》。他们观察和访谈了17名开发者,手工分类了570条评审评论,调研了165名管理者和873名程序员。

研究结果颠覆了一个普遍认知。

虽然44%的开发者和管理者将"发现缺陷"列为代码评审的首要动机,但实际评审评论中,与缺陷相关的评论仅占14%。大多数评论(29%)是关于"代码改进"——命名、格式、可读性等非正确性问题。其次是关于理解代码的澄清性问题(18%)和替代方案讨论(15%)。

更值得深思的是,与缺陷相关的评论主要覆盖的是"微小的低级逻辑问题"——边界情况、配置值、运算符优先级。“宏观"层面的设计问题或深层次缺陷,在评审中很少被发现。

为什么会这样?研究者发现了一个关键因素:理解。

理解:代码评审的隐形瓶颈

在微软的研究中,几乎每位受访者都提到:理解代码变更是评审中最困难的部分。一位资深开发者直言:“做代码评审最难的事情是理解变更的原因。”

当评审者对被审代码有先验知识时——比如他们是文件的所有者或最近修改过这些代码——评审速度更快,评论更深入、更有洞察力。但当评审者不熟悉代码时,他们需要花费大量时间建立上下文,而评论往往只停留在表面层次:格式、命名、显而易见的错误。

这解释了为什么缺陷发现评论如此稀少。评审者首先要理解代码在做什么,然后才能判断是否正确。当代码量超过某个阈值,或者评审者缺乏上下文时,理解本身就耗尽了认知资源,几乎没有剩余精力用于发现深层问题。

谷歌的研究提供了更精确的量化数据。

谷歌的数据:两万次日评审背后的真相

2018年,谷歌团队在ICSE软件工程实践分会上发表了一篇论文,详细描述了谷歌内部的代码评审实践。这是人类历史上规模最大的代码评审系统:每天超过20,000次变更,25,000名开发者参与评审,2014-2016年间累计900万次评审。

谷歌的数据揭示了几个关键事实:

  • 75%的变更只需要一名评审者。这与传统研究建议的"两名评审者最优"形成对比。
  • 中位评审时间不到4小时,远低于其他研究报告中15-24小时的中位时间。
  • 中位变更量是24行代码,超过35%的变更只修改一个文件,10%只修改一行。
  • 开发者每周平均花费约3.2小时进行评审

这些数据指向一个核心结论:谷歌的代码评审系统之所以高效,不是因为它能发现更多缺陷,而是因为它足够轻量、足够快速。

事实上,谷歌引入代码评审的初衷就不是发现缺陷。根据参与早期实践的员工回忆,代码评审在谷歌的最初目的是"迫使开发者写出其他开发者能理解的代码”——将研究代码库转变为生产代码库。评审的核心价值在于知识传播、保持代码一致性、建立共享的代码所有权。

缺陷发现是受欢迎的副作用,而非主要目标。

物理极限:人类评审者的认知边界

SmartBear在Cisco的研究提供了一些具体的数字,这些数字后来被广泛引用为代码评审的最佳实践:

  • 评审代码量应低于200行,不超过400行
  • 评审时间应低于60分钟,不超过90分钟
  • 评审速度应低于300行/小时,最好在200行/小时以下

这些数字背后是人类的认知生理学。当评审超过60分钟后,评审者会出现疲劳,注意力下降,缺陷发现率急剧衰减。当单次评审超过400行代码时,评审者被信息淹没,根本无法深入理解每一行代码的含义。

2024年的一项研究专门调查了"代码评审焦虑"现象。研究者发现,近50%的开发者在评审过程中经历过具有临床意义的焦虑。这种焦虑源于对被评判的恐惧、对批评的担忧、对负面评价的预判。而焦虑会进一步削弱认知能力,形成恶性循环。

更深层的问题在于评审者的心理状态。当评审者处于压力下——项目截止日期临近、评审队列堆积——他们倾向于快速浏览、只关注表面问题。这就是为什么格式和命名问题在评审评论中占比如此之高:它们是最容易发现的问题,不需要深入理解代码逻辑。

破坏性批评:评审评论的隐性代价

2022年,奥克兰大学的研究团队在CSCW会议上发表了一项关于代码评审中破坏性批评的研究。他们定义的"破坏性批评"有两个特征:非具体(如"这是垃圾代码")和不体谅(如"你需要多蠢才会这样写")。

研究调查了93名软件开发者,发现了一个令人不安的现实:

  • 超过一半的受访者在过去一年中收到过非具体负面反馈
  • 近四分之一的受访者收到过不体谅的负面反馈

更重要的是,研究发现存在显著的性别差异。女性开发者认为破坏性批评更不恰当,收到破坏性批评后继续与该开发者合作的动机更低。非二元性别参与者也表现出类似的倾向。

一位受访者在开放性评论中写道:“我用一个非性别的备用账户进行开源贡献,因为它帮助我把事情办成。而我的主账户明确标识我是女性,会收到更多尖刻的评论。”

这揭示了一个被忽视的问题:代码评审不仅是技术实践,也是社会互动。当评审评论带有破坏性时,它不仅无助于代码质量,还会损害团队凝聚力和包容性。

PR规模悖论:越大越糟糕

多个研究一致发现,Pull Request的规模与评审质量呈负相关。

SmartBear的数据显示,当代码量超过200行后,缺陷密度(每千行代码发现的缺陷数)开始下降;超过400行后,几乎没有评审能达到高缺陷密度。

2015年的一项研究分析了评审延迟与PR规模的关系,发现较大的PR需要更长时间才能获得首次反馈和最终批准。更关键的是,较大的PR获得的评论数量并不成比例增加——评审者面对大量代码变更时,倾向于放弃深度评审。

2023年的一项数据分析更加直接:保持PR在400行以下的团队,生产环境中出现的bug减少了40%

这形成了一个残酷的循环:开发者提交大型PR → 评审者感到压力 → 评审质量下降 → 缺陷逃逸到生产环境 → 开发者需要提交更多修复PR → 评审队列进一步膨胀。

反模式:当代码评审变成形式主义

研究者识别出了多种代码评审反模式:

浅层评审(Shallow Review):评审者只关注格式、命名等表面问题,忽略逻辑和设计层面的缺陷。这在评审者不熟悉代码或评审队列过长时尤为常见。

评审拖延(Review Procrastination):评审请求被搁置数天甚至数周。开发者在此期间被迫切换任务,丧失上下文。Sophie Leroy的研究表明,单次非计划的任务切换会消耗高达20%的认知能力——因为关于原任务的思维残留会干扰新任务的执行。

权力游戏(Power Dynamics):资深开发者利用评审权限拖延或不批准变更,以施加影响或表达不满。这种行为会制造有毒的团队氛围,导致开发者回避提交评审或减少贡献。

LGTM文化:评审者只回复"Looks Good To Me"而从未真正阅读代码。这在评审量过大或评审者认为某些开发者"可靠"时出现。2024年的一项研究分析发现,高达90%的大型代码变更在没有任何实质评审的情况下被合并,其中71%是自我合并。

评审者悖论:专业知识 vs 审评效果

一个反直觉的发现是:最熟悉代码的评审者,可能不是最有效的缺陷发现者。

当评审者是文件所有者时,他们对代码变更的上下文了如指掌,评审速度更快。但研究显示,他们更可能认同变更的方向,因为他们本身就参与了这些决策。他们可能"看不到"问题,因为他们已经内化了问题的框架。

相反,对代码不太熟悉的评审者可能会提出更多问题,但这些往往是关于理解的澄清性问题,而非真正的缺陷发现。他们缺乏上下文,无法判断变更是否引入了微妙的问题。

这提出了一个组织挑战:如何平衡"熟悉的评审者"(理解快但可能有盲点)和"新鲜的评审者"(视角新颖但理解成本高)?

时间分配:评审的真实成本

代码评审到底消耗多少开发时间?

谷歌的数据显示,开发者每周平均花费约3.2小时进行评审。其他研究显示,评审活动通常占开发时间的10-20%。

但这只是直接时间。间接成本包括:

  • 上下文切换成本:当代码评审打断深度工作状态,开发者需要15-25分钟重新进入"心流"状态
  • 等待成本:评审延迟期间,开发者无法继续相关工作,必须切换到其他任务
  • 返工成本:当代码评审发现需要重大修改,之前的工作部分白费

一项量化分析估计,一个5人的开发团队,如果每次评审平均需要2小时,每人每周参与10次评审,总成本可能达到每周100人小时——相当于2.5个全职工程师的工作时间。

这是否值得?答案取决于评审的实际产出。

重新定义成功:从缺陷发现到价值创造

如果代码评审不是发现缺陷的有效手段,它的价值在哪里?

微软和谷歌的研究指向几个被低估的价值:

知识传播:代码评审是最有效的代码库学习机制之一。新成员通过评审他人的代码快速了解项目约定和架构决策。

共享所有权:当代码被多人评审后,不再是"某人的代码",而变成"团队的代码"。这降低了关键人员风险(Bus Factor)。

设计讨论:代码评审往往是设计讨论发生的场所。评审者提出的替代方案可能比原实现更好。

自我约束:知道代码会被他人评审,开发者在编码时会更谨慎、更注重可读性。

审计线索:评审记录成为代码变更历史的文档,解释了"为什么这样改",对未来维护者有价值。

谷歌的实践表明,当代码评审的主要目标从"发现缺陷"转向"保证代码可理解和可维护"时,它成为了一个更有价值的实践。

实践建议:基于证据的优化

综合多项研究,以下实践有较强的实证支持:

控制PR规模:每次评审的代码量应控制在100-300行,绝对不超过400行。更大的变更应拆分为多个独立的PR。

设置合理预期:评审应在24小时内获得首次反馈。如果团队无法满足这个预期,需要重新审视评审流程或增加评审者。

避免评审疲劳:单次评审时间控制在30-60分钟。如果评审者感到疲劳,应该暂停而不是继续。

重视评审者选择:优先选择对代码有先验知识的评审者,同时偶尔引入新鲜视角。

建立评审文化:明确评审评论的期望风格。破坏性批评不仅是无效的,还会损害团队包容性。

自动化可自动化的:格式、命名、简单静态分析问题应该由工具自动检测,释放评审者专注于真正需要人类判断的问题。

尾声

代码评审并非万能药。它是一个实践——像所有实践一样,它有其适用的场景和固有的局限。

当代码评审被视为"免费的缺陷检测工具"时,它注定令人失望。研究发现缺陷的能力有限,消耗的时间却不菲。但当它被视为知识共享、团队建设和代码质量文化建设的一部分时,它的价值远超缺陷发现。

关键在于诚实地评估:你的团队为什么要做代码评审?你期望它达成什么目标?你的实践是否支持这些目标?

如果答案模糊,或许该重新思考这个被神化的实践了。


参考文献

  1. Bacchelli, A., & Bird, C. (2013). Expectations, outcomes, and challenges of modern code review. Proceedings of the 2013 International Conference on Software Engineering (ICSE), 712-721.

  2. Sadowski, C., Söderberg, E., Church, L., Sipko, M., & Bacchelli, A. (2018). Modern code review: a case study at Google. Proceedings of the 40th International Conference on Software Engineering: Software Engineering in Practice, 181-190.

  3. Cohen, J. (2006). Best Kept Secrets of Peer Code Review. SmartBear Software.

  4. Gunawardena, S. D., Devine, P., Beaumont, I., Garden, L. P., Murphy-Hill, E., & Blincoe, K. (2022). Destructive criticism in software code review impacts inclusion. Proceedings of the ACM on Human-Computer Interaction, 6(CSCW2), Article 292.

  5. Rigby, P. C., & Bird, C. (2013). Convergent contemporary software peer review practices. Proceedings of the 2013 9th Joint Meeting on Foundations of Software Engineering, 311-322.

  6. Fagan, M. E. (1976). Design and code inspections to reduce errors in program development. IBM Systems Journal, 15(3), 182-211.

  7. Kononenko, O., Baysal, O., & Godfrey, M. W. (2016). Code review quality: how developers see it. Proceedings of the 38th International Conference on Software Engineering, 1028-1038.

  8. Egelman, C. D., Murphy-Hill, E., Kammer, E., Hodges, M. M., Green, C., Jaspan, C., & Lin, J. (2020). Predicting developers’ negative feelings about code review. Proceedings of the IEEE/ACM 42nd International Conference on Software Engineering, 174-185.

  9. Bosu, A., & Carver, J. C. (2013). Impact of peer code review on peer impression formation: A survey. 2013 ACM/IEEE International Symposium on Empirical Software Engineering and Measurement, 133-142.

  10. Beller, M., Spruit, N., Spinellis, D., & Zaidman, A. (2017). On the dichotomy of debugging behavior among programmers. Proceedings of the 39th International Conference on Software Engineering, 752-763.