TDD并不是看上去的那么美
春节前的一篇那些炒作过度的技术和概念中对敏捷和中国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的困难之处
下面是几个我认为TDD不容易掌控的地方,甚至就有些不可能(如果有某某TDD的Fans或是ThoughtWorks的咨询师和你鼓吹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。没错!的确是这样的,不过,记住,我们是在实现代码后来决定什么地方放一个Mock或Stub,而不是在代码实现前干这个事的。
另外,某些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的解决,千万不要因为有问题就要马上换一种新的开发方法”。相信我,大多数的问题是人和管理者的问题,不是方法的问题。
建议继续学习:
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:陈皓 来源: 酷壳 - CoolShell.cn
- 标签: TDD
- 发布时间:2011-02-13 22:29:00
- [66] Oracle MTS模式下 进程地址与会话信
- [65] Go Reflect 性能
- [64] 如何拿下简短的域名
- [60] android 开发入门
- [59] 图书馆的世界纪录
- [59] 【社会化设计】自我(self)部分――欢迎区
- [58] IOS安全–浅谈关于IOS加固的几种方法
- [54] 视觉调整-设计师 vs. 逻辑
- [47] 界面设计速成
- [47] 读书笔记-壹百度:百度十年千倍的29条法则