结对编程的价值及注意点
结对编程( Pair Programming)可能是最受争议一项的敏捷实践,持续集成和重构基本已经普遍被大家认同了,TDD还能引发 很大的口水仗,倡导结对编程则有被狂砸砖头的风险,本文我不想说结对编程绝对有多好,我想分享的是一些有关结对编程我体验和观察到的价值,以及几个我认为特别需要注意的地方,尤其是后者, 如果以错误地方式用结对编程,弊很可能大于利。
结对编程是指两个开发人员(也可以是测试人员)坐在(也可以站着、蹲着,舒服即可)同一台计算机前,一起解决同一个任务(比如修Bug,加测试,加特性等等),其中一个人的角色是驾驶员(Driver),负责操作计算机、写代码、写测试,另一个人的角色是导航员(Navigator),负责观察驾驶员的工作,发现驾驶员引入的错误并及时提醒,两个人的角色可以经常变换。
结对编程这种工作方式首先是非常反直觉的,从开始学习编程,到每天的日常工作,大部分程序员从来都是独自坐在计算机前面解决问题,偶尔被打断还非常影响心情和工作效率,如果和另外一个人坐在一起编程,那会是什么情况?其实,到底会是什么情况谁也说不准,可能会非常令人生气,也可能会大大超出预期,对于没尝试过的人来说,找人试个一两次也无妨。
价值
最近两个月,我与超过10个人进行了结对编程,总时间大概有50小时,还组织了两个团队讨论这个主题,并阅读了一些相关的资料,在此基础上我认为结对编程的价值,或者说它能带来的好处,是显而易见的,具体总结为以下几点。
显著提高代码质量
我接触过的所有参与过或未参与过结对编程的程序员,都一致同意结对编程能提高代码质量,当驾驶员写代码的时候,旁边的导航员会一直看着,发现问题立刻会告诉他,拼写错误、用错方法、用错变量,各种低级错误是难免的,更为重要的是,当驾驶员写的代码导航员无法理解时,导航员会问,这个时候一些潜在的问题就能暴露出来,比如设计不清晰、命名不清晰、或者大的方向错误。此外,由于两个人会有不同的背景,相互能弥补对方的不足,从而尽早避免一些软件质量问题,这也是很好理解的。
然而代码质量的获得是要有付出的,最直接的付出就是时间,通常来说一组结对单位时间的产出会比两个人分别工作的产出要低,这是大多数人的体验,所以很多人就说结对编程比较浪费时间。但从长远的来说,在整个软件的生命周期来看,结对编程能在编码阶段避免大量bug的引入,因此也就省下了日后找bug,修bug的时间,我们都知道,bug被发现得越晚,修复的成本越高,从这个角度来说,我 相信结对编程总体上是节省了开发软件的时间。
促进知识分享及学习
在和团队讨论结对编程的时候,有两个相对较新的团队成员分享说他们一个很直接的体验就是,有人结对的时候他们能快速地学习并开展工作,而不是一个人埋头苦干遇到阻塞问题再犹豫要不要问别人。另一个和我结对的人在回顾的时候告诉我,我们所花的时间比他预期的要短很多,因为他不熟悉C#语言和相关的单元测试框架,但和我结对的时候,这就不再是个大问题。
很多公司的业务都有复杂的领域知识,这些知识有一部分被清晰地记录在文档上,但更多的是散落在零星的代码中和每个相关人员的脑子里,大多数情况下,通过阅读代码快速理解领域知识是非常困难的,但是如果旁边坐着一个对相关代码非常熟悉的人,那这个问题就迎刃而解了。
大多数程序员都听说过很多面向对象设计原则,比如单一职责,比如高内聚,低耦合,比如好莱坞原则,等等。但听说是一回事,理解是另外一回事,我见过一些程序员,一小时之前还在听面向对象设计培训,一小时之后却依旧写着过程式的代码。结对编程这个时候能发挥很大的作用,基于实际的产品代码,遵循设计原则一步步地重构,并辅以及时的解释,这能让同伴得到对设计最直接的体验,这样他就能快速地理解相信并在日后的工作中的沿用。
帮助团队信任及合作
相对于单独工作单独负责,结对把两个人放到了同一条船上,这可以看成是一个微小单元的‘荣辱与共’,面对他人赞同的时候,会有最直接的分享者,相视一笑;面对他人质疑的时候,会有最直接的支持者,不用说会站出来为你说话,信任就是这样慢慢建立起来的。如果整个团队的结对经常的更换,那么团队中的任何两个人都能建立一些信任关系,沟通自然也更加顺畅,合作也就更容易。
我发现氛围好团队实践结对编程更容易,而结对编程又反过来促进了团队氛围,这是一种增益。但是在氛围比较差的团队推广结对编程一开始会比较难,但这是个循序渐进的过程,急不得。
形成压力和专注
试过结对编程的人普遍会反映说比较累,这是因为结对的时候两个人都会为了尊重对方以及技术自尊给努力思考、高度专注。独自编程的时候,状态有好有坏,当觉得有点累或者遇到一些挫折的时候,会不自觉得放松下,刷个微博,看了邮件,喝口水,耗掉点时间;结对的时候,即使有点累,一般还是会努力保持状态,遇到挫折也会努力去克服,刷微博的可能性也会小很多。人都是有惰性的,有个人在旁边能帮助我们避免一些惰性的蔓延。这种压力下的专注状态能够帮助提高程序员的生产率。
此外,当我想找一个人的时候,如果他在独自工作,我很可能会去打断他,但如果他和另外一个人在结对,我就会再等等,因为一打断就是两个人了。当然不是所有人都像我这样,但结对的时候,被打断的概率确实会小一些。
注意点
虽然结对编程有着这么多的价值,但本文一开始就提到, 如果以错误地方式用结对编程,弊很可能大于利。在我的经验,如果在结对的时候能认真注意到以下几点并采取正确的态度和必要的措施,就能让结对编程健康地进行,否则的话,轻点的后果是结对进行不畅,更严重的后果是破坏团队氛围!
注意休息和负荷
前面已经说过,由于结对编程会形成压力并迫使人进入比较专注的状态,因此较之于单独编程,这种方式在单位时间内会消耗人更多的精力,有一些人不愿意尝试结对编程就是因为担心这种工作方式会太累。偶尔有几次,我一天做了5到6个小时的结对,之后的确感觉非常疲劳,试想如果让程序员每天都保持这么高强度的工作状态,那他很可能就会受不了。所以 结对编程要适度,对一个从未经历过结对编程的人来说,一开始每天尝试2到3个小时即可,先让他体会结对编程的好处,而不要让高负荷把他吓走,等到他渐渐适应结对编程的节奏之后,再慢慢尝试增加时间,但我认为一天最多4-5小时即可,不宜过多,尤其不要一周五天每天6小时那么做。如果有人提出感觉太累,那就适度降低频率。
结对编程的时候,也要注意节奏,不宜连续结对太长时间,我会每隔50分钟左右休息一下,喝口水,聊会天,以保证下次结对能够充满精力。如果两人经常忘了休息,可以放个定时器提醒自己。
注意倾听
清晰地表达自己可能是件比较困难的事情,但我发现耐性地倾听别人的话更难,在结对的时候,倾听非常重要。我就曾经经历过因为没有认真倾听,过早发表自己的想法,而导致结对成为了一场无休止的争论,这样的结果非常糟糕。
首先要去尝试理解对方想表达什么,驾驶员在写代码的时候,代码想表达什么?驾驶员解释的时候,听明白了吗?明白之后,再给出反馈,也许什么地方可以改进,也许什么地方存在误解,结对编程提供了一个很高的沟通渠道,浪费了就很可惜。
尽量避免过长的争论,有时候讨论方案A和方案B的时候,你坚持方案A,对方坚持方案B,如果两者差别不是太大,你也无法说服对方,那不妨就执行方案B,如果适当的妥协能提高两个人的生产率,建立信任,那何乐而不为呢?
警惕沉默
如果两人结对的时候没什么话语的交流,那是要非常警惕的事情。我观察下来,状态良好的结对编程,两人几乎是在不停地说话的,驾驶员一直在解释自己在干什么,领航员一直在提出问题,很多情况下两人还会把第三个人拉进去参与讨论,这样的沟通是非常高效的!
想对应的,如果驾驶员一直自顾自地敲键盘,领航员渐渐变得昏昏欲睡,或者甚至开始玩手机,那这和独自编程就几乎没什么差别了,唯一的差别就是浪费了一个人的时间。当发生这种情况的时候,要去考虑原因所在,也许两个人暂时合不来?也许有人太累了?也许两个人背景差别太大,驾驶员走太快而领航员跟不上?找出原因后,再针对地改进。
总结
总得来说,我相信结对编程是一种非常有益的编程方式,但我反对强制他人结对,也反对快速的推行结对,结对编程会改变大多数人的思维方式,而改变人是一件急不得的事情。
关于这个主题,Laurie Williams和Robert Kessler所著的《 Pair Programming Illuminated》是本不错的参考,我从中获益良多。此外,微软有一篇关于结对编程的论文,名为’ Pair Programming: What’s in it for Me?‘,其中调查并总结了大量微软程序员做结对编程后的感受,也非常值得参考。
最后感谢所有和我做结对编程的人,感谢你们帮助我学习成长。