《测试驱动开发》读后感
2009-11-27
这本书的作者是“极限编程”之父Kent Beck,书写得很薄,每一章都只有几页的长度。这就好像用TDD方法写出的代码般,每一个单元都是精巧明快的,使得人们很容易读懂,也使人们更有意愿将其读懂(短的文章更能激发人们的阅读欲望,不是吗?)。加之作者的笔调也十分轻松,这种小薄册要比那些百科全书式的大部头读起来舒服许多。
第一部分讲了一个支付系统中支持多币种需求的例子。作者以很慢的节奏来讲解TDD的过程,这节奏慢到甚至让我有一点难以接受,然而当着个例子最终完成的时候,回头看看整个开发过程,感觉如作者所述,不觉间竟然已经走出了这么长的一段距离。个人感觉,假如以传统的先设计再编码的方式开发,除非是非常非常有经验的程序员,否则很容易会得到不符合需求的设计或者花过多精力在需求之外的设计上编码。
第二部分是一个十分特别的例子。一种“提靴带”的开发方式:用xUnit测试框架来测试驱动开发xUnit本身。似乎这种模式只在编译器的开发中存在。从无到有,神奇之至。就好像xUnit被作者注入了神奇的DNA,然后使命般地自我演化生长出一个优秀的单元测试框架。我这么说可能有些夸张了。我并不认为实际的开发工作中会有这么美妙的设计过程。作者作为JUnit的开发者之一,对这套框架自然是了然于胸,设计起来也一定会有举重若轻之感。虽然我没学过Python,但也能跟着作者的“YY思路”一同前行。
第三部分作者揭示了测试驱动开发的模式。这部分有些稍有些“政治课本”的味道了,但依然不失风趣。有了前面两个例子,的铺垫,理解起来也相对容易些了。其中包含了TDD的实践原则(不可运行、可运行、重构)和TDD指导编码的技巧(“设计模式”和“重构”两章)。当读者有了更多的实践和经验,重读这部分会得到更多的体会。
TDD之所以有效率,是因为它使程序员的注意力完全集中于现有的需求,不必过多考虑变化。凡是参加过英语考试的人几乎都知道这样一个应试技巧:做阅读理解题的时候,先看问题然后去原文找答按要比通读全文再看问题做答能更快更准确地答完。这是因为看问题找答案使考生将精力集中到“现有的考试需求”上,回头阅读原文的时候自然而然地忽略掉与问题无关的词句,迅速找到问题相关的段落,提炼出答案。这就是测试驱动开发。我们只需要为现有的需求编写对应的测试用例,然后努力使这些用例通过测试。
TDD有效率的另一方面就是自动化单元测试。这是程序员给代码上的保险。作者在书中打了个比喻,TDD就像是井绳上的防滑扣,它在你没有了力气或者不慎手滑时不会使得吊桶跌落井底。想象一个没有使用TDD方法的项目,由于设计并没有基于项目自身的需求实践,而是基于设计者的经验和推断,在编码阶段,开发人员就会经常一步三回头地回顾设计,并且针对实际编码中遇到的问题做出一些修改;在集成测试阶段以及最终发布之后,没有单元测试用例,在发现Bug时,找出Bug的成因就成了一个艰难的任务。单元测试是从需求的实际出发,通过一点一点实践向前推进的,在编码的同时,也就将部分Bug限定了活动范围;而且单元测试迫使程序员写出便于测试的代码,便于测试的代码,就是的低耦合的代码,一块一块短小清晰的代码要比一坨一坨冗长纠结的代码更容易阅读;自动化测试使测试的成本降低,程序员的每次推进都有会得到快速的检验,前期花在自动化上的工作是值得的,“一次投保,终身收益”;在发现Bug或者遇到需求变更时,程序员也能很快定位问题,因为测试用例给了程序员解决问题的线索,更给了程序员拥抱变化的勇气。
测试驱动开发,是一种很人性化的开发方法。其中包含了很多心理学因素。它给了程序员勇气。即使不是基本功扎实程序员,也能用这种方法开发出好的程序(看一下书中附录B那个用TDD方法开发的Fibonacci数列程序,是不是觉得有些好笑?但回顾你第一次写Fib时的情景,是不是有似曾相识的感觉?);它使程序员能把问题管理好,使得代码是新鲜的、干净的、可控的;测试用例也量化了项目开发的进度,项目如期交付变得可能。
一直以来,我都有这样一个愿景:程序员们不再需要加班,不用再每天盯着显示器焦头烂额,不再有产品交付前的Debug炼狱,不再时常被发布版Bug噩梦惊醒,每晚睡得踏实, 每天8小时上班,我们可以一边喝着香醇的咖啡茶一边远望窗外的美丽风景,当自动测试报告出来后,我们能对着它微笑,然后轻松处理其中的每一个问题。我不敢说TDD能够实现这个愿景,但至少它给了我实现这愿景的希望。
Keep the bar green, to keep the code clean!