1.3 TDD的机理
为了看看TDD能带来什么不同,我们把它和传统的编程方式进行比较。我把传统的方式称为“后期调试式编程”(Debug-Later Programming,DLP)。在后期调试式编程(DLP)中,代码先设计并写出,即代码“写完”之后才进行测试。有趣的是,这个对于“写完”的定义忽略了一半左右的开发工作量。
人都会犯错误,在设计和编码中犯错也很正常。这时我们就发现了后期调试式编程的问题:它可能要在几天、几周或者几个月后才能反馈给开发者。反馈如此之晚,你已不可能从错误中吸取经验了。下次你还是会犯同样的错误。
在慢速反馈的情况下,出错代码之上可能还堆积了不少其他改动,因此问题的根源往往很难确定。有些代码可能已经依赖于错误的行为了。没有明确的原因和结果,唯一可以做的就是确定bug。这种天生很难预知的事情可以毁掉任何精心设计的计划。当然,你也可以为改错计划一些时间。但你计划的那点时间够吗?我们没办法进行可靠的估计。
从图1-1中可以看出,当发现一个bug的时间(Td)增加时,找到这个bug根本原因的时间(Tfind)也会增加,而且往往增加很多。修正有些bug的时间(Tfix)通常和Td无关。但如果这是由建立在错误假设之上的代码造成的组合错误,Tfix也可能大幅度增长。有些bug在数年之后才被发现。
现在来看一下图1-2。当发现bug的时间(Td)趋近于零,定位问题的时间(Tfind)也会趋近于零。刚刚引入到代码中的问题往往是很明显的。就算不那么明显,开发者也可以简单地通过回退来恢复到以前工作的状态。时间只会模糊程序员的记忆并让更多的代码建立在早期错误之上,而TDD则会让Tfind+Tfix最小化。
相比之下,TDD则会给出立即的反馈!对失误的立刻通知将帮助我们避免bug。如果一个bug只能存在几分钟,那它还是bug吗?不,它只是个被避免了的bug。TDD预防bug。后期调试式编程(DLP)则是把浪费制度化。