本文共 4102 字,大约阅读时间需要 13 分钟。
摘要:在软件行业中,神仙打架的名场面,那就不得不提的是2014年的那场——测试驱动开发(TDD)之争。
在历史上有很多精彩绝伦的神仙打架,比如数学界的牛顿和莱布尼茨关于微积分的旷世之争;比如量子物理中的爱因斯坦和波尔的紫禁之巅;比如足球里的梅西和C罗的旗鼓相当难分高下;又比如滴滴和快滴之间触目惊心的烧钱大战……而在软件行业中,也同样有神仙打架的名场面,那就不得不提的是2014年的那场——测试驱动开发(TDD)之争。
比赛的红方是David Heinemeier Hansson,蓝方是Kent Beck。David Heinemeier Hansson 由于名字较长简写成DHH,Ruby on Rails 正是出自于DHH之手。而这场打架还加入了“裁判”员——Martin Fowler,在比赛中Martin Fowler记录了红蓝双方的每一次组合拳、上勾拳、侧踹、抱摔……总结如下:
DHH已将TDD委托给历史垃圾堆。我很难过,不是因为我就把它从历史的垃圾堆中拯救出来,而是因为现在我需要雇佣新技术来帮助我解决编程过程中的许多问题:
神仙打架不亏是神仙打架,从那以后业界关于测试驱动开发的观念也分成了两派。一派主要来源自像国内的一些互联网等项目中声音——需求的迭代和更新之快,要求公司或团队能快速交付有价值的产品,而TDD对于很多开发人员来说无疑是带来了繁重的工作压力和交付压力。甚至有人开玩笑话说:“ Deadline Driven Development 才是第一生产力 ”。
当然也有人力挺TDD,“TDD并没有死。很明显,既然它有这么这么多的支持者,它怎么可能会死呢? 这就像在问,设计模式死了吗?或者功能性自动化死了吗?不,它并没有死。而且它在将来任何时候都不会死亡。它将来可能会变成其他一些新的事物、甚至是一些更好的事物,但是它永远不会死亡。所以让我们跳过这一部分吧。”
关于测试驱动开发说了这么久,那么测试驱动开发到底是个啥呢?
测试驱动开发,英文全称Test-Driven Development,简称TDD,是一种不同于传统软件开发流程的新型的开发方法。 它要求在编写某个功能的代码之前先编写测试代码,然后只编写使测试通过的功能代码,通过测试来推动整个开发的进行。 这有助于编写简洁可用和高质量的代码,并加速开发过程。
Kent Beck:“测试驱动开发不是一种测试技术。它是一种分析技术、设计技术,更是一种组织所有开发活动的技术”。
分析技术: 体现在对问题域的分析,当问题还没有被分解成一个个可操作的任务时,分析技术就派上用场,例如需求分析、任务拆分和任务规划等,《实例化需求》这本书可以给予一定的帮助作用。
设计技术: 测试驱动代码的设计和功能的实现,然后驱动代码的再设计和重构,在持续细微的反馈中改善代码。
组织所有开发活动的技术: TDD 很好地组织了测试、开发和重构活动,但又不仅限于此,比如实施 TDD 的前置活动包括需求分析、任务拆分和规划活动,这使得 TDD 具有非常好的扩展性。
Kent Beck 在他的著作《Test-Driven Development》(见参考附录)一书中提到:“代码简洁可用这句言简意赅的话,正是 TDD 所追求的目标”。
对于如何保证“代码简洁可用”可以使用分而治之的方法,先达到“可用”目标,再追求“简洁”目标。
可用: 保证代码通过自动化测试。
代码简洁: 在不同阶段人们对简洁的理解程度也不一样,不过遵循的原则差不多,例如 OOD 的 SOLID 原则(详见参考附录),Kent Beck 的 Simple Design 原则(详见参考附录)等。
虽然有很多因素妨碍我们得到整洁的代码,甚至可用的代码,无需征求太多意见,只需要采用 TDD 的开发方式来驱动出简洁可用的代码。
在TDD 的过程中,需要遵循的三项原则:
测试驱动开发是一个过程,依赖于不断重复极短的开发周期,这个周期也称为“红灯-绿灯-重构”,如上图。简单的来说,基于TDD的三项原则,TDD的这种步骤(周期)如下:
需要注意的是,不同阶段有不同的目的,他们需要不同的解决方案,前二个阶段需要很快地完成,以便知道新添加功能的状态。为了达成这个目的,可以通过任何手段,因为仅在这时才这样做,也是为了能快速完成好的设计。
TDD主要的好处主要包括了,确定性、重构代码、单元测试即文档。
确定性。TDD提升了单元测试的覆盖率,在每轮迭代产品都会新增代码,如果有一套覆盖率很高( 90% 或更高)的单元测试,那么只需执跑一遍测试用例,那么能成功交付的把握就会比较大。反之,如果覆盖率越低,越需要更多的人力去进行手动验证。 在 kent Beck的《测试驱动开发》举的例子中,正因有了TDD才有勇气和老板说我们可以做!这就是TDD最强大的地方,它让你拥有一套值得信赖的测试,打消你对修改代码的恐惧。
重构代码。Martin Flower在他的《重构》中也指出,完善的单元测试是他进行重构的基石,从TDD的流程可以看到,重构是TDD的一部分,运用TDD的同时也推动了代码的重构。
单元测试即文档。在软件行业里,人员的变动的很频繁的,如果要尽快熟悉某个模块的业务逻辑。看文档?程序员写的文章一般都不太容易看,而且文档经常会和代码不同步,代码修改了文档没跟着改的事情经常发生。看源码?看完也不一定知道为什么。如果这时候有一套非常完整的单元测试,那可能就是所有接手别人代码的程序员的福音。首先,代码不会撒谎,其次,测试用例明确告诉了你这个函数是做什么的,什么输入对应的都有什么预期输出。单元测试就是最好的底层文档,哪个专业人士不想提供这样一份文档呢?
此外,TDD还能够促成良好的代码设计。由于你先写测试代码,你会尽可能的让代码调用起来更加简单方便,这也就促使你去考虑如何更好的设计代码。以避免会出现一个函数里实现的功能过多,或者和其他代码过于耦合而无法测试的情况。
当然测试驱动开发除了好处以外,还有神仙打架中红方代表DHH所提出的一些问题。总结来看,关于TDD的争议可以大致从这几个方面来看,软件开发应该由什么来驱动,测试的速度和覆盖程度,以及设计思想层面等几方面。从 辩证统一的角度来看,事物有两个方面, TDD不一定能适用于所有的场景,同样TDD的局限性在某些场景下也不见得是对的,如果想要能更好的适用于自身,不仅要拿捏好度的问题还要以敏捷的思想来应对问题,比如不应该盲目的制定100%或0%的测试覆盖率,也不应该固化开发步骤而不顾实际情况。
所以,在最后的神仙打架中,Kent Beck也表达了David的论述可能会让TDD浴火重生、凤凰涅槃的观点,希望可以找到更加好的方法。但无论如何, 在我们实际工作中,不应该因为某些 观点成为我们接受或者拒绝它的理由。正所谓大道甚夷,而民好径,作为敏捷开发中的一项优秀实践来看,TDD只有在真正使用过后才能评价是否已死的问题。那么你在践行敏捷开发的时候,是否使用过TDD这种实践呢,又或是践行过其他一些敏捷开发的实践呢,有没有评测过你所在的项目中的敏捷开发的成熟度是如何的呢?
没有那就对了!
华为云的DevCloud专业服务正是为此而生!
针对不同的岗位提供了评估的能力,让开发者可以对号入座,并基于你所在的岗位、技术得到客观、全面、系统的测评以及名师般的学习引导。快来访问,通过个人能力评估,看看自己是什么水平吧!
本文分享自华为云社区《快来看神仙打架啊》,原文作者:敏捷的小智。
转载地址:http://umquz.baihongyu.com/