Bob大叔和Jim Coplien对TDD的论战

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

  一个测试驱动的程序员,其不会在写出一个测试失败的Unit Test前,去写一句可用在生产线上的代码。(没有测试之前不要写任何功能代码)

  在编写用于生产线上代码之前,不写过多的测试失败的Unit Test。(只编写刚好能体现一个失败情况的测试代码)

  在现有代码通过Unit Test前,不写更多的用于生产线上的代码。(只编写恰好能通过测试的功能代码)

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

  他们使用TDD的时候,软件没有一个架构或是framework。当然,Kent Beck说——TDD可以驱使你去做架构。但是,TDD和Unit Test 是一回事吗?Unit Test是一个伟大的事,尤其是当你去写API和类库的时候。今天XP所说的TDD和UT很不一样。如果你使用TDD来驱动你的软件系统架构,那么,基本上来说,三个迭代以后,你开发的软件就会crash掉,而且无法再往前开发。因为什么?因为连软件团队自己都受不了这三个迭代出来的架构,而且你还会发现,你根本没去重构。

  第二个问题是,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大叔辩解到,我说的可能和你说的这个有点不同。我们应该不会像你所说的往接口中写一些抽象成员函数,而是创建一些有抽象接口的对象。当然,我不会一下子为这个对象装载上一堆方法。那些是我需要使用测试驱动或是需求驱动来做的事,我还会随时随地在看是否哪里软件架构可以让我拆分接口。

  Coplien说,问题是你得知道你要干什么?他说他非常同意Knet的书”XP Explained”里说的——“你不能去猜”,然后他举了一个例子,一个他曾经在一个电信项目中重新架构软件的例子,这是一个长途交换机的项目,项目组特别喜欢用面向对象,有一个人需要去做一个“Recovery Object”(应该是系统恢复对象),Coplien说这是很扯的一件事,因为系统恢复根本就不是一个对象,因为他对业务不熟,所以想这么做。而当你在细节上分析的时候,你会发现这根本就不是一个有成员方法的对象。我个人认为,Coplien想用这个例子来说Bob大叔的先定义对象的抽象接口并不是一个好的需求分析的方法。Coplien还说,这个事情今天被资本化成了SOA,真是在玩火啊

Bob大叔说,这个他很同意。你的确需要知道这个对象的意义是什么。而且他和Coplien都同意应该根据可运行的代码来决定未来,而不是基于投机心理搞一个巨大无比的架构。

  此时,Bob大叔把话题又带回原地,他问Coplien:“你需要多少的时间才能写出可运行的代码?是不是一个系统需要写200万行代码才能算?”,Coplien说,在他的经历中,200万行代码算是小项目了,他的项目都是几亿行代码的。而让代码可以跑起来,他至少需要让所有的对象都联系起来。

  Bob追问到,“那么你是怎么测试这些对象的连接性的?”,Coplien说,我当然要测试,我会测试系统启动和停止,看看有没有内存问题,半小时就好了。Bob大叔似乎找到了突破点,于是说到:“Excellent!那么我们间的分歧是什么呢?也许你只是不同意TDD的概念和其专业化,当然,这是另外一个话题了”。

  然后,Coplien说了一段我非常非常认同的话——“我看到很多人正在做正确的事,来避免我们之前讨论的那些问题,当然那不是TDD的扩展,而是Dan North所说的BDD。可见,软件开发中很多人都是在用正确的很好的方法,而我对此有意见的是,有人把这个事说成TDD,然后人们就去买相关的书来了解TDD,并且看到“architecture only comes from tests”,我在过去6个月中听到过4次这样的说法,这就像你所说的,完全就是horse shit。而关于你所说的专业化的事,如果你没有见过一个专业化,你怎么知道?”。(不是吗?大多数人都知道怎么开发软件,而不是TDD才是专业化的软件开发。)

  然后,Bob想多谈谈专业化的事,Bob说,在今天,一个不负责任的程序会提交一段他没有跑过单元测试的代码,所以,要确定你没有把一条没有测试过的代码提交到代码库里的最佳做法就是TDD。

  Coplien完全不同意这个说法。他觉得底层的东西是更重要的。他用了一个示例来攻击Bob大叔的这个观点,他先是说代码走查和结对编程都有好的有价值的地方,当然和这个话题不相关。然后他又说了Unit Test,想想我们的单元测试,可能我们的测试案例并不可能测试我们程序中参数的各种状态,这些状态有可能只是半打,有可能是一百个,有可能是2的32次方个,所以,我们可以命中一些状态,也会没有测试到一些状态,我们的测试真的只是试验性的,所以,如果你在测试中发现bug,你真的很幸运。

  随后,Coplien推崇DBC的方法,这个方法认为软件有前验条件,后验条件,还有不变的。这个方法是Eiffel项目使用的一个方法,使用这个方法你可以静态的去做一些检查,相当于你做了一个基础架构来干这些事。Coplien相信这个方法有TDD所有的优点——我需要努力思考我的代码,我需要思考软件的外部接口,而且,Coplien发现这么做会比做测试更有效。这会让你对那些参数的范围考虑地更为宽广,而不是只在测试案例写几个随机分散的值来测试。

  今天,Bertrand Meyer(Eiffel语言的创造者,他也不赞同TDD)把这个方法推进了一步,叫CDD - Contract Driven Development,这个是一种关注于对象间关系,其在程序运行前提条件和运行后的后验条中达成一种契约,可以通过对契约条件的动态或静态的检查,来对程序的功能进行验证。这样可以让你更有效地测试程序。这种方法需要对业务的重点部位非常好的了解。这是TDD很难做到的

  Bob大叔似乎在努力回忆CDD和Eiffel,然后他说,TDD不就是干这个的吗?TDD就是把契约变成单元测试,不但测试输入,也测试返回值,这不就是先验条件和后验条件,而且他说,Unit Test和代码结合得更紧,而契约没有和代码结合得紧密,这是他觉得很不舒服的地方。

  Coplien说Bob大叔创建了不应该创建的二元论。他说代码在哪里,UT就跟到哪里,代码有多臃肿,UT就有多臃肿,而UT也是代码,也会有BUG,所以,其实这真是事半功倍。还有一个最有名的示例是ADA编译器,其使用了TDD,反而增加了代码中的BUG,因为你的代码多,测试就多,代码就更多,整个代码就太过臃肿。如果你测试中使用了断言,这意味着你就耦合上了代码,你的测试案例和你的代码耦合地越多,你的代码就越难维护。

  Bob大叔为Coplien对代码臃肿的说法感到惊讶。Coplien说,这就是他的经历,他看到的。Bob大叔承认有很多混乱的测试和混乱的代码,他觉得像XUnit这样的工具被滥用了。Coplien打断道,这不是要和你争论的,我争论的是这就是我看到大家在实践的东西。

  Bob大叔反回到,你有没有看到CDD也被滥用的情况?Coplien说,他只觉得目前,软件业对CDD用的还不够。

  最后,时间不够了,Bob大叔问了一个不相干的问题,他说,我们这里有BDD,CDD, TDD,关于DD,他不知道谁是最先第一个使用带DD这个词的,他说他好像记得一个RDD - Responsibility Driven Development。

  Coplien对这个问题可能很无语,他只能说——“DD,这是Unix的一个命令嘛,Disk Dump,但这可能算。谢谢你Bob,很高兴又一次见到你”

——————————————————分割线——————————————————

  英语很重要,不懂英语,只看国内的东西,你就容易被洗脑,你就需要更多的时间和精力去思考那些早被人思考过的问题。

  开发和测试,都是需要充分地了解业务,充分的思考,充分权衡后才能做得好的事。并不是你用了哪个方法后就专业了,就NB了。

  相当BS ——上不谈业务,下不谈技术,只谈方法论的人和公司,这是绝对的扭曲。

本文出自seven的测试人生公众号最新内容请见作者的GitHub页:http://qaseven.github.io/

时间: 2024-11-03 17:54:13

Bob大叔和Jim Coplien对TDD的论战的相关文章

[翻译]Bob大叔:反思极限编程

译者注: Bob大叔14年后再次谈论极限编程.极限编程经历了14年的风风雨雨后,Bob大叔将会给它怎么样的定义那? 在我手中拿着的一本白皮薄书,在14年前彻底的改变了软件世界.这本书的标题是解析极限编程,副标题是拥抱变化.作者是Kent Beck,出版时间为1999年. 这本书很薄,不到200页.排版很宽,间隔很远.写作风格即自由散漫又平易近人.章节不多,概念简单. 但是其影响却像地震一样,甚至至今震动仍未平息下来. 起始于第53页的章节10,列出了12项实践,引爆了行业内的大辩论.并催生了一场

想要少写代码,就多花点时间思考

我曾经在我的微博上说过这样一段话 ,而我想在这里把我的这个观点描述地更加完整一些. @左耳朵耗子 :聪明的程序员会使用50%-70%的时间用来思考,用来尝试和权衡各种设计和实现,然后她们用30% – 50%的时间是在忙碌着编码,调试还有测试.而聪明的老板也会鼓励团队这样做.但是傻逼的老板,苦逼的程序员却会拿出来100%-150%的时间来忙着赶进度,返工,重构,还有fix 大量的bug--所以, 越差的团队只会越忙,甚至还忙不完他们的工作. 而在现在这个浮躁的时期,再加上敏捷咨询师们这群人念的歪经

多些时间能少写些代码

导读:作者陈皓在微博上说过这样一段话:"聪明的程序员使用50%-70%的时间用来思考,尝试和权衡各种设计和实现,而用30%–50%的时间是在忙碌着编码,调试和测试.聪明的老板也会让团队这样做.而愚蠢的老板,愚蠢的程序员会拿出来100%-150%的时间来忙着赶进度,返工,重构,fix大量的bug-所以,越差的团队一般会越忙,而且还忙不完."文中作者就此观点进行阐述. 文章内容如下: 在现在这个浮躁的时期,再加上敏捷咨询师们念的歪经,他们让人感觉上就像是软件产品是可以在很短的时间内高质量的

《设计模式解析(第2版•修订版)》目录—导读

作者简介 设计模式解析(第2版•修订版) Alan Shalloway 美国Net Objectives咨询/培训公司的创始人和CEO.他是麻省理工学院的计算机科学硕士,具有30多年面向对象咨询.培训和软件开发的经验,并经常受邀在重要的软件开发会议(包括SD Expro.Java One.OOP和OOPSLA)上演讲. James R. Trott 美国一家大型金融机构的资深顾问.他是应用数学科学硕士.MBA和跨文化研究硕士.在其20年的职业生涯中,他一直将面向对象和基于模式的分析技术运用在知识

说说Android的MVP模式

安卓应用开发是一个看似容易,实则很难的一门苦活儿.上手容易,看几天Java,看看四大组件咋用,就能整出个不太难看的页面来.但是想要做好,却是很难.系统框架和系统组件封装了很多东西,开发者弄几个Activity,用LinearLayout把布局组合在一起,添加点事件监听,一个应用就成型了.红海竞争,不管多么复杂的UX和业务逻辑都是一个月快速上线,二周一个迭代,领导和产品早上改需求,晚上改设计,再加上产品经理和设计师都按照iOS来设计,这一系列原因导致很多安卓应用不但体验差,不稳定,性能低,而且内部

《设计模式沉思录》目录—导读

版权声明设计模式沉思录Authorized translation from the English language edition, entitled Pattern Hatching: Design Patterns Applied, 9780201432930 by John Vlissides, published by Pearson Education, Inc., publishing as Addison-Wesley Professional. Copyright 1998

读Clean Code

最近在上下班挤公交的时间细阅Clean Code(代码整洁之道),再次佩服Bob大叔幽默的文笔,独到的观点和理解视角.最让 我耳目一新的是Bob大叔对数据结构和对象的解释. 总的说来数据结构指的就是数据的载体,暴露数据,而几乎没有有意 义的行为,你应该在尖叫这不是贫血类?的确这和我们的贫血类很相似.最常见的应用在分布式服务,以wcf,webservice, reset之类的分布式服务中不可或缺的数据传输对象(DTO)模式,DTO(Request/Response)就是一个很典型的数据载体,只存

c#扩展方法奇思妙用高级篇一:改进Scottgu的"In"扩展

先看下ScottGu对In的扩展: 调用示例1: 调用示例2: 原文地址:New "Orcas" Language Feature: Extension Methods(http://weblogs.asp.net/scottgu/archive/2007/03/13/new-orcas-language-feature-extension-methods.aspx) 很多介绍扩展方法的也大都使用"In"作为例子,但很少有人再深入想一步.个人感觉这个In扩展的不够彻

深一层看单一职责原则

单一职责原则(Single Responsibility Principle, SRP)是Bob大叔提倡的S.O.L.I.D五大 设计原则中的第一个.其中,职责(Responsibility)被表述为"变化的原因" (reason to change):SRP被表述为"一个类应该有且只有一个变化的原因".但如果光从字面去理解, SRP很容易让人望文生义产生误解.本文希望能阐明SRP 的本质,达到避免误解和指导设计的 目的. 动机 对于设计原则的理解应该首先从它的动机