如何做好代码评审

“三人行,必有我师焉;择其善者而从之,其不善者而改之”

《论语》

前言

相信任何对技术有追求的工程师都希望提高自己的编码水平,任何团队都希望产品代码能具有统一风格,代码就像是出自同一人之手,降低认知负荷。

很多团队也都探索过 Code Review 实践,最终却不幸流于形式,虎头蛇尾,造成这种现象的原因是多方面的,团队文化、奖励机制、成本和收益不对等等问题:

1. 为什么代码评审很重要

2. 把 Code Review 作为一种制度

2.1 发布流水线上配置卡点

在发布流程中,设置 Code Review 卡点, CR 不通过不允许发布

2.2 代码入库前强制评审

如果代码仓库并不利用发布平台进行发布后入库,同时也希望能开发代码入库前的 Code Review 检查,可以在代码平台上开启开关来进行强制入库检查。之后可以通过在本地客户端发起代码评审,可以保证任何 Commit 在入库之前都经过了评审。这种方式可以像提交一个普通分支一样提交评审。

git push origin HEAD:refs/for/分支名 -o title="feat: add xxx config" 
-o description="a description" -o reviewer=xxx

3. 形成 Code Review 文化

把 Code Review 作为上线发布流程或者代码入库的卡点并不代表 Code Review 这件事就可以执行的很好。如果仅仅只是当作一个流程制度,那么就可能会流于形式,最终结果就是看起来做了 Code Review ,但没有人认真审查,随便看下就通过了,或者发现问题也不愿意修改。

要想把 Code Review 这件事做好,必须让 Code Review 变成团队的一种文化,开发人员从心底接受这件事,并认真执行,否则如果只有部分同学认同容易形成破窗效应,久而久之,Code Review 就无法真正执行下去,下列这些方面可以参考:

4. 提高评审效率和评审质量的实践

Code Review 的执行,很大部分程度上依赖于评审人的认真审查,以及被评审人的积极配合,两者缺一不可。但即使是团队已经初步形成了评审文化,但如果评审的成本过高,也会极大的打击评审人和被评审人的积极性,所以必须对 Code Review 进行行为规范来最大程度的降低 Code Review 时间成本,提升评审人和被评审人的沟通效率。这一章节会介绍不同角色对应的 Code Review 规范。

4.1 作为作者

4.1.1 确保 Code Review 只做一件事

保持单一职责原则可以有效避免 Code Review 成本过高。一个 Code Review 应该只负责一件事,处理了一个 Feature,解决了一个 Bug,新增一个组件或功能。

单一职责会让 Code Review 理解成本最小,不要为了省事在一个 Code Review 里掺杂太多其它修改,所以下列行为是不推荐的:

这些行为都是在增加评审成本,应该新起一个独立的 Code Review 来完成,而不是在本次 Code Review 中做。Code Review 的规模和范围并不以代码修改规模来作为唯一评判标准,也要判断该 Code Review 是不是只在做一件事。另外,如果 Code Review 是为了实现代码清理和代码格式化等优化,也不要夹带私货,避免引入 Bugfix 和 Feature。

4.1.2 发起 Code Review 的时机:尽量提前,开发中小步快跑

避免发起临门一脚的 Code Review,临门一脚指的是快接近发布上线时间才发起的 Code Review,开发代码都是为了发布上线,有一些需求会有发布上线的时间点限制,但发起临门一脚的 Code Review 会显著的将 Code Review 推向流于形式的方向。根据经验,Code Review 越左移,修改代码的成本越低,修改意愿也越高,什么是左移?先了解一下常规的发布上线流水线流程,有两种发起 Code Review 的时机,从 CR 实践落地效果上看,第一种 CR 发起的时机更好

从流水线上来看,许多人会在临近上线时,在靠右的地方快合并主分支的时候才进行 Code Review ,这个时候修改成本就很高,因为代码已经自测/测试通过,如果因为 Code Review 有问题需要重新修改代码,功能本身又要自测或者回归测试,占用更多的时间。而且因为已经临近上线,却因为 Code Review 被打回,开发人员愿意重构代码的意愿也会很低,明明发现问题,又因为上线压力,不打回不符合规范的代码,久而久之大家会失去对 Code Review 的敬畏心理, Code Review 也会慢慢流于形式变成应用发布的过场之一,既无法提高代码质量,降低系统 Bug,也不能提升开发人员的水平,反而降低的开发团队的效率,所以我们要尽量避免在上线之前才发起评审,最好的评审发起时机应该是在开发完毕后立即提交代码评审。但也有一些复杂场景需要反复进行测试和验证,对于这类 Case 也可以在 CI 流程完毕后再发起。

4.1.3 尽可能提前做好代码自审

在提交Code Review之前可以借助工具进行一次查缺补漏,避免将低级错误和不完善的代码展现给评审人。例如借助代码平台的新建评审页面展示提交内容,查缺补漏。

4.1.4 编写语义明确的标题

不论是 Code Review详情页,还是列表页面,标题都是评审者最先接触到的信息。

如下图,从评审列表无法判断 Code Review 所完成的事项,是否是在处理 Feature 还是 Bug,也无法判断紧急程度和优先级。

推荐使用如下格式来规范标题:

模块可以是每个平台约定俗成的模块,比如代码平台的模块包括:Code Search、 Code Review 、Issues、Wiki 等,从评审列表就可以获知大部分信息,当前 Code Review 在解决什么模块的什么问题,也可以根据前缀大概判断紧急程度。规范之后从列表对 Code Review 的意图一目了然,Code Review 也是团队的重要数据资产,通过规范的标题可以对模块的发展脉络进行方便检索。

4.1.5 编写详细的描述

Code Review 的描述也是最重要的信息输入之一,是 Code Review 发起人和代码评审人之间的对话,发起人有义务将自己的编码逻辑、修改范围、可能影响介绍给评审人。评审人在阅读代码之前就了解你的背景和思路,比阅读代码过程中再逐步领悟效率要高得多。评审人也有权利拒绝评审无任何描述信息的 Code Review。

描述部分建议提供以下信息:

背景:本次修改的原因是什么
思路和改动点:大概的思路是什么,改动了哪些方面可能造成的影响介绍一下

4.1.6 开发过程中的Code Review可以使用 WIP 前缀来标注

WIP:work in progress
评审人在注意到 WIP 开头的 Code Review 时可以暂时忽略

我们并不能保证每次评审发起后都是一个完整功能或者 fix,例如在发起评审后突然意识到有设计缺陷,或者意识到提交的代码缺少了 UT 覆盖等问题,评审人在不知情的情况下可能随时对你的代码进行评审,为了避免评审人将时间浪费在还未完成开发的 Code Review 上,创建人有义务将标题改成 WIP 前缀,Code 平台会限制这种 Code Review 的合并行为,评审人可以忽略这种评审。

4.1.7 解决所有 CheckList

每个评审创建人都要对自己的 Code Review 负责,确保 Code Review 达到最终可合并状态,这里的可合并状态并不是有人通过即可,还包括测试用例的状态,Trybots 的状态,评论的状态。 Code Review 会在突出位置展示当前未完成的任务。

作者需要确保 Code Review 的 Checklist 全部解决,其中包括:

4.1.8 尊重评审人的评论

尊重评审人的劳动,针对评审人提出建议或者反馈的评论,请给出适当的回应,虽然 Code Review 平台允许创建人将评论置为已解决,但不进行任何回复是不恰当的。
保持谦逊,任何人的代码都可能有改进的空间,哪怕你是这个领域的专家,提交的代码都有可能出现错误,承认不完美才是专业的表现。

4.1.9 利用格式化扫描插件来实现风格统一

尽管希望借助Code Review来实现代码仓库的风格统一,但将宝贵的精力用于敦促代码风格统一上是得不偿失的,各团队技术负责人配置自动化扫描插件来完成,例如Eslint、P3C、SpotLess。并配置Aone实验室任务、配置CR卡点等。

针对 Java 语法就有一些常见的风格扫描插件,例如:

4.2 作为评审人的最佳实践

4.2.1 尽快评审

把评审代码作为工作的一部分,和开发者尽快发起评审的原则一样,评审人需要留出足够的时间尽快完成评审。越早发现问题,修改代码的成本越低,修改意愿也越高。如果当前没有时间评审,也要明确告诉评审人会在什么时间点前完成,甚至将评审工作转交给其它同事完成。

4.2.2 对逻辑和质量进行评审

4.2.2.1 实现逻辑

Code Review 应该着重对业务逻辑进行检查

4.2.2.2 代码质量

提升代码质量是Code Review的重要目的,Code Review 可以对代码风格、规范、可维护性等进行检查。

但这部分审查不应该作为评审重点,产品或者技术负责人应当选择合适的扫描插件并配置合适的扫描任务来完成扫描和准入。

4.2.3 针对代码,而不是作者

Code Review 针对的是代码而非作者,尽量不要指责代码作者的行为和态度,同时也需要能够接受不同的方案,任何问题总有很多不同的方案,你有的只是你个人倾向的方案,但别人的方案可能同样没有问题。

4.2.4 避免过度追求完美

避免苛求每一行的代码都是完美的,避免以找问题的心态进行 Code Review,要抓住 Code Review 的关注重点反馈,另外,并非一定要找到问题才证明你在认真评审,若针对作者的每一行代码评审,很可能会惹恼到作者,也影响到他们对你的反馈的接受。

4.2.5 不要吝啬自己的赞美

毫不吝啬的正向反馈也有助于 Code Review 的实践落地,在日常 CR 中,通常的反馈都是问题或建议,鲜有称赞,但代码评审的目的不应该仅仅是发现错误和问题,还应该鼓励和指导开发人员所完成的出色工作。可以通过分享、点赞等方式等来评价。

4.2.6 明确评论是否要解决

评审人在发起评论时需要明确指出该评论是否需要被解决,代码平台支持评论标签,支持标注评论是否需要被解决,被标注为不需要解决的纯讨论性评论不会被计入 Check List。对于代码修改建议,需要给出明确的论据或者示例。

另外可以利用标题的描述对 Review 的评论进行分级,告诉开发者应该如何处理这个评论,例如给评论增加Optional前缀。

4.2.7 避免使用反问句来评价

避免使用反问句来质疑代码逻辑,通常来说当你 Code Review 代码时保持礼貌和尊重能使开发人员更加清晰,得到更多帮助。也要避免用负面词汇来评价代码。

🙅🏻‍♀️ 不好的例子: “Catch 异常都不精确的?直接一把抓的?那怎么区分出不同的异常呢?”

👌 好的例子: “我并没有发现这个并发模块给程序带来了多少帮助,并且还增加了程序的复杂性,因此我认为这段代码最好是用单线程而不是多线程。

5. 小结

想要推动 Code Review 在团队中更好地实施,很重要的一点便是增强团队成员对 Code Review 的认同感。 如果团队成员不认可 Code Review,即使强制设置了 Code Review 流程,也是形同虚设,反而影响正常开发流程的效率。相反的,如果团队同学都认可“ Code Review 是提升代码质量、提升研发效率的核心手段”,那么团队成员的主观能动性会越来越高,互相学习的氛围越来越浓,帮助别人的同时,也能有效提升自己的代码能力。Code Review 的价值得以最大化,最终实现整体提升研发效率提升。

资料引用

  1. https://phauer.com/2018/code-review-guidelines/?spm=ata.21736010.0.0.21977536LqogJB#code-reviews-guidelines-for-the-reviewer
  2. Google Code Review 规范:https://google.github.io/eng-practices/review/
  3. CODE REVIEW中的几个提示