结对编程随着敏捷开发思想的兴起而广为人知, 然而这种实践早已有之。 在 1987年, Intuit 公司 (当时只是一个刚刚创业的个人财务管理软件公司)向顾客宣布在 4 月份提供新版本的软件 (4月15日是美国报税的截止日期)。 但到了 3 月份的时候, 公司仅有的两个技术人员发现项目还是大大落后于预期, 于是这两人在 3 月的最后一个周末开展了疯狂的,不得已的结对编程活动:
来源: Amazon.com: Inside Intuit: How the Makers of Quicken Beat Microsoft and Revolutionized an Entire Industry (9781591391364): Suzanne Taylor, Kathy Schroeder, John Doerr: Books
http://www.amazon.com/Inside-Intuit-Microsoft-Revolutionized-Industry/dp/1591391369/ref=sr_1_1?ie=UTF8&qid=1322317678&sr=8-1#reader_1591391369
结对编程
有人要问,既然代码复审能发现这么多问题,有这么好的效果,如果我们每时每刻都处在代码复审的状态,那不是很好么?事实上,极限编程(Extreme Programming - XP)正是这一思想的体现――为什么不把一些卓有成效的开发方法用到极致(Extreme)? 结对编程就是一个例子。
在结对编程模式下,一对程序员肩并肩地、平等地、互补地进行开发工作。两个程序员并排坐在一台电脑前,面对同一个显示器,使用同一个键盘,同一个鼠标一起工作。他们一起分析,一起设计,一起写测试用例,一起编码,一起单元测试,一起集成测试,一起写文档等。
结对编程不是程序开发者独到的发明,在现实生活中,也存在着类似的搭档关系(Partnership):
越野赛车(驾驶,领航员)
驾驶飞机(驾驶,副驾驶)
战斗机的编组(长机,僚机)
提示:这些任务都有共同点:在高速度中完成任务,任务有较高的技术要求,任务失败的代价很高。
结对编程中的角色
结对编程中有两个角色:
(a)驾驶员(Driver)是控制键盘输入的人。
(b)领航员(Navigator)起到领航、提醒的作用。
这两个角色是可以互换的。和现实生活中的例子类似,一个人负责具体的执行(驾驶,用键盘编辑程序等),另一人负责导航、检查、掩护等。
同学们杂曰――
1)编程从来就是一个人的活动。学校里这么教的,我们一直以来也是这么做的。两个人本来可以去做两个模块,现在一个模块两个人写是不是一种浪费(这可是两份工资哦)?
2)我习惯一个人写程序,不喜欢被人盯着工作,这样我不自在,无法工作。
3)身旁的这个家伙老是问问题,他/她不会看书么?我都无法专心工作了。
4)会不会出现,“我只领航,不用敲键盘,多爽……”的情况?
5)有些公司规定所有的任务都要结对编程, 结果大家都走形式, 滥竽充数的人也在结对编程的过程中得过且过
……
为什么要结对编程?
每人在各自独立设计、实现软件的过程中不免要犯这样那样的错误。在结对编程中,因为有随时的复审和交流,程序各方面的质量取决于一对程序员中各方面水平较高的那一位。这样,程序中的错误就会少得多,程序的初始质量会高很多,这样会省下很多以后修改、测试的时间。具体地说,结对编程有如下的好处:
(1)在开发层次,结对编程能提供更好的设计质量和代码质量,两人合作能有更强的解决问题的能力。
(2)对开发人员自身来说,结对工作能带来更多的信心,高质量的产出能带来更高的满足感。
(3)在心理上, 当有另一个人在你身边和你紧密配合, 做同样一件事情的时候, 你不好意思开小差, 也不好意思糊弄。
(4)在企业管理层次上,结对能更有效地交流,相互学习和传递经验,能更好地处理人员流动。因为一个人的知识已经被其他人共享。
总之,如果运用得当,结对编程能得到更高的投入产出比(Return of Investment)。
不间断地复审
结对编程让两个人所写的代码不断地处于“复审”的过程,正如前所述,复审是不断地审核,提高设计和编码质量的过程,结对编程让复审随时随地发生,这样才能及时地发现问题和解决问题,避免把问题拖到后面的阶段。
开发中的复审主要包括:设计复审、代码复审、测试计划复审、文档复审。
这些复审可以在伙伴之间进行,也可以在团队内部进行。结对编程和传统开发过程的复审有什么区别呢?
(1)传统意义上的伙伴复审,即程序员之间的互相复审,有以下的问题:
a. 复审人缺乏对程序的深入了解,降低了复审的效果;
b. 不能持久、定时地进行复审;
c. 对需求和设计的不了解导致无法实现全面有效的复审。
(2)团队复审是指多于两人的团队就某一程序实体进行的复审,团队复审的缺点在于:
a. 什么时候开会做复审?不可能一个团队天天开会。要找到一个所有人都能出席的时间,并不容易;
b. 牵涉的人员众多,理解程度不一,复审的速度和效果不能得到有效的平衡――太快则有人不懂,太慢则浪费许多人的时间;
c. 正是由于成本问题,无法对所有的设计和代码进行深入的复审;
d. 由于人员众多,有面子问题。
在结对编程中,任何一段代码都至少被两双眼睛看过,两个脑袋思考过。代码被不断地复审,这样可以避免牛仔式的编程。同时,结对编程避免了“我的代码”还是“他的代码”的问题,使得代码的责任不属于某个人,而是属于两个人,进而属于整个团队,这样能够帮助建立集体拥有代码的意识,在一定程度上避免了个人英雄主义。
结对编程的过程也是一个互相督促的过程,每个人的一举一动都在别人的视线之内,所有的想法都要受到对方的评价。由于这种督促的压力,使得程序员更认真地工作。结对编程“迫使”程序员必须频繁地交流,而且要提高自己的技术能力以免被别人小看。
但是要注意,每个人每天的高效率工作时段不超过3~4个小时。结对编程中驾驶员和领航员的互换可以让程序员轮流工作,从而避免出现过度思考而导致观察力和判断力下降。
什么样的人适合结对编程?
Extreme Programming对实施的程序员提出了更高的要求。这种要求不是技术水平,也不是学历水平或工作经验。这种要求是对一个人的心智、道德修养的更高要求。结对编程中,编码不再是私人的工作,而是一种公开的“表演”。程序员的代码、工作方式、技术水平都变得公开和透明,这也许是有些同学不喜欢这一方式的原因。
如何结对编程?
(1)驾驶员:写设计文档,进行编码和单元测试等XP开发流程。
(2)领航员:审阅驾驶员的文档、驾驶员对编码等开发流程的执行;考虑单元测试的覆盖程度;是否需要和如何重构;帮助驾驶员解决具体的技术问题。
(3)驾驶员和领航员不断轮换角色,不宜连续工作超过一小时。领航员要控制时间。
(4)主动参与。任何一个任务都首先是两个人的责任,也是所有人的责任。没有“我的代码”、“你的代码”或“她的代码”,只有“我们的代码”。
(5)只有水平上的差距,没有级别上的差异。尽管可能大家的级别资历不同,但不管在分析、设计或编码上,双方都拥有平等的决策权利。
结对编程是个渐进的过程――
有效率的结对编程不是一天就能做到的。结对编程是一个相互学习、相互磨合的渐进过程。开发人员需要时间来适应这种新的开发模式。刚开始的结对编程很可能不比单独开发效率更高。但是在度过了学习阶段后,结对编程小组的开发质量、开发时间通常比两人单独开发有明显的改善。
要避免的误区――
1) 不分情况强迫每个任务都用结对编程的方式, 或者固执地遵守一些教条 (例如 "结对的成员必须水平相当..." 等等)
2) 没有提供足够的支持就匆忙上马结对编程 - 工作环境, 硬件, 对结果的期望都要准备好。
3) 在具体作法上加入过多限制或要求 - 应该让两位程序员自己决定具体的方式。
不适合结对编程的情况――
并不是所有的项目都适合结对编程,下面是一些不适合使用的例子。
1)处于探索阶段的项目,需要深入地研究,在这种情况下,一个人长时间的独立钻研是有必要的。
2)在做后期维护的时候,如果维护的技术含量不高,只需要做有效的复审即可,不必拘泥于形式,硬拉一个人来结对唱二人转。
3)如果验证测试需要运行很长时间,那么两个人在那里等待结果是有点浪费时间。
4)如果团队的人员要在多个项目中工作,不能充分保证足够的结对编程时间,那么成员要经常处于等待的状态,反而影响效率。
5)关键是如何最大限度地发挥“领航员”的作用,如果用处不大,也就无需结对。
推而广之,所谓极限编程,就是把一些认为重要和有效的做法发挥到极致,如表11-1所示,在这层意义上,“极限编程”应该叫“极致编程”。
表11-1 极致编程
如果…… |
发挥到极致就变成…… |
了解顾客的需求很重要 |
每时每刻都有客户在身边,时时了解需求 |
测试/单元测试能帮助提高质量 |
那就先写单元测试,从测试开始写程序――TDD |
代码复审可以找到错误 |
从一开始就处于“复审”状态――结对编程 |
计划没有变化快 |
那就别做详细的设计,做频繁的增量开发,重构和频繁地发布 |
其他好方法…… |
发挥到极限的做法…… |
下面是 <现代软件工程> 的同学们亲身体验了结对编程之后的一些感想:
(link)
第一次体会到结对带来的效率:
那是project到了比较关键的创造阶段,整整一天,我们俩椅子靠椅子的坐在电脑前,一边讨论一般coding,那次才真正的体会到结对真的能够带来效率。一整天的coding是容易走神的事,还好有pair在旁边指导,总是不断在我敲某某变量之前提前告诉我成员变量的名字,数据修改时帮忙检查是否有漏掉的,变量和函数定义的时候一起为其取名字,感觉有点眼花了,就换了个角色,我也开始对他“指指点点”了,一个人coding,一个人review,确实能减少一些不必要的错误,减少一些漏洞,算法实现后一起做些简单的测试,看到bug了再一起分析,我能明显的感觉到与以前的个人编程不一样,我们能比较快的找到bug初始点,并能提出比较的修改方法。特别是当看到功能进一步实现时,心里确实挺happy,更重要的这份感受有同伴与你一起分享。
(LINK)
以前觉得结对编程的效率不高,因为只有一个人能够在敲代码,后来发现,事实不是这样的。两个人在一起的时候,一个人敲代码,另一个人能够及时发现错误,出现什么问题也能够一起讨论,其实效率更高。两个人一起的时候能够更加全身心的投入,而且互相都能够学到很多东西。总之通过这次结对编程,感觉收益匪浅。
(LINK)
于是我们进行了项目中最关键的一次PAIR PROGRAMMING,我们利用编译课上机时间,在机房里PAIR完成了整个项目的类的设计与程序结构的设计。我们一起分析出类,然后找属性,写方法头,开始是WG用键盘,后来我用。一个明显的好处是,写完一条自己不确定的语句,马上可以跟PAIR一起缕一缕思路。一下午下来,感觉甚为清爽,因为终于清楚这个项目的做法了。