2.9

2.9 拉取请求与代码评审指标

概述与动机

代码评审通常是主题 2.6 周期时间分解中单一最大的等待时间来源,同时也是最直接处于团队自身掌控之下、可以改善的阶段,不同于一个共享的平台瓶颈或一项外部依赖。本主题涵盖存在于评审阶段内部的具体指标:首次评审时间、拉取请求规模、评审迭代次数与评审者负荷分布,以及如何用它们来改善评审速度,同时不牺牲评审本应提供的真正质量收益。

本主题最警惕的风险,是本书尚未直接涵盖过的:如果不慎追求,优化评审速度可能悄悄侵蚀评审质量。一个通过给一切盖橡皮图章批准,把首次评审时间减半的团队,改善了一个指标,同时摧毁了这项实践的真正价值。本主题的每一条建议,都是在把这种权衡牢记于心的前提下写成的,因为拉取请求指标是本书中最容易被操纵得在仪表盘上看起来漂亮、同时让底层代码库可衡量地变差的指标之一。

对大团队而言,评审指标揭示出原本不可见的负荷均衡问题:一小撮资深工程师吸收了不成比例份额的评审负荷、某个具体团队或代码库区域评审持续停滞,或者一种大到让彻底评审在实践中几乎不可能的拉取请求模式,无论评审者多么勤勉。这些模式在规模上的累积效应,远超它们在小团队中的表现,因为在小团队里,人人都能直接看到这种不均衡,无需指标来揭示它。

核心原则

  • 首次评审时间通常是最大的杠杆,而不是评审的彻底程度本身。 大部分延迟来自一份拉取请求在等待被查看,而不是来自评审对话一旦开始就耗时很长。
  • 更小的拉取请求评审得更快、也更彻底,而不只是更快。 规模是同时撬动速度和质量的一个杠杆点。
  • 评审速度与评审质量不会自动处于张力之中,但可能被不慎权衡取舍。 明确防范这种权衡。
  • 评审者负荷不均衡很常见,而且通常不可见。 少数人往往吸收了不成比例的份额。
  • 这些指标暴露在橡皮图章操纵风险之下。 一次没有真正审视的快速批准,会挫败评审的全部意义。

建议

把首次评审时间作为主要的速度指标来跟踪

测量从一份拉取请求被打开,到评审者第一次实质性评论或批准之间的间隔,从你的版本控制平台自动埋点。这通常是评审阶段内主导性的等待时间来源(主题 2.5、主题 2.6),改善它(通过更清晰的评审指派规范、通知实践,或专门的评审时间段)通常能为团队带来现有可用的、对整体周期时间的单一最大改善。

跟踪拉取请求规模,主动鼓励更小的变更

测量每份拉取请求变更的行数或触及的文件数,把持续偏大的中位数规模视为一个值得直接讨论的信号。更小的拉取请求评审得更快、评审得更彻底(评审者能真正把整个变更装在脑子里),也更容易在出问题时回滚,这直接连接回主题 2.10 部署频率背后的批量大小原则。在工作允许的地方,鼓励把大型变更拆分成一系列更小、可独立评审的拉取请求。

明确监控评审者负荷分布

在一个滚动窗口内跟踪每个人完成的评审数,专门留意一小撮人是否吸收了不成比例的份额。这种模式很常见,往往落在最资深或最受信任的工程师身上,既造成瓶颈(他们的可用性限制了整个团队的评审吞吐量),也造成耗竭风险(主题 3.2 更深入涵盖幸福感指标)。刻意地轮换评审责任,而不是任由它默认围绕响应最快的人集中。

明确防范橡皮图章操纵风险

把首次评审时间与一个质量信号配对:追溯到零评论就获批的变更所造成的缺陷或事故比例,或近期评审过的代码所需要的合并后修复比例。一个通过不加真正审视就批准来改善评审速度的团队,应当看到这道护栏恶化,这正是主题 1.2 配对原则应用到这个具体指标家族上的体现。永远不要在没有这道反向指标的情况下追逐评审速度。

用评审迭代次数来发现摩擦,而不是评判个人

一份拉取请求在合并前经历的评审轮数,可能标示出真正的摩擦、不清晰的需求、对方案的分歧、不一致的风格期望,这些都值得在流程层面进行调查。避免用这个数字直接评判具体的作者或评审者;一个高迭代次数更常是一个系统或沟通信号,而不是一个个人信号,把它当作个人记分卡来对待,冒着主题 1.1 所警告的那种评价性漂移的风险。

权衡取舍:利与弊

方案优点缺点
纯粹为首次评审时间优化信号快速、清晰,容易埋点若不加防范,可能激励表面化、橡皮图章式的评审
纯粹为减少拉取请求规模优化同时改善速度与彻底程度并非所有工作都能干净地拆分成小的增量
均匀轮换评审负荷降低瓶颈和耗竭风险可能拖慢需要特定专业知识的专业化、难评审代码的评审
把评审集中在资深工程师身上深厚的领域专业知识得到一致应用随时间推移造成瓶颈和耗竭风险

核心张力是速度与审视深度之间的张力。本主题中每一项加快评审的技术(更快的首次响应、更小的拉取请求、更分散的评审者负荷)如果不加本主题所推荐的质量护栏而追求,都带有把真正审视权衡掉的风险。解决之道是把每一个速度指标都与一个在同一时期内跟踪的质量信号配对,这样团队才能分辨真正的流程改善,与一种正在悄悄侵蚀的评审标准。

与团队讨论的问题

  1. 我们实际的首次评审时间是多少,评审阶段消耗了我们整体周期时间的多大比例? 拉出真实数字,而不要依赖印象;评审等待时间往往比团队所假定的更长,恰恰是因为等待所花的时间比主动工作所花的时间更容易被低估。

  2. 我们拉取请求规模的中位数是多少,如果这个规模缩小,我们的评审延迟会缩小多少? 大型拉取请求评审起来更慢,也更可能收到表面化的评审,原因很简单,评审者无法把整个变更装在脑子里。看看你实际的规模分布,而不只是中位数。

  3. 评审负荷是否集中在一小撮人身上,如果其中一人两周不可用,我们的评审吞吐量会发生什么? 这个问题同时揭示出瓶颈风险和耗竭风险。拉出真实的评审者负荷数据,而不要依赖印象。

  4. 我们是否曾以一种事后看来降低了真正审视程度的方式改善过一项评审速度指标? 在这里要诚实;这正是本主题所指出的橡皮图章风险,而且很容易在没有任何刻意决定的情况下滑入其中。

  5. 一个高评审迭代次数在我们团队中通常意味着什么:真正的分歧、不清晰的需求,还是不一致的风格期望? 看一批迭代次数异常高的拉取请求,诊断出真正的模式,而不要假定它反映了作者或评审者的不足。

  6. 我们是否有一道与评审速度指标配对的质量护栏,还是我们只是孤立地跟踪速度? 如果诚实的答案是不存在这样的护栏,那就是一个值得在进一步推动评审速度之前补上的缺口,依据主题 1.2 的配对原则。

行业视角

初创公司。 小团队的评审往往默认很快,有时甚至快得过头,单人批准、审视最少,因为人人都信任彼此。随着团队成长,需要留意的风险,是评审质量没有随团队规模同步扩展,因为对五名工程师有效的非正式信任,并不会自动对五十名工程师同样有效。

小型企业。 大多数版本控制平台开箱即用地报告合并时间和评审次数统计数据;使用这些数据,而不要构建定制埋点。最值得养成的自律,只是留意评审负荷是否随着团队成长而悄悄集中到了一两个人身上。

企业。 评审者负荷不均衡和专业知识瓶颈在这里尤其常见,因为对一个关键系统的深厚领域专业知识,可能会把评审责任集中到一小群人身上,无论团队规模多大。投资于刻意的知识共享和评审轮换来分散专业知识,同时降低瓶颈和那份专业知识存在于太少人身上的巴士因子风险。

政府。 这里的评审流程常常伴随合规方面的分量,与质量目标并存,这可能使拉取请求按设计变得更大、评审变得更慢。在真正的合规要求确实需要彻底评审之处,把改善努力集中在减少等待时间上(更快的评审指派、更清晰的分流),而不是妥协评审的实际深度,并在出于监管原因必须保持高强度审视时,明确记录这种权衡。

案例

企业。 一家网络安全公司的工程组织发现,在一个两百人的组织中,一小撮首席工程师完成了超过40%的所有代码评审,这种不均衡,直到评审者负荷数据被拉出来之前,从未有人直接测量过。这种集中既是一个瓶颈,因为这些工程师的可用性限制了整个组织的评审吞吐量,也是一次敬业度调查(主题 3.2)单独标记出的耗竭风险。该组织引入了一个结构化的评审轮换项目,配合有针对性的知识共享会议,在两个季度之内,评审负荷已经分散到一个宽得多的群体,首次评审时间也作为瓶颈缓解的直接副作用而改善。

政府。 一家税务机构的工程团队,在压力之下要求改善交付速度,设定了把首次评审时间减半的目标。一个季度之内,目标达成了,但一次随后的质量审计发现,合并后缺陷修复拉取请求急剧上升,集中在那些只用一条简短评论就获批的变更中。该团队的修复方案,是把速度目标与一道明确的质量护栏配对:评审后两周内所需要的合并后修复比例,并针对什么才算真正的实质性评审重新培训了团队,在保留大部分来自更好的评审指派和更小拉取请求规模的速度改善的同时,恢复了真正的审视。

商业理由:动机、投资回报与总拥有成本

管理良好的评审指标带来的回报,是更快的交付而不牺牲质量,这是一种罕见的组合:大多数交付改善都在某处用速度换取了风险,但评审阶段的改善(更小的拉取请求、更好的负荷分布、更快的首次响应)在配合本主题所推荐的质量护栏追求时,会真正同时改善两者。上面的网络安全案例很典型:修复瓶颈改善了速度,而底层评审质量,若有变化的话,也随着专业知识更广泛地传播而有所改善。

总拥有成本很低:这些指标中的大多数,直接来自现有的版本控制平台数据,只需最少的额外埋点,而它们所指向的流程变化(评审轮换、鼓励更小的拉取请求),主要花费的是自律,而不是工具投资。

反模式与陷阱

  • 不配对质量护栏就优化首次评审时间: 招致挫败评审目的的橡皮图章式批准。
  • 忽视评审者负荷集中: 造成瓶颈和耗竭风险,在被测量之前保持不可见。
  • 把评审迭代次数当作个人记分卡: 更常是一个系统或沟通信号,而不是一个个人信号。
  • 接受持续偏大的拉取请求为不可避免: 大多数大型变更能拆分得比团队最初所假定的更细。
  • 无论变更风险如何都施加统一的评审深度: 在低风险变更上浪费审视,同时可能对高风险变更审视不足。
  • 测量评审速度,却从未检查真正的审视是否随之下降: 这个指标家族被无意间操纵的最常见方式。

成熟度模型

  • 第一级,启动: 评审指标不被跟踪;评审负荷分布和拉取请求规模不可见。
  • 第二级,发展: 一些来自平台默认设置的评审速度数据存在,但没有质量护栏,也没有对评审者负荷的主动管理。
  • 第三级,标准化: 首次评审时间、拉取请求规模与评审者负荷被一致地跟踪,配以一道明确的、与速度改善配对的质量护栏。
  • 第四级,管理: 评审者负荷通过轮换和知识共享被主动重新平衡;迭代次数模式在流程层面而不是个人层面被调查。
  • 第五级,协奏: 评审阶段指标直接为流程投资提供依据,组织能够证明评审速度与评审相关质量结果在一段持续时期内同时得到了改善。

讨论思路

  1. 我们当前的首次评审时间中位数是多少,这段时间实际上去了哪里?
  2. 我们的评审负荷是否集中在少数人身上,如果其中一人不可用,风险是什么?
  3. 我们是否曾以牺牲真正审视为代价改善过评审速度,哪怕是无意中?
  4. 我们拉取请求规模的中位数是多少,大多数变更实际上能缩小多少?
  5. 我们是把一个高评审迭代次数当作系统信号,还是当作个人判断?

要点回顾

  • 首次评审时间通常是评审阶段内单一最大的杠杆,比评审对话本身的时长更重要。
  • 更小的拉取请求同时改善评审速度和评审彻底程度。
  • 评审者负荷不均衡很常见,通常不可见,除非被直接测量;它同时造成瓶颈和耗竭风险。
  • 把每一个评审速度指标都与一道明确的质量护栏配对,以抓住这个指标家族尤其容易出现的橡皮图章操纵风险。
  • 用评审迭代次数来诊断系统层面的摩擦,而不是评判具体的作者或评审者。

参考文献与延伸阅读

  • Accelerate: The Science of Lean Software and DevOps,Nicole Forsgren、Jez Humble、Gene Kim著(代码评审实践及其与交付绩效的关系)。
  • Alberto Bacchelli与Christian Bird的Modern Code Review研究(大规模代码评审实践的实证研究)。
  • Peer Reviews in Software: A Practical Guide,Karl E. Wiegers著(评审流程设计及其权衡)。
  • The Principles of Product Development Flow,Donald G. Reinertsen著(应用于拉取请求规模的批量大小推理)。