摘要:在软件行业中,神仙打架的名局面,那就不得不提的是 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 的话,你的代码就是恶浊的。
由单元测试开始驱动你的设计并不是一个好的主见。
TDD 的概念流量交易“测试必须够快”是目光短浅的。
对 TDD 的依赖会导致彻底遗记零碎测试。
关注并且只关注单元模块并不能有助于创立一套完满的零碎。
100% 的覆盖率是愚昧的。
程序员心愿软件是一门迷信,可是它并不是。它更像是创造性的写作流动。
优良的软件并不像工程学那样,它更像写作。分明简洁的写作要优于简单艰涩的写作。
清晰是有益处的,好到应该将清晰性作为第一指标,而非测试覆盖度或者测试速度。
成为一名优良的开发人员就像成为一名优良的作家一样艰难。
就像写作一样,成为优良的程序员的方法就是以清晰为指标从而大量编写软件、大量浏览软件。
蓝方 Kent Beck 观点:
DHH 已将 TDD 委托给历史垃圾堆。我很惆怅,不是因为我就把它从历史的垃圾堆中援救进去,而是因为当初我须要雇佣新技术来帮忙我解决编程过程中的许多问题:
适度工程化。我偏向于“投入”我“晓得”我“将须要”的性能。使一个红色的测试变为绿色(以及将来的测试列表)有助于我实现足够的性能。我须要找到一个新的办法来放弃专一。
API 反馈。我须要找到一种新的办法来取得对于我的 API 决策的疾速反馈。
逻辑谬误。我须要找到一种新的办法来抓住那些我很容易犯的厌恶的测试谬误。
文档。我须要找到一种新的形式来传播我对 api 的冀望,并记录我在开发过程中的想法。
感到手足无措。我真的会思念如何应用 TDD,即便我无奈设想一个实现,我简直总能想出如何编写测试。我须要找到一个新的办法,以便下一步上山。
将接口与实现思维拆散。我偏向于用实现揣测来净化 API 设计决策。我须要找到一种新的办法来拆散这两个档次的思维,同时在它们之间提供疾速的反馈。
协定。我须要找到一个新的办法,准确地与一个编程搭档对于我正在解决的问题。
焦虑。兴许我最思念的是 TDD 给我的霎时“所有都好吗?”按钮。
我置信我会找到其余办法来解决这些问题。及时。疼痛会加重的。再见 TDD,老朋友。
神仙打架不亏是神仙打架,从那以后业界对于测试驱动开发的观点也分成了两派。一派次要起源自像国内的一些互联网等我的项目中声音——需要的迭代和更新之快,要求公司或团队能疾速交付有价值的产品,而 TDD 对于很多开发人员来说无疑是带来了沉重的工作压力和交付压力。甚至有人开玩笑话说:“Deadline Driven Development 才是第一生产力”。
当然也有人力挺 TDD,“TDD 并没有死。很显著,既然它有这么这么多的支持者,它怎么可能会死呢? 这就像在问,设计模式死了吗?或者功能性自动化死了吗?不,它并没有死。而且它在未来任何时候都不会死亡。它未来可能会变成其余一些新的事物、甚至是一些更好的事物,然而它永远不会死亡。所以让咱们跳过这一部分吧。”
对于测试驱动开发说了这么久,那么测试驱动开发到底是个啥呢?
测试驱动开发(TDD)是什么
测试驱动开发,英文全称 Test-Driven Development,简称 TDD,是一种不同于传统软件开发流程的新型的开发方法。它要求在编写某个性能的代码之前先编写测试代码,而后只编写使测试通过的性能代码,通过测试来推动整个开发的进行。这有助于编写简洁可用和高质量的代码,并减速开发过程。
Kent Beck:“测试驱动开发不是一种测试技术。它是一种剖析技术、设计技术,更是一种组织所有开发流动的技术”。
剖析技术:体现在对问题域的剖析,当问题还没有被分解成一个个可操作的工作时,剖析技术就派上用场,例如需要剖析、工作拆分和工作布局等,《实例化需要》这本书能够给予肯定的帮忙作用。
设计技术:测试驱动代码的设计和性能的实现,而后驱动代码的再设计和重构,在继续轻微的反馈中改善代码。
组织所有开发流动的技术:TDD 很好地组织了测试、开发和重构流动,但又不仅限于此,比方施行 TDD 的前置流动包含需要剖析、工作拆分和布局流动,这使得 TDD 具备十分好的扩展性。
测试驱动开发(TDD)的指标
Kent Beck 在他的著述《Test-Driven Development》(见参考附录)一书中提到:“代码简洁可用这句长篇累牍的话,正是 TDD 所谋求的指标”。
对于如何保障“代码简洁可用”能够应用分而治之的办法,先达到“可用”指标,再谋求“简洁”指标。
可用:保障代码通过自动化测试。
代码简洁:在不同阶段人们对简洁的了解水平也不一样,不过遵循的准则差不多,例如 OOD 的 SOLID 准则(详见参考附录),Kent Beck 的 Simple Design 准则(详见参考附录)等。
尽管有很多因素障碍咱们失去整洁的代码,甚至可用的代码,无需征求太多意见,只须要采纳 TDD 的开发方式来驱动出简洁可用的代码。
测试驱动开发(TDD)的规定
在 TDD 的过程中,须要遵循的三项准则:
在编写好失败的单元测试之前,不要写任何产品代码。
只有有一个单元测试失败了,就不要再写测试代码。无奈通过编译也是一种失败。
产品代码恰好可能让以后失败的单元测试胜利通过即可,不要多写。
测试驱动开发(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 这种实际呢,又或是践行过其余一些麻利开发的实际呢,有没有评测过你所在的我的项目中的麻利开发的成熟度是如何的呢?
没有那就对了!