订单系统建模思考

本文是对于订单建模的一点思考整理,里面应用一些对领域驱动设计的思考,默认读者对于领域概念有一些基本了解。

基本元素

交易最早是通过以物易物的方式来交换,后面产生等价通用物品即货币。交易上下文领域对象包括:

1
2
3
4
顾客 Consumer
货 Goods
货币 Currency
商家 Merchant

对于交易一句话描述就是,顾客在商家那里通过等价货币购换取了货物。

上面描述的四种领域对象作为领域实体,每一种领域实体通过 key 组合来确定实体的唯一性,ext 是值对象,用来描述实体。对应的实体描述如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Consumer:
{
"key": "USER_ID",
"ext": { }
}
Goods
{
"key": "SKU_ID",
"amount": 100,
"ext": { }
}
Currency
{
"type": "CNY|VIRTUAL_COIN",
"amount": 100
}
Merchant
{
"key": "yO7LmcWjqsJz1N5j",
"ext": { }
}

状态事件抽象

订单状态变更命令通用流程抽象如下图,一个领域命令被触发后,首先进行状态变更前的资格校验事件回调,所有校验方均校验通过后方可进行后续处理,将交易修改为对应状态,状态修改后发布对应的状态变更事件,经由事件总线发布事件,所有监听方进行后续处理。一个领域命令执行结束。此流程可以套用到任何状态变更命令。

状态变化通过领域命令发起 command,首先进行 BeforeOperating 操作前的处理,每一个命令都定义了事件的资格校验 qualification 接口,实现接口的可能是子域内处理,比如下单的库存校验,优惠校验等,也可能是具体业务的校验,需要实现资格校验接口。通过后进行事务性的状态变更操作 updateState,操作后进行状态变更后 AfterOperating 的事件发布,由各个业务监听进行后续处理。这样处理方便业务逻辑解耦,订单子域专注于订单状态的管理。

对应到订单系统,对于订单状态和物流状态节点以及领域事件如下表示:

订单状态

  • 已创建 CREATE(COMMIT)
  • 已支付 PAID
  • 已退款 REFUND(REFUNDING)
  • 已关闭 CLOSED

物流状态

  • 待发货 WAITING
  • 已发货 DELIVERED
  • 已收货 RECEIVED
  • 已退货 RETURN

领域命令

  • 创建订单 createOrder
  • 超时关单 closeOrder
  • 支付订单 payOrder
  • 申请退款 refundOrder
  • 订单履约 deliverOrder
  • 商家发货 deliverGoods
  • 用户收货 receiveGoods
  • 用户退货 returnGoods

子域拆分

订单子域的拆分也是业务职责的拆分,订单管理和物流管理是相对独立的两个模块,订单主要关注收款履约退款,物流主要关注用户的收退货状态,所以整个交易域的订单和物流会被拆分成两个子域。

订单事件举例

订单创建命令,首先对注册的条件回调方进行回调,确认当前的购买资格,通过后进行事务性的订单创建,创建后进行订单已创建的事件发布,所有监听方接收到消息后进行分析处理。