TDD 不能做什么?
- 不能窥探方法内是如何实现的,例如对于一个排序算法,只能验证结果是否符合预期,不能验证使用了哪种算法(冒泡、插入等)
- 不能求解自己不会的问题,例如:
- 自己没有思路的算法题
- 破解世界七大数学难题获得高额奖金
TDD 是一种架构技术
- 从“驱动”的角度讲,TDD 并不是一种编码技术,它无法驱动你写出你不会实现的代码。
- TDD 是一种架构技术,它能通过测试与重构,驱动单元的划分以及功能的归属,因而是一种更为落地的架构软件的方式。
- 在 TDD 中,重构是和测试一样重要的驱动力,驱使我们得到更好的架构和更清晰的代码结构。
常用的重构手法
以下操作应该被看作修改代码的基本功,而不是重构 如果无法借助自动化重构工具高效修改代码,那么 TDD 带来的效率将会大打折扣。而无法支持这几个核心手法的 IDE,也不足以支撑 TDD 的实施。
语义化的查找替换(Semantic Find and Replace)
- 在不破坏现在代码结构的前提下,完成查找替换
- 提取方法(Extract Method)
- 内联方法(Inline Method)
通过提取 / 合并单元进行重架构(Extract and Merge Units)
- 在提取方法的基础上,我们可以进一步将提取出的行为从当前对象中分离出去,也就是提取对象(Extract Object)
- 一旦提取出对象,我们就能通过类内字段(Field)、参数(Parameter)等方式,不再直接引用当前对象上下文,从而将其与当前对象上下文分离
- 对应地,我们可以使用的重构手法有引入字段(Introduce Field)、引入参数(Introduce Parameter)等
使用多态替换条件
- 通过策略模式消除 if else
重构到模式(Refactoring to Patterns)
- 将架构上的坏味道替换为设计模式(Design Pattern)。
- 这是一种更有效的架构软件的方法,用公认的好设计(模式)替换了公认的不好的设计(坏味道),还能满足功能的需求,必然能是更好的架构(而不用虚无缥缈地归结于“品味”或“经验”)。
- 对于 TDD,行业中存在这样一种困惑:从功能测试出发,逐步完成软件开发,这或许没问题。但架构怎么办?
- 实际上,红 / 绿 / 重构循环中的重构就是解决架构问题的。
- 只不过架构并不是预先设计的(Upfront Design),而是在完成功能的前提下演进而来的,因而也称演进式设计(Evlutionary Design)。
- 通过重构到模式演进式地获得架构,是一种实效主义编码架构风格(Pragmatic Coding Architect)。
⭐️⭐️⭐️⭐️⭐️ Joshua Kerievsky 在 2004 年写过一本书,《Refactoring to Patterns》(中文版《重构与模式》)。这本书的价值远被低估了,是关于软件架构非常重要的著作!
最晚尽责时刻(Last Responsible Moment,LRM)
- 其在信息不足的情况下做决定,不如延迟到信息更多,或是不得不做出决策的时机再决策。
- 这种策略的重点在于,在保持决策有效性的前提下,尽可能地推迟决策时间
- 在架构愿景不清晰时,能让我们不必花费时间进行空对空的讨论,可以尽早开始实现功能,再通过重构从可工作的软件(Working Software)中提取架构。
- 这种方式也被称作 TDD 的经典学派(Classic School)或芝加哥学派(Chicago School)
伦敦学派(London School)
- 适用于架构愿景已经比较清晰的情况
- 一种利用架构愿景分割功能上下文,然后再进入经典模式的 TDD 方法
- 对于复杂的场景,可以极大简化构造测试的时间
经典学派和伦敦学派
- 都是 TDD 中都需要掌握的基本功
- 在功能上下文内,以经典学派为主
- 而跨功能上下文时,可以使用伦敦学派对不同的功能上下文进行隔离