今天在reddit看到微软某大牛的博客(https://blogs.msdn.microsoft.com/ericgu/2017/06/22/notdd/),说到拒绝TDD(测试驱动开发,下文统一使用TDD)的事情。我很有感触。感兴趣的可以看看原文,我大概总结一下原文的意思(TL;DR):1、大多数TTD做的好的,都是设计和重构牛逼的;2、如果TDD的第三步(重构)去掉,剩下的只有一堆耦合很高的测试,写测试耗时很长,测试很难写。所以新手在学习编程时,学会设计和重构才是最重要的,而设计和重构是通过经验获得的,没有很死的规则。
下面有个很有意思的评论,说现在只要有人反对TDD的思想,别人就会鄙视他/她。那些TDD的推崇者,说TDD做不好的,是“没有按照正确的方式”来做。于是团队里某个TDD拥护者想给其他人展示“正确的方式”:写了一个小程序,包含300个测试;程序到了QA,几天内发现90个bug;都是典型的UI bug;修复前两个bug花了三天,因为很多测试要重写……
上面的例子有些夸张,不知道是否属实。我对TDD有大概的认识,不过向来不感冒。大概是因为我对于编程的理解,和TDD有本质的不同。TDD要求测试优先,我不知道有没有人在实践中,会先把测试写出来,再去写代码。这个是我不能理解的。如果要写测试,必然是要测试的东西都设计好了,接口成形了。实际上,我们往往在实现的过程中,才可以逐渐把接口抽象出来。也就是说,写程序的过程,是一个重构的过程,重要的是写出一些代码来,才有的重构,才有的测试。
程序的设计是需要重构的,一开始没有人能把所有细节想清楚,往往一开始是不管设计的,只要写出来一个能够用的程序,可能设计很糟糕,但是至少有个重构的对象,剩下的就是在不改变功能的情况下,来对程序进行各种变换修改了。作家写作也是一样的,先不管他,把能想到的都写出来,然后再调整、修改、润色,这和写程序一模一样。
不知道大家看到大触绘画没有,或者雕刻家雕刻,这些都有个共同的特点,就是一开始只是画个大概和轮廓,然后再一遍一遍地雕琢细节。我认为写程序本质上和画画、雕刻、写作等艺术创作的过程是一样,你有个灵感,写一些东西,重构一下,再重构一下,直到你认为成形了。唯一不一样的,是程序的有些部分需要实际运行才能确认是否正确,我想这才是测试的价值:你对于某一部分没有信心,所以写个测试来确保这块能够正常运行,通常这部分都是和外部系统交互的。
把测试提到最重要的部分,用测试来保证程序的正确性,是本末倒置的表现,也是一种教条主义。就像所谓各种敏捷的方法论一样,虽然有一定的价值,然而按照全部规则来做的,无疑会出现各种问题。团队都是不一样的,敏捷也要理解精髓,自定义实践,而不是拿别人总结的规则来生搬硬套。