代码改变世界

结对编程和TDD六问

2010-09-27 22:35  袁国彬  阅读(2038)  评论(18编辑  收藏  举报

 结对编程和TDD是什么?

  我这里谈的“是什么”,不是谈的这两者的定义,因为定义大家搜索一下就知道了。而是这两者的本质意义。只有抓住了本质,你才会明白你为什么要采用这两种方式去编程,以及在实际运用过程中需要重点注意什么,又需要忽略哪些干扰因素。

  结对编程:极限codereview,把codereview做到极致;

  TDD(Test Driven Development):极限单元测试,把单元测试做到极致。

  根据以往的项目经验,特别是在嵌入式项目中,前期的质量活动,其测试出BUG的成本明显低于后期的质量活动,codereview的重要性怎么强调都不过分,而单元测试在传统开发流程中从时间顺序上是排名第二的质量活动,也是一个非常重要的测试手段。既然前期的质量活动是如此的重要,何不把它们做到极限呢?这就引出了结对编程和TDD。

 

 结对编程和TDD给我们带来了什么?

1)   新鲜感

2)   不习惯,感觉别扭

3)   编程效率降低

  以上三点,是结对和TDD初期反应非常集中的体验。前面两条还好说,第三条编程效率的降低似乎是不可忍受的,特别是在项目进度很紧张的时候。有了这个缺陷,就使得结对编程和TDD看上去也并不是那么美了。

但是先别着急,我们再往下看。

4)   对代码质量更有信心

  结对编程和TDD同时采用了之后,项目组同事普遍的反映都是对代码质量更有信心了。而且我自己在采用前后从测试部反馈出来的数据上看,BUG数量降低的非常明显。

  如果还是不够有说服力的话,那来点权威数据。

  有实验表明,平均下来结对编程时间花销比单人编程增加10%的时间,但也会比单人编程减少15%的代码BUG。如果再算上后期代码的维护和学习成本,结对编程比单人编程更有效率,还更为节省成本。

所以,如果你是以完成代码为目标的话,结对编程的效率降低,如果你是以完成高质量的代码为目标的话,效率并没有降低,反而是提高的。

5)   从结对伙伴学到好的经验

  这是一次非常好的也是最直接的经验交流和传递的机会。

6)   代码更规范

  因为有个人一直注视着你,你不好意思把代码写的很难看。

7)   为代码重构打下坚实的基础

  TDD出来的单元测试例,成为了重构的天然保护层。没有测试例保护的重构是高风险的,不建议在没有单元测试例的情况下作重构。

8)   越复杂的代码,使用价值越高

  假设一个复杂的特性有十个关键点,一个人想可能只能想到7个,遗漏3个,而两个人想的话可能只会遗漏1个,甚至1个都不会遗漏。而这3个遗漏需要流到后面的质量环节去发现,风险和发现成本均提高。

9)   体验到合作的乐趣

  当两个人配合默契的话,结对编程是一件非常快乐的事情。至少我是这种感觉。

10) 有效缓解程序员沟通能力的退化

  程序员一天到晚都只对着电脑,一天也说不了几句话,说话和沟通的能力长期得不到锻炼,有退化的风险。而结对编程对沟通能力是一次挑战,也是一个改善的机会。

 

结对编程需要注意什么?

   有时候妥协比说服别人更加重要。

  通常都说技术人员,特别是程序员对于自己负责的领域或者模块都有很强的自信心。自信心是好的,但是如果需要两个人合作去完成一件事情的话,这种自信心有可能反而会成为达成目标的一种阻碍。

  有人在我的上一篇文章《敏捷初体验》回复说:“两小儿辩日”是结对编程的最大悖论。其实这就是我在结对编程是什么里提到的需要忽略的干扰因素。结对编程不在于分出高低,也没有绝对的对和错。当然也不存在“两小儿辩日”这种事情,毕竟做的都是自己熟悉的事情。结对在于把codereview做到极致,减少BUG。至于方案上的东西,除非有明显的好坏之分,否则“有时候妥协比说服别人更重要”,这样才会产生相互的良性循环。即使采用了对方的方案,在实际操作的过程中,仍然可以植入一些你的想法,而你也可能会发现其实对方的方案其实是有他的优点的。这样会比一味的争辩对达成目标更有效果。

 

TDD需要注意什么?

 

  单元测试例面向需求 ,而不是面向代码。

  比较经典的例子就是TDD是先挂上靶子再射箭,而传统开发是先射箭再在箭头处挂上靶子。后一种方式靶子几乎没有发挥作用。而单元测试例就是挂靶子,如果编写测视例的时候思维老停留在代码上,而不是面向需求,这样的测试例并不能很好的保证代码是正确的需求表现。

 

我的模块不适合TDD怎么办?

  思路:编写可测试性高的代码。

  对于C语言编程而言,消息比较多,流程类的代码不太适合做TDD。对于不适合TDD的代码并不是要鼓励一定要硬TDD,但是仍然可以想办法去提高TDD率。这里提供一种思路,就是编写可测试性高的代码。可以借鉴WEB编程MVC模型,对于早期的web编程语言,所有的代码都混合在一个.html文件中,做单元测试是不可能完成的任务。但现在WEB编程的可测试性越来越高,这得益于MVC等优秀框架的提出。

 

  对于C代码中消息流程类的代码,就好比controller,它设计的越轻量级越好,对于涉及到业务处理的所有东西都单独提取出来,单独处理或者另起文件处理。类似于Model。这种类比不一定准确,却是一种思路。其实很多事情都能找到办法。

 

我觉得我不适合/不喜欢TDD怎么办?

  敏捷并不是集万千优点于一身,它有很多优点同样也有缺点。没有采用TDD或者结对编程并不代表你写出来的代码质量就不高。但如果你对敏捷还比较感兴趣,或者你的公司正在敏捷,而你因为害怕变化而犹豫的话,可以送你一句话:

  鼓起改变的勇气,尝试一次,再坚持一下,也许你就喜欢上她了。