TDD并不是看上去的那么美

简介: 导读:酷壳网的陈皓之前在网站上发布了一篇题为《那些炒作过度的技术和概念》,现在再次给大家介绍《TDD并不是看上去的那么美》,文章详细剖析了TDD的困难之处、TDD是测试范围等等。以下是全文:春节前的一篇那些炒作过度的技术和概念中对敏捷和中国ThoughtWorks的微辞引发了很多争议,也惊动了中国ThoughtWorks公司给我发来了邮件想来找我当面聊聊。

导读:酷壳网的陈皓之前在网站上发布了一篇题为《那些炒作过度的技术和概念》,现在再次给大家介绍《TDD并不是看上去的那么美》,文章详细剖析了TDD的困难之处、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,你可以问问他们下面这些问题)

测试范围的确定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正好让你的重构和优化不会以牺牲功能为代价。说的没错,但仅在理论上。操作起来可能会并不会得到期望的结果。“结对编程”其并不能保证结对的两个人都不会以满足测试为目的,因为重构或是优化的过程中,一旦程序员看到N多的test cases 都failed了,人是会紧张的,你会不自然地去fix你的代码以让所有的test case都通过。另外,我不知道大家怎么编程,我一般的做法是从大局思考一下各种可行的实现方案,对于一些难点需要实际地去编程试试,最后权衡比较,挑选一个最好的方案去实现。而往往着急着去实现某一功能,通常在会导致的是返工,而后面的重构基本上因为前期考虑不足和成为了重写。所以,在实际操作过程中,你会发现,很多时候的重构通常意味着重写,因为那些”非功能性”的需求,你不得不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的解决,千万不要因为有问题就要马上换一种新的开发方法”。相信我,大多数的问题是人和管理者的问题,不是方法的问题。

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

目录
相关文章
|
26天前
|
算法 搜索推荐 程序员
编程之舞:探索代码的诗意与美
【10月更文挑战第25天】在数字世界的海洋里,代码不仅是冰冷的逻辑和命令,它也如同一首首精妙绝伦的诗篇,充满了节奏感、和谐与美感。本文将带你领略编程的艺术之美,通过深入浅出的语言和生动的比喻,让你体会到编程不只是技术的堆砌,更是创造力的体现。从基础的数据结构到复杂的算法设计,我们将一同揭开编程的神秘面纱,感受它带来的无限可能。
|
4月前
|
程序员 微服务
编码之舞:探索编程语言的诗意与美
在数字世界的深处,编程不仅仅是冷冰冰的代码和逻辑。它是艺术家的画笔,诗人的羽毛笔,能够描绘出功能性与美感并存的作品。本文将通过一次个人的技术感悟之旅,探讨如何在日常的软件开发过程中寻找和创造美,以及这种追求如何影响一个程序员的成长和技术选择。
22 0
|
小程序 Oracle Java
设计:小即是美
设计:小即是美
设计:小即是美
|
分布式计算 Java 编译器
Martin Odersky访谈录所思
Martin Odersky访谈录所思
|
机器学习/深度学习 监控 Kubernetes
软件工程大师 Martin Fowler 谈机器学习持续交付(中)
机器学习应用程序在我们的行业中变得越来越流行,但是与更传统的软件(例如: Web 服务或移动应用程序)相比,开发、部署和持续改进它们的过程更加复杂。 它们会在三个轴上发生变化:代码本身、模型和数据。 他们的行为通常很复杂且难以预测,而且他们更难测试、更难解释、更难改进。 机器学习的持续交付 (CD4ML) 是将持续交付原则和实践引入机器学习应用程序的学科。
|
机器学习/深度学习 存储 算法
软件工程大师 Martin Fowler 谈机器学习持续交付(上)
机器学习应用程序在我们的行业中变得越来越流行,但是与更传统的软件(例如: Web 服务或移动应用程序)相比,开发、部署和持续改进它们的过程更加复杂。 它们会在三个轴上发生变化:代码本身、模型和数据。 他们的行为通常很复杂且难以预测,而且他们更难测试、更难解释、更难改进。 机器学习的持续交付 (CD4ML) 是将持续交付原则和实践引入机器学习应用程序的学科。
|
架构师
怎么做软件设计才美
之前学习了极客时间上的一个专栏《软件设计之美》,作者对软件设计、编程范式、设计原则与模式、设计方法进行了讲解,内容全面。 专栏里面的一些内容,也有些接触,但认知还不够深,比如面向对象。而且专栏把这些内容都串联起来,跟着专栏内容总结梳理一下。
152 0
怎么做软件设计才美
|
算法 程序员 测试技术
【人月神话】01 人月神话
【人月神话】01 人月神话
200 0
【人月神话】01 人月神话