在这个用户场景中的名词,如Consumer、Order、Restaurant和CreditCard,暗示了这些类都是需要的。
同样,Accept Order用户故事也可以分解为多个场景,如下:
这个场景暗示需要Courier类和Delivery类。在经过几次迭代分析之后,结果显然就是这个领域模型应该包括一些类,如MenuItem和Address等。图3显示了核心类的类图。
图3 FTGO领域模型中的关键类
每一个类的作用如下:
- Consumer:下订单的用户。
- Order:用户下的订单,它用来描述订单并跟踪状态。
- OrderLineItem:Order中的一个条目。
- DeliveryInfo:送餐的时间和地址。
- Restaurant:为用户准备生产订单的餐馆,同时也要发起送货。
- MenuItem:餐馆菜单上的一个条目。
- Courier:送餐员负责把订单送到用户手里。可跟踪送餐员的可用性和他们的位置。
- Address:Consumer或Restaurant的地址。
- Location:Courier当前的位置,用经纬度表示。
类似上面这张类图描述了应用程序架构的一个方面。但如果没有对应的场景,这个图也就是仅仅好看而已,并不实用。下一步开始定义对应架构场景的系统操作。
定义系统操作
当定义了抽象的领域模型之后,接下来就要识别系统必须处理的各种请求。我们并不讨论具体的用户界面,但是你能够想象在每一个用户场景下,前端的用户界面向后端的业务逻辑发出请求,后端的业务逻辑进行数据的获取和处理。FTGO是一个Web应用,这意味着它的大部分请求都是基于HTTP的。但也有可能一些客户端会使用消息。相比绑定到具体的通信协议,使用抽象的词汇来描述跟系统操作有关的请求更为合理。
有以下两种类型的系统操作。
- 指令型:创建、更新或删除数据的系统操作。
- 查询型:查询和读取数据的系统操作。
从根本上说,这些系统操作都会对应到具体的REST、RPC或消息端口。但现阶段我们不必在意这些实现细节。让我们先开始识别一些指令。
识别系统指令的切入点是分析用户故事和场景中的动词。例如Place Order用户故事,它非常明确地告诉架构师,这个系统必须提供一个Create Order操作。很多用户故事都会直接对应或映射为系统命令。表1列出了一些关键的系统命令。
命令规范定义了命令对应的参数、返回值和领域模型类的行为。行为规范中包括前置条件(即当这个操作被调用时必须满足的条件)和后置条件(即这个操作被调用后必须满足的条件)。例如,以下就是createOrder()系统操作的规范。
前置条件对应着Place Order用户场景中的givens,后置条件对应着场景中的Then。当系统操作被调用时,它会检查前置条件,执行操作来完成和满足后置条件。
下面是acceptOrder()的系统操作规范: