资深的程序员都知道 Code Review 可以对代码质量,代码规范,团队代码能力提升带来很大的提升,还有著名的技术专家“左耳朵耗子”也说过:

我认为没有 Code Review 的公司都没有必要呆(因为不做 Code Review 的公司一定是不尊重技术的)

  • 出自《程序员的练级攻略 - 修养篇》

国外很多技术公司都非常重视 Code Review 也都做的特别好,例如 Google,亚马逊,但是国内很多公司在践行 Code Review 的时候却是步履蹒跚,步步艰难,选用的方法不对,最终导致事倍功半的结果,总结一下我见过的几种情况:

  • 因为 Code Review 导致团队成员之间相互指责,团队凝聚力产生间隙
  • Code Review 形式化,没有提升代码质量,减少 bug,反而降低开发效率
  • Code Review 确实产生了效果,但是因为流程太重,导致团队效率降低

我们也在践行 Code Review,探索的路上也遇到一些障碍和经验,总结分享一下,如果你也遇到这些问题,或许可以花一点时间读一读这篇文章,说不定会有帮助。

Code Review 能带来哪些好处,本文就不说了,大家都很熟悉了,本文主要简单说一下 Code Review 有哪几个基本的共识和原则:

  1. Code Review 高效的原则是用机器去做大部分的事情
  2. Code Review 的时机(天时地利人和)
  3. 推行 Code Review 的关键原则

Code Review 高效的原则是用机器去做大部分的事情

不同的语言的格式和风格都是比较固定的,例如我最熟悉的 Java 语言常见的风格有以下几种规范:

  1. Order Java SE 的标准规范:https://www.oracle.com/technetwork/java/codeconvtoc-136057.html
  2. Google Java 开发规范: https://google.github.io/styleguide/javaguide.html
  3. 阿里巴巴 Java 开发手册:https://github.com/alibaba/p3c (国内常用)

还有我最近常用的 Ruby 语言,官方所推崇的几种风格规范:

  1. Ruby Style Guide:https://github.com/rubocop-hq/ruby-style-guide
  2. Airbnb Ruby Style:https://github.com/airbnb/ruby

但凡是标准规范都是比较机械化的条条框框,应该交给机器去检查(常用的工具由:P3C,Rubocop,SonarQube 等),机器静态扫描效率不仅比人高出一个数量级,而且非常严谨,不容易出错,甚至可以武断的说:所有的自动化工具的本质,都是为了要减少对人的依赖性,因为人本身是具备很多种不确定性,所以并不适合做一些需要确定性并且反复重复的事情

Code Review 的时机(天时地利人和)

在以往的工作经验中,Code Review 越是靠左移,修改代码的成本越低,开发人员的修改意愿也就越高,那什么叫左移?

我们看一下软件开发的流水线和个人认为最合理的 code review 时机:

软件工程的开发流水线(图)

从流水线上来说,有些人会在临近上线,在靠右的地方合并 master 的时候才进行 code review,这个时候修改成本就很高,因为代码已经测试过,如果因为 code review 有问题需要重新修改代码,那么功能本身又要回归测试,占用的测试双倍的时间,对于人力资源是双倍的浪费,因为已经临近上线,却因为 code review 被打回,开发人员愿意重构代码的意愿也会很低,如果明明发现问题,又因为上线压力,不打回不符合规范的代码,那么久而久之大家失去对 code review 的敬畏心理,code review 也会慢慢变成形式化,应用发布流程而已,既不能提高代码质量,降低系统 Bug,也不能提升开发人员的水平,反而降低的开发团队的效率,所以选择在上线前进行 code review 不是一个好主意,所以从性价比上来说 code review 最好的时机应该是在 功能分支自测完成后,需要合并到 develop 分支申请提测前 通知项目组成员对增量的代码进行 code review。

所以,代码审查要高效的话,核心就是要追求快速反馈,越早发现代码问题修改的成本就越低,具体参考下图:

这里需要注意的是,代码在经过机器扫描后(这里有一个技巧就是可以在 GitLab CI 加入自动的代码风格检查,代码静态扫描是一个高频操作,一天可能会有几十,甚至上百次的 Commit,如果接入 GitLab CI 实现自动化静态扫描,大家不需要在自己本地执行静态扫描,那么效率也会大大的提升),项目组成员只需要把注意力放在 代码逻辑结构,功能设计的可维护,可扩展性 等机器不容易发现问题的地方上,然后就完成代码审查。因为代码还未提测,所以就算 Merge Request 不合格被打回后,因为还未提测,也不会占用测试人员的资源,开发人员的修改意愿也会更高,总体来说是可以达到高效和质量的要求

Code Review 要计入开发的工作量

很多团队不做 code review 都有一个共同的原因是觉得浪费时间,结果导致糟糕的代码合并入库,频繁出现线上问题,然后开发人员疲于奔命的去修复线上事故 BUG,虽然短期来看功能是快速上线了,但是算上复工的时间,长期来看整体的交付周期还是被拉长了,整体还是低效的,而且糟糕的生产质量人很容易打击开发人员的持续生产高质量代码的信心,所以将 code review 计入开发的工作量是重视长期利益的一种做法,也是 code review 能够成功落地的重要前提,从团队管理的角度来说,不计入工作量的事情就不会被重视,不被重视的话那么 code review 最终在团队只会被废弃或者流于应付形式,并未发挥作用。也是很多团队推行 code review 失败的原因。

推行 Code Review 的关键原则

想要在审核代码的时候,避免团队成员因为某些模糊不清的细节争论不休的情况,那么就要提前让团队建立对代码审核的原则和方法达成共识,我就曾经见过团队的技术人员在代码审核的时候因为某个函数方法的实现方式争吵不休,各自都认为自己的实现是正确的,那么提前建立一下这种共识:

相互尊重原则

站在代码作者的角度:

  1. 审核人花费时间和精力阅读他不熟悉的代码,并且帮忙指出代码中的问题来帮助代码作者提高,代码作者应该尽可能的为审核人提供配合和方便
  2. 代码作者提交高质量的代码,就是对审核人和审核团队的最基本尊重(提交一堆乱如麻花的代码,没有自测错误百出的代码是极度不负责任的表现)
  3. 最好要有清晰的 commit 历史,让人可以一目了然代码的提交内容,如果代码过度复杂,那么就需要和审核人面对面沟通,才能足够的高效

站在代码审查者的角度:

  1. 一定要懂得相互尊重,提出建议要懂得换位思考,考虑代码作者的感受,不要用主观的批评或者情绪化的语气指责团队的同事
  2. 提出代码改进建议,必须是基于事实,或者明确的代码规范文档,不可强行把个人喜好强加在对方身上(例如用不同的语法实现相同的功能 for/while )
  3. 不要钻进代码的牛角尖和抠细节,人工审查更多的要把精力放在代码逻辑,功能设计等无法扫描的问题上
建立共识

站在团队的角度:

  1. code review 的目标长期来看,收益是提升团队的项目质量,减少团队陷入反复修复 bug 的困境中,让团队有机会去面对更多的挑战
  2. code review 对个人和团队而言都是成长的机会,放下不必要的自尊心,要用开放的包容的心态去接受不同的意见,取其精华

总结

以上就是我个人和团队在 code review 中的实践和总结,Code Review 关键还是要结合团队的情况选择合适的审查方式,如果团队追求敏捷开发,快速迭代那么集中式的代码审查会可能就不太适合你们当前的团队,可能项目成员 1 对 1 的结对编程可以更加高效的完成代码审查,每个团队的发展阶段不同,适用的 GitFlow 开发流程也不同,反正没有最好的工具,最有最合适的工具。

CodeReview 的经验和原则的更多相关文章

  1. atitit.提升研发效率的利器---重型框架与类库的差别与设计原则

    atitit.提升研发效率的利器---重型框架与类库的差别与设计原则 1. 框架的意义---设计的复用 1 1.1. 重型框架就是it界的重武器. 1 2. 框架 VS. 库 可视化图形化 1 2.1 ...

  2. android( java) 处理 null 和 预防空指针异常(NullPointerException) 的一些经验。

    概述: 在实际编码中总是会遇到 空指针异常 ,本文总结了一些处理空指针的个人经验. 原则: 尽早的检查,尽早的失败. 比如: 通过intent传参到新的目标 activity,而且一定需要这个参数,那 ...

  3. atitit.提升研发效率的利器---重型框架与类库的区别与设计原则

    atitit.提升研发效率的利器---重型框架与类库的区别与设计原则 1. 框架的意义---设计的复用 1 1.1. 重型框架就是it界的重武器. 1 2. 框架 VS. 库 可视化图形化 1 2.1 ...

  4. WCF分布式开发步步为赢(6):WCF服务契约继承与分解设计

    上一节我们学习了WCF分布式开发步步为赢(5)服务契约与操作重载部分.今天我们来继续学习WCF服务契约继承和服务分解设计相关的知识点.WCF服务契约继承有何优势和缺点?实际项目里契约设计有什么原则和依 ...

  5. ASP.NET网站中设置404自定义错误页面

    在用ASP.NET WebForm开发一个网站时,需要自定义404错误页面. 做法是这样的 在网站根目录下建立了一个404.html的错误页面,然后在Global.asax文件中,加入如下代码: &l ...

  6. 走进小作坊(十一)----移动web实现指南

    四.五年前智能手机行业刚刚兴起,差别于之前功能机阉割版的web开发方式,一些学者就開始探索移动web的UI方向了.从PC迁移到移动端的web设计现成可用的原则有,很多其它的则是依据移动端独有特点进行探 ...

  7. 毕业后的第二份工作:进入国外 在新加坡工作 每月一次18K

    --訪传智播客成都校区12.26就业班学员 杨洋 姓名:杨洋 毕业院校:重庆科技学院 专业:电子信息技术与project 就职公司:新电科技 岗位:Javaproject师 月薪:18K 上午.他刚去 ...

  8. session的使用

    一.什么是session? Session:在计算机中,尤其是在网络应用中,称为“会话控制”.Session 对象存储特定用户会话所需的属性及配置信息.这样,当用户在应用程序的 Web 页之间跳转时, ...

  9. JVM GC(整理)

    1 GC类型 1 )YGC  一般情况下,当新对象生成,并且在Eden申请空间失败时,就好触发YGC ,堆Eden区域进行GC,清除非存活对象,并且把尚且存活的对象移动到Survivor区.然后整理S ...

随机推荐

  1. 集训作业 洛谷P1433 吃奶酪

    嗯?这题竟然是个绿题. 这个题真的不难,不要被他的难度吓到,我们只是不会计算2点之间的距离,他还给出了公式,这个就有点…… 我们直接套公式去求出需要的值,然后普通的搜索就可以了. 这个题我用的深搜,因 ...

  2. T3 成绩单 题解

    这个题本来不归我讲,但我A完之后觉得太坑了,还是讲一下吧. 首先这个题有个重要的地方:(字典顺序,学号全为小写字母,从小到大排列) 字典序和字典顺序是不一样的!!! 我以为是字典序……,wa了,字典顺 ...

  3. 用c#自己实现一个简单的JSON解析器

    一.JSON格式介绍 JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.相对于另一种数据交换格式 XML,JSON 有着很多优点.例如易读性更好,占用空间更 ...

  4. Redis Desktop Manager安装

    Windows安装: 1.下载安装包 官网下载地址:https://redisdesktop.com/pricing 官网下载需要付费使用 再此附上一个免费的破解版本,绿色安全可用 链接:https: ...

  5. 火狐浏览器如何使用二次验证码/虚拟MFA/两步验证/谷歌验证器?

    一般点账户名——设置——安全设置中开通虚拟MFA两步验证 具体步骤见链接  火狐浏览器如何使用二次验证码/虚拟MFA/两步验证/谷歌验证器? 二次验证码小程序于谷歌身份验证器APP的优势 1.无需下载 ...

  6. MySQL(二)表的操作与简单数据操作

    六大约束:主键约束.外键约束.非空约束.唯一约束.默认约束.自动增加 1.not null非空 2.defaul默认值,用于保证该字段的默认值 ; 比如年龄:1900-10-10 3.primar k ...

  7. 开源项目推荐 - 巨鲸任务调度平台(Spark、Flink)

    Big Whale(巨鲸),为美柚大数据研发的大数据任务调度平台,提供Spark.Flink等离线任务的调度(支持任务间的依赖调度)以及实时任务的监控,并具有批次积压告警.任务异常重启.重复应用监测. ...

  8. Zabbix3.2安装

    一.环境 OS: CentOS7.0.1406 Zabbix版本: Zabbix-3.2 下载地址: http://repo.zabbix.com/zabbix/3.2/rhel/7/x86_64/z ...

  9. parted分区

    ((parted)mklabel ----创建磁盘标签New disk labeltype? gpt ---输入磁盘表情名(parted) p ----再次列出磁盘分区 (parted) mkpart ...

  10. linux的/etc/passwd、/etc/shadow、/etc/group和/etc/gshadow

    1./etc/passwd  存储用户信息 [root@oldboy ~]# head /etc/passwd root:x:::root:/root:/bin/bash bin:x:::bin:/b ...