原文:http://coolshell.cn/articles/3649.html

春节前的一篇那些炒作过度的技术和概念中对敏捷和中国ThoughtWorks的微辞引发了很多争议,也惊动了中国ThoughtWorks公司给我发来了邮件想来找我当面聊聊。对于Agile 的Fans们,意料之中地也对我进行了很多质疑和批评。我也回复了许多评论。不过,我的那些回复都是关于中国ThoughtWorks咨询师以及其咨询的方法的。我对Agile方法论中的具体内容评价的不是很多,所以,我想不妨讨论一下Agile方法论中的具体的实践(以前本站也讨论过结对编程的利与弊)。

那么,这次就说说TDD吧,这是ThoughtWorks中国和Agile的Fans们最喜欢的东西了。我在原来的那篇文章中,我把TDD从过度炒作的技术剔除了出去,因为我还是觉得TDD有些道理的,不过,回顾我的经验,我也并不是很喜欢TDD。我这篇文章是想告诉大家,TDD并没有看上去的那么美,而且非常难以掌控,并且,这个方法是有悖论之处的

TDD简介

TDD全称Test Driven Development,是一种软件开发的流程,其由敏捷的“极限编程” 引入。其开发过程是从功能需求的test case开始,先添加一个test case,然后运行所有的test case看看有没有问题,再实现test case所要测试的功能,然后再运行test case,查看是否有case失败,然后重构代码,再重复以上步骤。其理念主要是确保两件事:

  • 确保所有的需求都能被照顾到。
  • 在代码不断增加和重构的过程中,可以检查所有的功能是否正确。
  • 我不否认TDD的一些有用的地方,如果我们以Test Case 开始,那么,我们就可以立刻知道我们的代码运行的情况是什么样的,这样可以让我们更早地得到我们实现思路的反馈,于是我们更会有信心去重构,去重新设计,从而可以让我们的代码更为正确。

    不过,我想提醒的是,TDD和Unit Test是两码子事儿。有很多人可能混淆了自动化的Unit Test(如:XUnit系例)和TDD的软件开发过程。另外,可能还会有人向鼓吹“TDD让你进行自顶向下的设计方式”,对此,请参阅本站的《Richard Feynman, 挑战者号, 软件工程》——NASA的挑战者号告诉你自顶向下设计的危险性。

    TDD的困难之处

    下面是几个我认为TDD不容易掌控的地方,甚至就有些不可能(如果有某某TDD的Fans或是ThoughtWorks的咨询师和你鼓吹TDD,你可以问问他们下面这些问题)

  • 测试范围的确定。TDD开发流程,一般是先写Test Case。Test Case有很多种,有Functional的,有Unit的,有Integration的……,最难的是Test Case要写成什么样的程度呢。
  • 如果写的太过High Level,那么,当你的Test Case 失败的时候,你不知道哪里出问题了,你得要花很多精力去debug代码。而我们希望的是其能够告诉我是哪个模块出的问题。只有High Level的Test Case,岂不就是Waterfall中的Test环节?
  • 如果写的太过Low Level,那么,带来的问题是,你需要花两倍的时间来维护你的代码,一份给test case,一份给实现的功能代码。
  • 另外,如果写得太Low Level,根据Agile的迭代开发来说,你的需求是易变的,很多时候,我们的需求都是开发人员自己做的Assumption。所以,你把Test Case 写得越细,将来,一旦需求或Assumption发生变化,你的维护成本也是成级数增加的。
  • 当然,如果我把一个功能或模块实现好了,我当然知道Test 的Scope在哪里,我也知道我的Test Case需要写成什么样的程度。但是,TDD的悖论就在于,你在实现之前先把Test Case就写出来,所以,你怎么能保证你一开始的Test Case是适合于你后面的代码的?不要忘了,程序员也是在开发的过程中逐渐了解需求和系统的。如果边实现边调整Test Case,为什么不在实现完后再写Test Case呢?如果是这样的话,那就不是TDD了。
  • 关注测试而不是设计。这可能是TDD的一个弊端,就像《十条不错的编程观点》中所说的一样——“Unit Test won’t help you write the good code”,在实际的操作过程中,我看到很多程序员为了赶工或是应付工作,导致其写的代码是为了满足测试的,而忽略了代码质量和实际需求。有时候,当我们重构代码或是fix bug的时候,甚至导致程序员认为只要所有的Test Case都通过了,代码就是正确的。当然,TDD的粉丝们一定会有下面的辩解:
  • 可以通过结对编程来保证代码质量。
  • 代码一开始就是需要满足功能正确,后面才是重构和调优,而TDD正好让你的重构和优化不会以牺牲功能为代价。
  • 说的没错,但仅在理论上。操作起来可能会并不会得到期望的结果。1)“结对编程”其并不能保证结对的两个人都不会以满足测试为目的,因为重构或是优化的过程中,一旦程序员看到N多的test cases 都failed了,人是会紧张的,你会不自然地去fix你的代码以让所有的test case都通过。2)另外,我不知道大家怎么编程,我一般的做法是从大局思考一下各种可行的实现方案,对于一些难点需要实际地去编程试试,最后权衡比较,挑选一个最好的方案去实现。而往往着急着去实现某一功能,通常在会导致的是返工,而后面的重构基本上因为前期考虑不足和成为了重写。所以,在实际操作过程中,你会发现,很多时候的重构通常意味着重写,因为那些”非功能性”的需求,你不得不re-design。而re-design往往意味着,你要重写很多 Low-Level的Test Cases,搞得你只敢写High Level的Test Case。

  • TDD导致大量的Mock和Stub。相信我,Test Case并不一定是那么容易的。比如,和其它团队或是系统的接口的对接,或是对实现还不是很清楚的模块,等等。于是你需要在你的代码中做很多的Mock和 Stub,甚至fake一些函数来做模拟,很明显,你需要作大量的 assumption。于是,你发现管理和维护这些Mock和Stub也成了一种负担,最要命的是,那不是真正的集成测试,你的Test Case中的Mock很可能是错的,你需要重写他们。
  • 也许,你会说,就算是不用TDD,在正常的开发过程中,我们的确需要使用Mock和Stub。没错!的确是这样的,不过,记住,我们是在实现代码后来决定什么地方放一个Mock或Stub,而不是在代码实现前干这个事的。

  • Test Case并没有想像中的那么简单。和Waterfall一样,Waterfall的每一个环节都依赖于前面那个环节的正确性,如果我们没有正确的理解需求,那么对于TDD,Test Case和我们的Code都会的错的。所以,TDD中,Test Case是开发中最重要的环节,Test Case的质量的问题会直接导致软件开发的正确和效率。而TW的咨询师和Agile的Fans们似乎天生就认为,TDD比Waterfall更能准确地了解需求。如果真是这样,用TDD进行需求分析,后面直接Waterfall就OK了
  • 另外,某些Test Case并不一定那么好写,你可能80%的编程时间需要花在某个Test Case的设计和实现上(比如:测试并发),然后,需求一变,你又得重写Test Case。有时候,你会发现写Test Case其实和做实际设计没有差别,你同样要考虑你Test Case的正确性,扩展性,易读性,易维护性,甚至重用性。如果说我们开发的Test Case是用来保证我们代码实现的正确性,那么,谁又来保证我们的Test Case的正确性呢?编写Test Case也需要结对或是Code review吗?软件开发有点像长跑,如果把能量花在了前半程,后半程在发力就能难了。

    也许,TDD真是过度炒作的,不过,我还真是见过使用TDD开发的不错的项目,只不过那个项目比较简单了。更多的情况下,我看到的是教条式的生硬的 TDD,所以,不奇怪地听到了程序员们的抱怨——“自从用了TDD,工作量更大了”。当然,这也不能怪他们,TDD本来就是很难把控的方法。这里送给软件开发管理者们一句话——“当你的软件开发出现问题的时候,就像bug-fix一样,首要的事是找到root cause,然后再case by case的解决,千万不要因为有问题就要马上换一种新的开发方法”。相信我,大多数的问题是人和管理者的问题,不是方法的问题。

    虚拟座谈会:TDD有多美?
    http://www.infoq.com/cn/articles/virtual-panel-tdd

    TDD并不是看上去的那么美的更多相关文章

    1. 让Python带你看一场唯美的横飘雪!

      “北国风光,千里冰封,万里雪飘”,这句诗描写了一句美丽肃静的风光图,恰逢昨天笔者这边也下了一场比较大的雪,要不今天就用Python带大家也来领略一次美丽的雪景? 开发环境 版本:Python3.6 系 ...

    2. BBC这10部国宝级纪录片,让孩子看遍世间最美的地方

      https://weibo.com/ttarticle/p/show?id=2309404382383649486138#related

    3. 看美剧英文字幕学英语的利器——“深蓝英文字幕助手”简介

      我从初中开始基本上就是一个英语很烂的人,数理化再好有什么用,工作了,结果发现数理化都没啥用,最有用的还是当年学的最烂的英语.于是在2011年年底开始了学习英语的课程,在学习的过程中,外教经常会放英剧美 ...

    4. 测试驱动开发(TDD)及测试框架Mocha.js入门学习

      组里马上要转变开发模式,由传统的开发模式(Developer开发,QA测试),转变为尝试TDD(Test-driven development,测试驱动开发)的开发模型.由此将不存在QA的角色,或者仅 ...

    5. 【学英语~磨耳朵】2013年以来看过的所有美剧&电影&纪录片等等

      我看美剧看太多了,而且同一部剧刷很多遍.这种coach potato的做法其实一点也不好,英文会好可能只是意外收获.下面是单子: 美剧: 老友记-情景喜剧-10季全看.至今还在网易云音乐循环10季音频 ...

    6. Win10看图总有遮挡?如何找回好用的照片查看器

      来,大家日常在电脑上查看图片是用什么软件?老牌的ACDSee.XXX看图王.美图看看还是Win系统自带的呢?反正小编在没什么特殊需要的时候,只用系统自带,免除安装.功能够用,想要进行处理也能用Win自 ...

    7. IDDD 实现领域驱动设计-一个简单业务用例的回顾和理解

      上一篇:<IDDD 实现领域驱动设计-由贫血导致的失忆症> 这篇博文是对<实现领域驱动设计>第一章后半部分内容的理解. Domain Experts-领域专家 这节点内容是昨天 ...

    8. 对HTML+CSS+JavaScript的个人理解

      HTML就像人的骨头架子,是人的根基,要有个人样呀,一个网站,一个WebApp要是缺根儿骨头,那就像人少个胳膊少个腿儿的,行动不方便啊:CSS就像人穿得衣服.鞋子,男人的纹身,女人擦得粉儿,好看呀,一 ...

    9. Apache Spark源码走读之14 -- Graphx实现剖析

      欢迎转载,转载请注明出处,徽沪一郎. 概要 图的并行化处理一直是一个非常热门的话题,这里头的重点有两个,一是如何将图的算法并行化,二是找到一个合适的并行化处理框架.Spark作为一个非常优秀的并行处理 ...

    随机推荐

    1. 如何制作一个自适应手机、电脑、ipad的网页方法总结

      进入2015年,手机上网的用户已经越来越多,已经赶超PC端.随着2G.3G.4G.免费WIFI和无线基站的不断普及,越来越多的人开始使用手机上网. 移动设备正超过桌面设备,成为访问互联网的最常见终端. ...

    2. php检测服务器是否可用 不可用发动钉钉消息

      <?php set_time_limit(0); //ping一个IP地址,能不能通 function ping($ip) { $ip_port = explode(':', $ip); // ...

    3. Win7 IIS 部署站点遇到的问题 如 HTTP 错误 404.XX

      HTTP 错误 404.2 - Not Found 由于 Web 服务器上的“ISAPI 和 CGI 限制”列表设置,无法提供您请求的页面. 解决办法:设置为允许-面相 =============== ...

    4. Android自定义视图四:定制onMeasure强制显示为方形

      这个系列是老外写的,干货!翻译出来一起学习.如有不妥,不吝赐教! Android自定义视图一:扩展现有的视图,添加新的XML属性 Android自定义视图二:如何绘制内容 Android自定义视图三: ...

    5. android:padding和android:margin的区别[转]

      本文综合了:http://zhujiao.iteye.com/blog/1856980 和 http://blog.csdn.net/maikol/article/details/6048647 两篇 ...

    6. Web结构组件

      一.Web结构组件 1.代理 位于客户端和服务器之间的HTTP实体,接收客户端的所有HTTP请求,并将这些请求转发给HTTP服务器. 2.缓存 HTTP的仓库,使常用的页面的副本可以保存在离客户端更近 ...

    7. 20155326 《Java程序设计》实验五网络编程与安全实验报告

      20155326 <Java程序设计>实验五网络编程与安全实验报告 实验内容 任务一 1.两人一组结对编程: 参考http://www.cnblogs.com/rocedu/p/67667 ...

    8. nodejs mongodb 数据库封装DB类 -转

      使用到了nodejs的插件mongoose,用mongoose操作mongodb其实蛮方便的. 关于mongoose的安装就是 npm install -g mongoose 这个DB类的数据库配置是 ...

    9. Hdu2389 Rain on your Parade (HK二分图最大匹配)

      Rain on your Parade Problem Description You’re giving a party in the garden of your villa by the sea ...

    10. hdu 4968 最大最小gpa

      http://acm.hdu.edu.cn/showproblem.php?pid=4968 给定平均分和科目数量,要求保证及格的前提下,求平均绩点的最大值和最小值. dp[i][j]表示i个科目,总 ...