这篇文章的起因是在《“敏捷中国史”交流群》里的一个争论,我希望能够通过这篇文章说明自己的一个观点:相对于结对编程,Code Review是一种更加合理与普适性的研发实践。
背景情况介绍
基于变更的Code Review
按照维基百科的定义,结对编程也是Code Review的一种形式。所以,当我想要把Code Review与结对编程对立起来的时候,实际上是指一种更加特定形式的Code Review。在GitHub上,这样的形式非常流行,甚至不需要再做更多的说明。在维基百科上,这一类型被称为正式的基于变更的代码审查(Regular change-based code review)。除了Github的Pull Request,还有由Gerrit支持的基于Changeset的模式。
后续为了比较,我将会展开一些具体的实践细节。
结对编程
这可能是众多敏捷软件开发方法中,“极限编程”区别于“其他敏捷”最大的一个特征。或者说,其他的那些敏捷方法中,已经不再强调必须结对编程了。按照维基百科上展示的一些研究成果,结对的好处有以下一些:
-
更好的设计与更好的代码
-
有助于团队内成员互相学习(尤其是老手带新手的情况下)
-
不太会忘记编写单元测试,花时间上网或处理个人电子邮件,或偷工减料
-
相比一个人工作,2个人结对工作时,更加不容易被人打断
围绕结对编程的一些争议
事实上,结对编程的好处,是否存在夸大,是存在争议的。
-
有研究发现结对编程往往一定程度地缩短了开发时间,而且对代码质量产生了正的边际效益,但是结对编程大大增加了开发人员的工时;也就是说与单独编程相比花费大大增加了。[1]
-
还有研究者指出:有关结对编程的研究遭遇了发表偏倚,有些不利于结对编程的研究要么没有开展研究,要么没有投稿,要么没有被授权发表。
为何基于变更的code review会比结对编程更好?
一、提升代码质量
结对编程也能够提升代码质量,但是这个可能性是发生在结对的2个人身上的。也就是说,两个聊完了,代码写出来了。代码的质量也就这样了。
而一个人写代码,想要提交去被review的时候,可能看到代码的人,是不确定的。在开源社区,看到代码的人也许成千上万,这些人走过路过都可能会发表一些意见。即使是在企业项目、团队内部,这个代码也不仅仅是这个功能的Pair搭档能够看到。
所以,当一段代码,可能被走过路过的开发者,+1分或者-1分,甚至直接-2分的时候。他有可能会更加注重自己的代码质量。不仅仅是让自己的搭档看懂,更要让所有潜在的批评者看懂。
二、分享与传播知识
当然,结对编程也可以做到这一点,但是:这样的分享与传播,存在两个限制:一对一的交流,知识从A传到了B。C何时能够知道呢?除非是,某一天A与C结对,或者B与C结对,而且在结对过程中,正好聊到了这一话题。
第二个限制,是因为结对编程时的交流,往往是口头的。而基于变更的Code Review,各种评审意见,都是数字化且可以再检索的。这就使得后续的员工,想要学习组织的知识时,可以更方便的顺着代码,顺着提交记录与讨论记录了,了解到当时发生了什么。
三、工具性增强
因为基于变更的Code Review需要工具支持,所以我们也可以不断的改进工具,使得开发的过程不断得以优化。
-
得分门禁:我们可以规定,一个变更只有得分超过N分,才能够被合入。而每个人最多只能+1或+2分。假设一个团队有20个人,我们可以规定得分至少超过5分。那么开发者至少需要找到团队内部的3个人看过并认可他的代码,才能够合入。这就像是分布式存储中的N备份策略。越是重要的数据,我们备份的数量越多,数据也就越安全。
-
工具门禁:现在很多的CI工具,可以直接集成在Code Review的过程中,甚至以机器人的身份,直接参与打分。比如:XX测试不通过,直接-1分。再和上面提到的得分门禁配合起来。就能够对一次代码提交的质量,做出更加全面与深入的分析
-
研发数据:以上这些开发行为所产生的数据,都会保存在一个Code Review的系统里。较之过去的开源社区完全通过Email文字交流。这些研发数据的结构化,可分析性变得更高了。我们也因此能够进行更加深入的分析,甚至用上某种机器学习的手段,帮助我们不断改进代码的质量。
较之无需任何工具就可以开展的结对编程,我相信:工具的力量会更加强大。
针对熊节观点的一个反馈意见
在微信群里,熊节提到了一个很有意思的观点:软件开发到底是一项科技活动还是一项社会活动?使用流程与工具,其实是假设了程序员不爱交流,也无法改变,所以要用某种工具来帮助他们。(大意如此)
在我看来,面对面的交流固然是交流,借助工具的交流同样也是交流。作为程序员,其实我们会更加偏爱简洁、高效,甚至结构化的交流,而不是低效的,容易产生歧义的“口头交流”。
从某种意义上来说,我是支持不断的发展与改进工具的,无论是开发工具,还是交流的工具,都有可能变得更好。
Talk is messy, the code is clear. :D