结对编程随着敏捷开发思想的兴起而广为人知, 然而这种实践早已有之。 在 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
有人要问,既然代码复审能发现这么多问题,有这么好的效果,如果我们每时每刻都处在代码复审的状态,那不是很好么?事实上,极限编程(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一起缕一缕思路。一下午下来,感觉甚为清爽,因为终于清楚这个项目的做法了。
两人合作
软件开发的过程看似一个个程序员在孤独地写代码, 其实一个成功的软件团队, 成功的企业需要很多合作, 从历史上看, 我们可以发现很多成功的企业都是两个人合伙开创的, 下面是一些例子:
(推动PC 发展的电子表格程序 - VisicALC - 的两位创始人 Dan & Bob)
(Facebook 的两位创始人 Mark and Eduardo [电影画面])
…
说到合作, 有些孤独的高手没人可合作, 无聊得会让左右手互搏, 但是一般人还是需要很多人来帮忙做事情, 两人一对一的合作是其他合作的基础。除了两人一见如故, 永远是蜜月期的那种个例, 大部分人的伙伴关系也是有一个不平坦的发展过程, 下面我们来看看两人合作有什么阶段:
两人合作的不同阶段(舞蹈版)
移山公司的同事们中午吃饭时,大家关心起阿亨的婚姻大事来,纷纷给他支招,问他们现在到了什么阶段,是否拜见过对方父母,是否谈婚论嫁等。突然有人问了这么一句:“你们吵过架了么?”阿亨一愣,想了想,说:“没有。”杂曰:“那还早得很,还有很长的路要走呢!”
下午开会的时候,阿超说,人不可能没有矛盾,两个人连架都没吵过,说明两个人之间还是有距离。谈恋爱,两人合作项目,都有类似的阶段,大家在学校里跳舞有没有舞伴?下面我们以舞伴为例,描述一下各个阶段。
以跳舞为例,刚认识,拘谨而彬彬有礼。
这一阶段的现象:两人刚刚互相认识,这时大家都有礼貌,一般交流不少,每个人都想得到对方的接纳,试图避免冲突和容易引起挑战的观点。对即将进行的舞蹈,有不同的期望值。
2.磨合阶段(Storming)
开始跳舞,开始踩脚。接触之后,才感到手足无措,眼睛不知往哪里看,才能感到对方原来舞步是这样的……这样的笨拙。这时,会出现如下对话:
——哦,对不起,我又踩了你的脚。
——噢!您揪着我的肉了!
——哦,我是要你向右转!
——你这叫跳舞么,简直就是牵驴拉磨!
……
——对不起,我昨晚对你态度不好,咱们今晚还去跳舞么?
跳舞逐渐和谐、合拍,团队成员就很多事情取得了一致。一些成文或不成文的规则逐步建立起来了。男方轻轻的一个手势,女方就知道如何旋转。
跳舞二人合而为一,为艺术而舞蹈(大家发出了唏嘘向往之声)。
并不是所有的合作都能达到这一阶段,Storming太多后,我们还可能进入“解体阶段”。
散伙,各走各的独木桥,回宿舍抱着板凳跳舞,或者另找舞伴。
同学们尝试结对编程一个星期后,阿超询问荔荔感想如何,荔荔支吾半晌说,两个人讨论,是不是比谁的嗓门大?我和九条讨论的时候,他的嗓门越来越大,我只好同意他的说法了。
阿超说,两人在一起合作,自然会出现不同意见,每个人都有自己的想法,在两个人平等合作的情况下,不存在领导与被领导的关系,如何能说服对方?要听对方的话语和观察对方的肢体语言,了解它们所表示的潜台词,试着从对方的角度看待问题。同时也要根据情况采取不同的方法影响别人,有以下几种方式,如表11-2所示:
表11-2
方式 |
简介 |
逻辑/感情 |
推/拉 |
注解 |
断言 (Assertion) |
就是这样吧,听我的,没错! |
感情 |
推—— 主动推动同伴做某事 |
感情很强烈,适用于有充分信任的同伴。语音、语调、肢体语言都能帮助传递强烈的信息 |
桥梁 (Bridge) |
能不能再给我讲讲你的理由…… |
逻辑 |
拉—— 吸引对方,建立共识 |
给双方充分条件互相了解 |
说服 (Persuasion) |
如果我们这样做,根据我的分析,我们会有这样的好处,a、 b、 c…… |
逻辑 |
推—— 让对方思考 |
有条理,建立在逻辑分析的基础上。即使不能全部说服,对方也可能接受部分意见 |
吸引 (Attraction) |
你想过舒适的生活么?你想在家里发财么?加入我们的传销队伍吧,几个月后就可以有上万元的收入…… |
感情 |
拉—— 描述理想状态,吸引对方加入 |
可以有效地传递信息,但是要注意信息的准确性。夸大的渲染会降低个人的可信度 |
提示:没有绝对正确或错误的方法,只有合适或不合适的方法。几种方法可以同时使用,只要使用者本人不会头晕。
如何更有效地给合作伙伴提意见? 这个博客讲了一个方法:
http://www.cnblogs.com/xinz/archive/2011/08/22/2148776.html
参考资料:
http://en.wikipedia.org/wiki/Pair_programming