# TDD流程和优势
# TDD的流程
如何描述TDD的流程呢?在徐昊的课程中给了一个比较清晰的答案:
- 首先将需求分解成功能点,也就是将需求转化为一系列可验证的里程碑点
- 如果已经存在架构或架构愿景,则依据架构中定义的组件与交互,将功能点分解成不同的功能上下文
- 如果不存在架构愿景,则可以将功能点作为功能上下文
- 将功能点按照功能上下文分解为任务项,进一步将可验证的里程碑点,分解为功能上下文中的可验证的功能项
- 将任务转化为自动化测试,进入红、绿、重构循环,驱动功能上下文内的功能实现
- 如果重构设计功能上下文的重新划分,提取、合并组件可以视作对于架构的重构与梳理,可以利用这种手法调整后续功能点钟对于功能上下文以及任务项的划分
- 如此往复循环此过程,直到所有功能完成
任务列表中的任务项源自两层分解,一层是源自对业务理解的功能点的分解,另一层是源自架构愿景的功能上下文分解。功能点分解帮助我们形成可验证的里程碑点,这些里程碑点可以看作由可工作的软件构成的进度度量,功能上下文分解帮助我们找到正确的单元,直到我们保持良好的软件架构。如果功能点分解错误,那么就得不到功能正确的软件,如果功能上下文分解错误,那么就得不到架构良好的软件。
# TDD的优势
使用TDD开发软件对人的要求,与其他所有软件工程方法对人的要求大致是一样的,这个要求就是理解需求、明白架构。在这几方面TDD有如下几点工程管理上的优势:
- 理解需求等于可以针对功能点写出测试。换句话说,写不出测试就是不理解需求,不理解需求也不推荐开发功能。在不理解需求的前提下开发功能点,只能带来负的进度,从工程管理的角度上看,判断一个人是否理解需求的成本极高,这个成本就是我们常见的各种拉群,各种拉通会议,各种反复宣讲确认,这个过程经常是鸡同鸭讲,不断消磨团队的精力与斗志。TDD先写测试,后写生产代码的实践,实际上本质就是要求先理解需求,再开发。TDD对于什么叫理解了需求,也有清晰的要求,简单来说就是能写出这个功能点的测试就是理解了需求。从工程管理的角度来说,看看测试就能判断一个人对需求的理解程度。
- 不写测试从某种程度上来说就是没理解清楚需求。没理解需求就去写测试,其实就是做的无用功,如果整个团队都写不出测试,那么说明这个需求无法通过可管控的方式进行交付。可管控意味着需求在实现的层面上可以被执行,需求对应的结果是可以确定的。在无法通过可管控的形式进行交付,意味着不确定这个需求在实现层面是否可被执行,需要进入探索模式。在不确定的情况下,要追求低成本及时止损。探索模式需要在给定的时间范围内尝试,超出这个范围仍未解决就要将其视为项目风险,通常已经形成阻塞、延期或者大量返工的时候,才能发现根本原因是不能确定一个项目的实现方式。
- 所有软件从业者都认为架构是重要的,但很少有人理解架构是如何发挥作用的。架构并不是纸面上的框图,而是约定了构成系统软件系统的组件,以及组件之间的交互方式,也就是说架构是组件职责划分的依据以及组件的交互模式。比如MVC架构,表明系统组件按职责分成三种:管理数据的模型(model)、负责展示的视图(view),以及处理事件交互逻辑的控制器(controller)。他们的交互模式为:视图渲染模型中的数据,视图中触发的事件则交由控制器处理,控制器可以通过修改某些来更新视图。架构必须要成为全体人员的共识,才能真正发货作用,否则架构就是一句空话。TDD可以通过功能上下文和任务项拆分的情况,判断成员是否理解了架构。如果团队成员形成了架构共识,那么对于相同的功能点,团队所有成员拆分的功能上下文应该也会相同。
- 架构愿景很难再一开始就想的尽善尽美,随着需求的发展,总会出现以当前架构愿景不容易实现的需求。如果出现不当的职责划分和别扭的组件交互,这只会加速架构的腐化。TDD可以通过功能上下文及任务拆分的情况判断当前架构能否实现当前需求。TDD要求先写测试,实际上是以可工作软件的形态,验证对需求的理解,而任务分解则是在确定单元颗粒度的过程中验证对于架构的共识。