Bob大叔和Jim Coplien对TDD的论战

Bob大叔和Jim Coplien对TDD的论战

今年春节时,我写了一篇《TDD并不是看上去的那么美》,在这篇文章中我列举了一些关于使用TDD的一些难点和对TDD的质疑,后来出现了一些争论(可参见那篇文章的评论),以及Todd同学的《TDD到底美不美》,还有infoQ中文上的那个几乎没有营养离线讨论。今天,有网友给我推来一个英文版infoQ的视频——“Coplien and Martin Debate TDD, CDD and Professionalism”,这是2008年2月18日的视频,视频的主角两个人争论TDD好还是不好,一个是敏捷社区的教主级的人物——Robert Martin(大家称之为“Bob大叔”),另一个是C++,OO,多范式编程的大师Jim Coplien(大家都叫他Cope)。这两个人对TDD的见解有分歧。Coplien的很多观点和我之前的不谋而合,而他自己称他是坚决强烈地站在TDD的对立面上。下面是Jim的原话:

I have adopted a very strong position against what particularly the XP community is calling test driven development.

InfoQ的视频很多时候相当的不给力,就像有前列腺的患者撒尿一样,半天都挤不出一滴。不过,好在那里有这两个人对话的摘录。在这里,我给大家摘要一下:

——————————————————正文分割线————————————————————

Coplien首先让Uncle Bob定义了一下TDD,Uncle Bob说明了他的三个法则:(敏捷的同学一定不陌生)

  1. 一个测试驱动的程序员,其不会在写出一个测试失败的Unit Test前,去写一句可用在生产线上的代码。(没有测试之前不要写任何功能代码)
  2. 在编写用于生产线上代码之前,不写过多的测试失败的Unit Test。(只编写刚好能体现一个失败情况的测试代码)
  3. 在现有代码通过Unit Test前,不写更多的用于生产线上的代码。(只编写恰好能通过测试的功能代码)

Coplien说他有意见的不是这三个法则,而是因为这个三个法则是孤立说出来的。Coplien说他和一些咨询师或是Scrum Master参与过很多的项目,他们发现这些项目都有两个问题:

  1. 他们使用TDD的时候,软件没有一个架构或是framework。当然,Kent Beck说——TDD可以驱使你去做架构。但是,TDD和Unit Test 是一回事吗?Unit Test是一个伟大的事,尤其是当你去写API和类库的时候。今天XP所说的TDD和UT很不一样。如果你使用TDD来驱动你的软件系统架构,那么,基本上来说,三个迭代以后,你开发的软件就会crash掉,而且无法再往前开发。 因为什么?因为连软件团队自己都受不了这三个迭代出来的架构,而且你还会发现,你根本没去去重构。
  2. 第二个问题是,TDD这种方法破坏了GUI(图形界面),就算是Kent也说:“你永远不可以在一个漂亮的界面后面隐藏一个糟糕的架构”,Coplien强烈地相信软件的架构是通过界面来发出其光芒。他觉得如果没有一个好的软件架构,这个会影响用户的操作。

Coplien接着说,如果我们使用Uncle Bob的三条法则,我们也许没有什么问题,但Coplien想告诉大家另一个非常重要的事,那就是软件架构。并说:“我根本不接受TDD是软件专业化实践的论点”

Bob大叔说,让我们回到99年,那时的敏捷社区觉得软件架构是无关的,不需要软件架构,只需要做一堆tests,做一堆stories,以及足够快的迭代,这样就可以让那些代码魔幻式地拼装起来,这就是horse shit。对于大多数的敏捷拥护者来说,这的确是愚蠢的。今天你再和Knet说这个事,他也会说那不过是一种说法。

Coplien回应到,实际上,Knet在解释XP的时候,在他的书131页的位置说过,“是的,你得做些前期的架构,但也别把自己搞乱了”。

Bob大叔把话题转回来,继续聊关于架构方面的事,他说软件的架构很重要,他也写很一些关于架构的书,他说他也是一个架构方面的怪才,但是他认为架构自己并不会形成软件的所有的外表。他觉得好的软件架构和设计能力应该出现在若干次迭代之后。他觉得你在架构软件的时候,你会创造一些东西,也会破坏一些东西,并且会在几次迭代中做一些试验性的工作,来尝试一下不同的架构。在2到3次迭代以后,你可以知道那一种架构是对的,这样,你可以在后面的迭代中进行调整 。因此,他认为架构是需要进化和发展的,而不会因为被可执行的代码所形成,也不会因为你所写的测试而形成

Coplien赞同架构进化的观点,而且他相信软件的架构的演变和进化不是因为你写的代码,也不是因为Use Case,也不是告诉你你的软件需求的范围和其中的关系,但是如果你做的方法是以增量式的,以用户驱动式的,而你却在和用户沟通时没有一些前期的业务知识,那么这一定是相当有风险的,并且你一定会把事搞砸的。

Coplien接着说,他在Knet早期提到TDD的时候和Knet时,提到YAGNI(陈皓注:You Aren’t Gonna Need It,XP的一个法则,也就是只做最简单的事)时,Kent说到:“让我们来做一个银行帐户,一个储蓄帐户”,储蓄帐户其实就是对余额进行一些加加减减的事,就像一个计算器一样。Copilen继续解释到,但是如果你要做一个真正的银行系统,你的软件架构根本不可能从一个储蓄帐户的对象(计算器)重构出来。因为储蓄帐户根本就不是一个对象,其是一个流程,后面有一个数据库的查帐索引事务,还有存款保证多和利息,还有一些转帐功能。就算是这样,这也只是用户的功能,你还需要支持税务人员和精算会计师等这些人,这会让银行系统成为一个错综复杂的软件架构,这绝对不是你可以用迭代干出来的事。当然,Bob大叔是可以的,因为他有40年的银行系统的经验。但是Bob大叔你的这40年可真不敏捷啊

Coplien接着说, 因为Bob大叔可以在软件前期做很多很重要的决定,这让得后面的事变得相对比较简单。Coplien根本不相信只要你把代码往那一放,在上面披上一层皮,再设置好一些角色,设置好接口,在文档里写上整个业务结构,而你只有在有人花钱的时候你才会在其中填充进真正的代码,反之就违反了你的YAGNI原则。所以,你只是在你需要的时候做你要做的事,但你却还是要提前得到你的软件架构,否则你一定会把你自己逼进死角的。

Bob大叔辩解到,我说的�