如何在团队中做好Code Review
一、Code Review的好处
想要做好Code Review,必须让参与的工程师充分认识到Code Review的好处
1、互相学习,彼此成就
无论是高手云集的架构师团队,还是以CURD为主的业务开发团队,大家的技术能力、经验都是有差异的。
通过Code Review,对于同样的功能实现,有经验的工程师可以给经验尚浅的工程师提供合理的优化建议。经验尚浅的工程师可以通过阅读优质代码,快速学习相关技术运用的最佳实践。如果大家技术实力相当,可能就是互相刷新思想了。
你有一个苹果,我有一个苹果,彼此交换一下,我们仍然是各有一个苹果;但你有一种思想,我有一种思想,彼此交换,我们就都有了两种思想,甚至更多。
2、知识共享,自动互备
在大部分团队,尤其是采用服务化架构以及微服务架构的团队,通常都是1个开发人员负责多个服务/项目(Project),如果没有Code Review,那么项目中所涉及的架构知识,或者业务知识,就只存在于项目执行过程中产出的架构文档,以及核心流程、功能的说明文档了。
文档可以帮助其他工程师了解服务/项目的情况,但通常其他工程师不会主动去阅读这些文档,等到真的要维护别的工程师写的代码,文档的完整性往往没有最初的效果好了,文档跟代码实现的匹配度也会下降。
Code Review的过程,就是根据提交者的描述阅读代码的逻辑,看代码实现是否跟描述一致。在这个时候,Reviewer就必须阅读文档,知识的传播性就更好,也基本上不会出现只有1个人了解某个项目的情况了。
3、统一风格,提升质量
如果要给代码质量分一下等级的话,那应该是:
可以编译通过->可以正常运行->可以测试通过->容易阅读->容易维护。那么,通过Code Review的代码最起码可以达到易阅读这个级别。
要做到易阅读,可不是说只要有Code Review这个环节就可以了,还要有相关的规范,让大家按照同样的工程风格、编码风格去构建项目和编写代码。统一风格一方面是让大家无论是维护项目还是阅读代码,不用互相适应各自的编码习惯,另外也是给Reviewer一个Code Review的基本依据。
发现Bug不是Code Review的必需品,而是附属品。至于那些低级的问题/bug交给代码扫描工具就可以了,这不是Code Review的职责。
二、推动Code Review落地执行
1、选定工具
可以用来做Code Review的工具很多,这里主要介绍相对主流的Gerrit、GitLab
- Gerrit
Gerrit是Google开源的代码审查工具,Gerrit也是一个基于Git构建的版本管理工具,Gerrit支持将其他Git仓库的代码跟Gerrit自己的仓库做同步。所有的代码审查的操作以及权限控制都是在Gerrit自己的仓库上进行的。
Gerrit是面向代码审查来构建的,所以在代码审查的权限控制,以及功能上都是非常完善的。
Gerrit是可以强制CodeReview的,支持Develop、Reviewer、Approver三种角色支持对每个Project配置不同的CodeReview的人员以及权限。
如果要根据Gerrit的数据做一些统计报表,就直接访问Gerrit的数据库,如果功能上不满足要求,反正是开源的,有Java研发团队就可以自己定制
总之,Gerrit的Code Review功能是非常完善的,缺点可能就是UI、交互太老了以及平台的管理功能较弱。
- GitLab家族
GitLab是基于Git构建的源代码管理系统,基于GitLab构建的 GitLab.com 是仅次于 GitHub.com 的在线源代码管理平台。
GitLab分GitLab CE(社区版)和 GitLab EE(企业版)两个版本,开源的社区版功能相对会弱一点,但是免费使用,可以自由部署、定制、维护。企业版功能强大,但是需要收费的。
GitLab可以通过MergeRequest来Review代码,也可以做到强制CodeReview,社区版支持Develop、Reviewer两种角色,企业版支持Develop、Reviewer、Approver三种角色,可以给给项目/组分配不同的角色(Master、Developer)来控制Merge代码的权限。
如果需要根据GitLab的数据做一些统计报表,GitLab提供了非常友好的restful API,如果要定制化,建议是通过API来做定制化的工具,不受编程语言限制。
GitLab的Code Review的功能没有Gerrit功能完善,但是GitLab附带的文档功能、以及GitLab完善的管理后台都要比Gerrit更好,如果要做CI/CD,GitLab的社区版几乎是最佳选择
- Gerrit VS GitLab 综合对比
工具 | 权限 控制 | UI 交互 | 源代码 管理 | 可维护 | 数据 统计 | 工具 配套 |
---|---|---|---|---|---|---|
Gerrit | ⭐ ⭐ ⭐ ⭐ ⭐ | ⭐ ⭐ | ⭐ ⭐ ⭐ | ⭐ ⭐ | ⭐ ⭐ ⭐ ⭐ | ⭐ ⭐ |
GitLab社区版 | ⭐ ⭐ ⭐ | ⭐ ⭐ ⭐ ⭐ ⭐ | ⭐ ⭐ ⭐ ⭐ ⭐ | ⭐ ⭐ ⭐ ⭐ ⭐ | ⭐ ⭐ ⭐ ⭐ ⭐ | ⭐ ⭐ ⭐ ⭐ ⭐ |
GitLab企业版 | ⭐ ⭐ ⭐ ⭐ | ⭐ ⭐ ⭐ ⭐ ⭐ | ⭐ ⭐ ⭐ ⭐ ⭐ | ⭐ ⭐ ⭐ ⭐ ⭐ | ⭐ ⭐ ⭐ ⭐ ⭐ | ⭐ ⭐ ⭐ ⭐ |
Gerrit强项只有Code Review的控制,GitLab的功能更全面,但GitLab的企业版是收费的。所以,综合来说,我更推荐GitLab社区版
基于GitLab的CodeReview教程:https://ken.io/note/gitlab-co...
2、制定开发规范
没有规则,就没有执行。规则中首当其冲的就是开发规范。
规范中建议包含:
- 工程规范(工程结构,分层方式及命名等等)
- 命名规范(接口、类、方法名、变量名等)
- 代码格式(括号、空格、换行、缩进等)
- 注释规范(规定必要的注释)
- 日志规范(合理的记录必要的日志)
- 各种推荐与不推荐的代码示例
如果团队人数较少,项目的工程复杂度较低,可以自行制定规范。毕竟适合团队的就是最好的。
如果团队有一定规模,且还会不断扩张,还是建议根据大厂的规范进行制定,或者是直接采用。
Java开发手册:https://github.com/alibaba/p3c
Google代码风格指南:https://zh-google-styleguide.... (涵盖:C++、Python等)
3、制定流程规范
- 确定Code Review实施环节
CodeReview建议是放在代码提交测试前,也就是开发人员完成代码开发及自测后将代码提交到测试分支时进行Code Review。毕竟,如果测试通过后再进行Code Review,如果需要代码变更,势必会增加测试的工作量,甚至影响项目进度。亦或是顶着项目上线的压力,干脆“以后再说”了
以通用的Git Workflow来说,那就是把Code Review放在Feature分支合并到Develop分支时了。
- 制定角色行为规范
角色 | 规则 |
---|---|
Developer | 1、一次提交的功能必须是完整的 2、默认细粒度提交(以独立的方法/功能/模块为单位)。如需粗粒度提交,需提前跟Reviewer沟通确认 3、Commit Message中要清晰描述变更的主题 必要时,可以以链接或者文件的形式附上需求文档/设计文档 |
Reviewer | 1、不允许自我Review并Merge代码 2、Review不通过打回前需跟Developer说明原因并达成一致 3、Review不通过需明确填写打回的原因 4、单次Review时长需控制在2分钟~2小时内完成(特殊情况请说明原因) |
Approver | 1、审批不通过需注明原因<br/>2、审批时长需要控制在1小时以内 3、对于放行的非质量问题,需持续跟进 |
这样规范,主要是为了:
- 控制提交Code Review的代码的粒度
- 控制单次Code Review的时间
- 提升Commit/MergeRequest描述的质量,减少沟通成本
这样,我们就可以通过细粒度高频次的方式尽可能利用工程师碎片化的时间进行Code Review,一定程度上保证Code Review的效率。
毕竟,粗粒度甚至是集中式的Code Review,时间上难以把控。发现了问题的时候,修复的成本也往往更高。
4、分享与统计
有了工具、开发规范、流程规范,就可以指引参与的工程师参与Code Review,那么我们也要对Code Review的过程以及结果进行检验,毕竟不进行检查/验收的规则,是无法达到预期效果的。
Code Review毕竟不是数学题,我们无法通过简单的计算去验证。所以我们要通过侧面验证,来帮助Code Review的执行
- 定期分享
我们是期望CodeReview可以让工程师之间互相学习的,那么对于一次Code Review通常只有参与的2-3个工程师有互相学习的机会,那么在这个过程中学到的知识,定期的分享出来,既可以加强知识的流动,又可以检查大家究竟有没有在Code Review过程中学习到知识,或者有没有认真的进行Code Review
至于分享的内容,可以是开发规范中的范例代码,也可以是规范中的正例代码,也可以是针对某个功能实现的最佳算法/最佳实践,也可以是Code Review过程中的争议代码,也可以是自己踩过的坑。
总之,Code Review之后的代码分享,不但可以加强知识的流动,还可以检验Code Review的效果。
- 数据统计
为了在一定程度上保证Code Review的效率,我们在规范里是要求参与的工程师:
- Developer控制提交Code Review的粒度,或者控制每个Commit的粒度
- Developer要准确清晰的描述所提交的代码
- Reviewer&Approver要在规定时间内完成Code Review
这些情况纯粹靠人工是无法检验的,还是需要有一定的数据统计。
如果用Gerrit,可以查询Gerrit的数据库,里面会有Code Review的信息,
如果用GitLab,可以通过WebHook或者restful API获取Code Review信息
我们可以做成报表,来展示Code Review的情况:
- 每人每周Code Review所消耗的时间
- 每人每周被Code Review所消耗的平均时间
- 超过规定时间的Code Review情况
- 代码提交描述字数过少的情况
- 等等(根据自己的需要来)
以上情况只是Code Review的侧面反馈,用来帮我们发现Code Review执行过程中可能出现的问题。不过,出现问题并不意味着Code Review的质量/效率一定受到了影响。
比如,工程师A被Code Review的耗时是团队内最高,有可能是有某次代码是周五晚上提交的CodeReviw,这单次CodeReview的耗时就会超过48小时。也有可能是对应的Reviewer是团队新人,要通过相关业务项目了解对应Project的承担的职责及代码,这是个学习的过程,自然耗时加长。
又比如工程师B提交的代码描述文字过少,可能就是中间件团队对某些基础组件进行升级,或者安全团队要求升级某个依赖的开源组件,以修复某个安全漏洞。
但是通过这种的数据,可以让Code Review的情况直观的展示出来。来发现大家执行过程中需要优化的事项, 不断帮助大家完善规则,做好执行。
三、保证Code Review质量的关键
1、工程师对研发规范的认真学习
无论Code Review的工具以及流程是怎么样的,都少不了开发规范作为支撑,毕竟我们期望Code Review达到的效果之一就是,团队中的工程师可以写出像规范中描述那样的高质量代码。
工程师对研发规范的掌握程度,决定了自己编码代码的质量,也决定了自己Review通过的代码的质量。所以,无论如何,加强对研发规范的学习和理解,都是保证Code Review质量的重中之重
2、资深工程师的认真对待
Code Review目的是帮助工程师交流和学习进步的。无论是技术能力还是编码习惯,亦或是业务知识。无论规则怎么制定,终究还是需要参与的工程师来执行,如果大家互相睁一只眼闭一只眼,互相降低要求,那么执行的效果一定会打折扣。
虽说三人行必有我师,但收益最大的一定是经验(技能/业务知识)尚浅的工程师,收益最低的一定是团队中最资深的工程师。而恰恰经验尚浅的工程师的收益大部分都要来自资深工程师的付出。
所以,一定要跟资深工程师最好沟通,让他们严格要求,不能对经验尚浅的工程师放水,以帮助他们提升编码能力以及业务知识。
这也可以减少甚至避免他们为经验尚浅的工程师的代码“善后”。
四、备注
附录
- Java开发手册:https://github.com/alibaba/p3c
- 基于GitLab的CodeReview教程:https://ken.io/note/gitlab-co...
- Google代码风格指南:https://zh-google-styleguide....
- Jenkins+Sonar执行代码扫描:https://ken.io/note/jenkins-m...
相关文章:

分布式服务框架 Zookeeper -- 管理分布式环境中的数据
2019独角兽企业重金招聘Python工程师标准>>> 转自:http://www.ibm.com/developerworks/cn/opensource/os-cn-zookeeper/ Zookeeper 分布式服务框架是 Apache Hadoop 的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题&am…

ubuntu18下配置VS Code
配置逻辑主要是 launch.json指定预先处理的任务(preLaunchTask)及读取build文件(program) tasks.json指定输入原始文件和输入build文件(args) 参考:https://www.cnblogs.com/JsonZhangAA/p/9750282.html launch.json中的配置 {"version": "0.2.0","co…

Blender钢铁机器人建模与动画全流程制作视频教程
Blender钢铁机器人建模与动画全流程制作视频教程 流派:电子学习| MP4 |视频:h264,1280720 |音频:AAC,44.1 KHz 语言:英语中英文字幕(根据原英文字幕机译更准确) |大小:15.8 GB |时长:19.5小时 使用软件:…
android 模板 ui布局,Android UI布局
一、线性布局-LinearLayout(至上而下布局)其中android:orientation”vertical”意思为垂直方向的线性布局,此处的”vertical”可改为”horizontal”,意思是水平方向的线性布局。android:layout_width”match_parent”意思为这个控件的宽度占满整个屏幕或者父控件&am…

两数的加减乘除
设计思路: 首先要解决把输入的字符转化为计算的数字的问题,然后解决怎样用消息框输入输出即可。 程序流程图: 源代码: 实验结果: 转载于:https://www.cnblogs.com/wxyxxx/p/4859039.html

使用Docker搭建svn服务器教程
使用Docker搭建svn服务器教程 svn简介 SVN是Subversion的简称,是一个开放源代码的版本控制系统,相较于RCS、CVS,它采用了分支管理系统,它的设计目标就是取代CVS。互联网上很多版本控制服务已从CVS迁移到Subversion。说得简单一点…
SDK Instrumentation创建一个Note的实例
除了高层框架如Robotium的solo,我们也可以直接调用SDK底层的提供的Instrumentation的API来实现如前几篇文章描述的创建一个note的功能。总所周知之Robotium就是基于Instrumentation的框架高层抽象实现的一个项目,所以对比《Robotium创建一个Note的实例》…

UOJ #53.线段树区间修改
【题目描述】:如题,已知一个数列,你需要进行下面两种操作:1.将某区间每一个数加上x2.求出某区间每一个数的和 【输入描述】:第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。第二行包含N个…

Blender三维插图设计视频教程 3D Characters and Illustrations in Blender 2.9
Blender三维插图设计视频教程 3D Characters and Illustrations in Blender 2.9 MP4 |视频:h264,1920x1080 |音频:aac,44100 Hz |时长:16h:06分钟|文件大小:4.75 GB 流派:电子学习|语言:英语 云桥网络 平台 获取 教程 本课程详细介绍了blender 4个案…

android mac测试地址,android获取有线网的Mac地址
Android TV开发中有的机器会接有线网,需要获取Mac地址,下面是我测试的两种Mac地址的获取方式。1.一共两个方法,目前第二个方法获取的不准,最后一位数取的不对。private String getMacAddress(){String strMacAddr null;try {Inet…

[高中作文赏析]感受冬天
转载于:https://www.cnblogs.com/zhangzujin/p/4864725.html

2022-2028年中国文化产业园投资分析及前景预测报告(全卷)
【报告类型】产业研究 【报告价格】4500起 【出版时间】即时更新(交付时间约3个工作日) 【发布机构】智研瞻产业研究院 【报告格式】PDF版 本报告介绍了中国文化行业市场行业相关概述、中国文化行业市场行业运行环境、分析了中国文化行业市场行业的…

matlab 降维工具箱
Matlab Toolbox for Dimensionality Reduction降维方法包括:Principal Component Analysis (PCA) • Probabilistic PCA • Factor Analysis (FA) • Sammon mapping • Linear Discriminant Analysis (LDA) • Multidimensional scaling (MDS) • Isomap •…

程序还没写完只能当然计算器用,先发过来用着后面的慢慢写
真的是没办法,只好先发上来用着,后面的要先处理事情,等处理完接着写!! http://files.cnblogs.com/mari/starco.rar 这个是地址!!!转载于:https://www.cnblogs.com/mari/archive/2004/12/22/80317.html

Servlet生命周期与工作原理
Servlet生命周期分为三个阶段: 1,初始化阶段 调用init()方法 2,响应客户请求阶段 调用service()方法 3,终止阶段 调用destroy()方法 Servlet初始化阶段: 在下列时刻Servlet容器装载Servlet: 1&#…

ue4中面部动画制作视频教程 Facial Animation More In Unreal Engine 4
ue4中面部动画制作视频教程 Facial Animation & More In Unreal Engine 4 时长4h 包含项目文件 1920X1080 MP4 大小解压后:5.75G 语言:英语中英文字幕(根据原英文字幕机译更准确) 面部动画&虚幻引擎4中的更多内容 信息…

android c聊天功能,Android实现简单C/S聊天室应用
Android的网络应用:简单的C/S聊天室,供大家参考,具体内容如下服务器端:提供两个类创建ServerSocket监听的主类:MyServer.java负责处理每个Socket通信的线程类:ServerThread.java客户端:是一个Android应用程序>Multi…

docker 容器访问宿主机的解决方式
需求 基于本地docker的自研及使用需要,希望docker容器的服务能连接到宿主机提供的服务。 背景 网络上查阅了大量的资料,基本的解决办法是通过手动查阅IP的方式进行, 但docker宿主机的ip是会动态改变的,并不能保证永久不变。因此…

WinAPI: 输入光标相关的函数[3]
为什么80%的码农都做不了架构师?>>> 本例测试修改光标的形色, 效果图: 代码文件: unit Unit1;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls, ExtCtrls;typeTForm1 class(TForm)RadioGr…

用泛型方法Java从实体中提取属性值,以及在泛型方法中的使用
public <T> T getFieldValue(Object target, String fieldName, Class<T> typeName){try {Object fieldValue FieldUtils.readField(target, fieldName, true);return (T)fieldValue;} catch (IllegalAccessException e) {log.error("出错:实体类{}没有{}类型…

藤本植物和攀爬植物模型包 Globe Plants – Bundle 23 – Vines and Creepers 03 (3D Models)
藤本植物和攀爬植物模型包 Globe Plants – Bundle 23 – Vines and Creepers 03 (3D Models) 全球植物–第23束–藤本植物和攀缘植物03 (3D模型) 大小解压后:1.73G 云桥网络 平台huo取素材 这个捆绑包23包括15种3D藤本植物和攀缘植物,用于一般的景观…

蘑菇模拟器TV版 for Android,安卓NES模拟器TV版下载
NES Emulator TV精选了上千款经典的红白机小游戏,我们小时候玩过的经典游戏都能够在这里找到,每一款游戏在这里都能够分别存档,没有太多时间的上班族可以尝试一下,给玩家带来最好的游戏体验。软件简介NES模拟器精选上千款红白机游…

由Node.js事件驱动模型引发的思考
引言 近段时间听说了Node.js,很多文章表述这个事件驱动模型多么多么优秀,应用在服务器开发中有很大的优势,本身对此十分感性去,决定深入了解一下,由此也引发了一些对程序设计的思考,记录下来。 什么是Node.…

2022-2028年中国未硫化橡胶制品行业市场运行格局及未来前景展望报告
【报告类型】产业研究 【报告价格】4500起 【出版时间】即时更新(交付时间约3个工作日) 【发布机构】智研瞻产业研究院 【报告格式】PDF版 本报告介绍了中国未硫化橡胶制品行业市场行业相关概述、中国未硫化橡胶制品行业市场行业运行环境、分析了中…

使用 TListView 控件(3)
为什么80%的码农都做不了架构师?>>> 本例效果图: 代码文件: unit Unit1;interfaceusesWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,Dialogs, StdCtrls, ComCtrls;typeTForm1 class(TForm)ListView1: TListView;Button…

POJ 1038 Bugs Integrated Inc (复杂的状压DP)
\(POJ~1038~~*Bugs~Integrated~Inc:\) (复杂的状压DP) \(solution:\) 很纠结的一道题目,写了大半天,就想练练手,结果这手生的。其实根据之前那道炮兵阵地就不应该写的,但是总觉得自己的思路会好一些&#x…

Blender基础入门学习教程 Learning Blender from Scratch
Blender基础入门学习教程 Learning Blender from Scratch 流派:电子学习| MP4 |视频:h264,1280720 |音频:aac,48000 Hz 语言:英语中英文字幕(根据原英文字幕机译更准确)|大小:5.5 GB |时长:7h 28m 你会学到什么 云…

android 事件冒泡,Android事件分发
当用户触摸屏幕时,系统会对触摸事件做出相应的相应,这个事件会产生一个MotionEvent,系统根据一定的规则将其传递给View进行处理,这个过程就是事件分发机制了。事件的传递分为两个阶段,即捕获阶段和冒泡阶段。捕获阶段&…

sqlserver trigger
1 --2 -- Create database trigger template 3 --4 USE [EasyJobExTest]5 GO6 7 --判断触发器是否存在,存在则删除8 IF EXISTS(9 select top 1 t.name as trigger_name,a.name as table_name from sys.triggers t,sys.objects a 10 where Lower(a.name)section and t.paren…

jenkins+sonarqube流水线脚本模板
pipeline { //这个任务在哪个主机上运行 //agent any//将这个项目运行在slave上 agent { label node1 }//参数化构建,主要设定git_version变量的值 parameters { string(name: git_version, defaultValue: v1.1, description: 选择你要部署的tag??) }stages { //整个部署的任…