最近又有一个同事和我讨论TDD并质疑TDD是否真的有用,已经记不清是第几次类似的讨论了,前段时间王垠的一篇关于 AI 的文章中也顺带黑了一把 scrum 和 tdd,作为一个坚持实践 tdd 的tdd粉,我觉得应该深入讨论下这个问题,有时候听一听不同的意见,反而能让我们看的更加清楚。

那么,为什么这么多人不喜欢 TDD 呢?

TDD 和设计

有一个普遍存在的误解,认为采用 TDD 能够帮助我们做出更好的设计,而当抱着这个期待去 TDD 的时候,却发现得到的结果也只是 just so so,瞬间粉转黑?

我自己在最初尝试 TDD 的时候也一直存在这种错觉,毕竟在 TDD 的过程中的确可以得到更加面向接口的设计,通过小步迭代进行快速重构,最终得出的代码相较于之前还是有明显提升的。观念的转变来源于两次Coding Dojo,第一次是TDD的Coding Dojo,通过使用TDD我自认为得到了一个很解耦的设计,而同一个题目在第二次关于软件设计的Coding Dojo中却得到了完全不一样的结果,采用抽象原子加组合的设计模式,代码更加简洁,可扩展性也更高。

这件事让我对 TDD 产生了怀疑,差一点也要粉转黑,不过,在进行一番思索之后我才发现我在纠结的根本是一个伪命题。

TDD 通常不提倡前期把详细的设计全部做好,而是鼓励在重构过程中进行涌现式设计,根据需要一步一步剥离或者调整接口,根据TDD的3步军规,你新增的所有代码应该是刚好能保证前一个测试用例通过,事实上,如果我们严格按照3步军规去做,很快就会发现一个问题:因为每次增加的代码不多,代码设计只能一点一点调整,在某一次的调整过程中如果代码设计进入一个岔道,往后可能就只能在这个岔道上一路向北,不能回头了!看起来是因为遵守了3步军规,导致驱动出一个 just so so 的设计。

实则不然。

虽然大多数时候我们要遵守3步军规,但是当我们意识到有更好的设计涌现出来的时候,要果断的抛弃现有的用例和代码,基于新的设计重新进行 TDD!

而至于我们能否意识到更好的设计,则和我们在设计方面的能力有关,和TDD无关!

所以 TDD 只是驱动开发(Develop),而不是驱动设计(Design)。

TDD 和单元测试的成本

另一个一直纠结不休的争论是关于成本,如果一个功能只需要200行代码就能搞定,我为什么要多写200行的测试呢?看起来工作量翻了一倍,而且一旦后面设计有调整,这200行的测试用例立马就打了水漂!

这个问题很难解释,特别是对因为存在类似疑问而从来不曾真正动手去写单元测试的人,不管什么样的解释都看起来很苍白。在尝试解释了 N 多遍并失败之后,这里我再尝试把这些失败的解释总结一下。

开发效率不仅仅体现在代码编写上

内部质量不受控的代码,在调试和后期维护中会耗费成倍的成本,一个简单的 for 循环越界,或者 == 写成 = 的手误,在写代码时只是那么一两秒的脑回路短路,但在未来可能会花上几天甚至几周的时间定位,更不用说复盘,分析报告和毫无意义的改进举措了!
单元测试能有效减少代码中的低级错误,而TDD能在编码环节就让你更清楚的理解需求边界和测试场景,不至于到调试阶段才发现某些场景在编码时遗漏。

即使是仅针对代码编写效率,TDD也有助于提升

TDD有助于我们进行出面向接口编程,合理的接口划分能将全局复杂的业务逻辑分解到各个独立的接口实现中,从而降低局部复杂度;另外,TDD让编码过程更专注,更容易进入到“心流”的状态,从而提升程序员的编码效率。

测试的重构是很自然

至于测试的重构,不妨和 FT 类比一下,如果用户需求发生了变化,测试场景需要调整,FT也要进行重新设计,UT 也是一样,当待测试的对象变更了(类重新设计),对应的测试代码肯定也要删除重写。实际情况中,除非是基础数据类型发生重构会触发大面积的测试用例重构外,大多数情况下代码之间依赖的都是接口,相对而言接口是比较稳定的,如果仅仅是接口实现的变更,往往只需要重构对应该接口实现的测试用例即可,对依赖该接口的类没有波及。

这个问题是最难解释的一个,只能说如果我们连这种成本都不愿意付出,那我们还是不要做软件了。

TDD 和大神

我想Linus在写Linux内核的时候,应该不是采用 TDD 的方式开发的,但是 Linux 绝对是非常伟大的产品,有很多伟大的设计,我们也看到,实际上很多大神级别的人物,并不采用 TDD 的开发方式,包括前面提到王垠的文章,这段时间在看《Unix编程艺术》甚至对于 C++/OO 都并不抱太多好感。

所以我在想,为什么呢?

后来想到一个可能的结论——对于这些大神级别的人物来说,因为他们对于软件开发本质的理解已经达到相当的高度,TDD这种工具或者方法对于他们来说,都太过于重量,或者说束手束脚。

这样一想就又释然了,谁叫咱还没到那高度呢,还是老老实实写 TDD 吧……

余下全文(1/3)

本文最初发表在www.jianshu.com,文章内容属作者个人观点,不代表本站立场。

分享这篇文章:

请关注我们:

发表评论

电子邮件地址不会被公开。 必填项已用*标注