🌈🌈🌈🌈🌈🌈🌈🌈
欢迎关注公众号(通过文章导读关注:【11来了】),及时收到 AI 前沿项目工具及新技术的推送!在我后台回复 「资料」 可领取
编程高频电子书!
在我后台回复「面试」可领取硬核面试笔记!文章导读地址:点击查看文章导读!
感谢你的关注!
🍁🍁🍁🍁🍁🍁🍁🍁
基于电商履约场景的 DDD 实战
DDD 业务建模流程
对于 DDD 开发项目来说,分为 3 个部分:战略设计、战术设计、代码开发
- 战略设计:划分有界上下文、确定子域类型、上下文映射,把上下文里的通用语言制定一套规范出来,后续开发根据这个规范来完成
- 战术设计:在战略设计的基础上,进一步细化领域模型,包含了上下文中有哪些类,类之间如何配合,战术设计中包含了聚合、实体、值对象、仓储、领域服务、业务组件、领域事件、命令这些更加具体的东西
- 代码开发
接下来先说一下从战略设计、战术设计、代码开发这三个方面来对 DDD 业务建模整体的流程进行分析讲解,从 0 到 1 带你完成一个 DDD 项目
第一部分:战略设计
在战略设计中,主要进行的工作就是:划分有界上下文、确定子域类型、上下文映射,把上下文里的通用语言制定一套规范
接下来说一下这几个名词到底代表什么意思
- 划分有界上下文:将各个业务模块的责任划分清楚,各个模块只负责自己的任务,达到高内聚的效果,比如仓储服务负责发货、商品校验一些任务,而履约服务负责生成履约单以及使用仓储服务所提供的一些功能,将各自负责的任务写到各自的上下文中去
- 子域:一般来说和有界上下文是一一对应的,比如履约有界上下文就对应了履约子域、订单上下文就对应了订单子域
- **上下文之间的映射:**映射指的是各个子域之间如何进行交互,以及子域之间的关系(比如生产者消费者映射关系、发布订阅映射关系等)
- **通用语言的制定:**在不同的上下文中,可能有些东西具体的细节定义不同,但是指的是同一个东西,因此需要指定统一的通用语言。这里举个例子,比如对于订单 Order 来说,在订单上下文中是订单的含义,而在履约上下文中,则是履约单的含义,但是他们指的都是同一个东西,因此需要通用语言的规范,各个上下文按照规范去做
至此,战略设计中设计的名词,我们就已经了解了,接下来开始 DDD 业务建模的第一部分:战略设计
战略设计:划分有界上下文
首先,对当前业务模块划分出来它的有界上下文
这里使用事件风暴会议来找出来履约系统的有界上下文
如何使用事件风暴会议来划分履约系统的有界上下文?
事件风暴会议是一种协作式的工作方法,通过可视化的方式,让团队成员参与到业务流程的分析和设计中,从而更好的定义业务需求
使用事件风暴会议通过五个步骤划分履约有界上下文:
- 召集会议:程序员、用户、产品经理、管理者大家一起开会,将所有履约相关的事件全部说出来
- 梳理事件:将履约相关的事件按照时间线进行排列
- 梳理履约相关的用户界面和命令:对履约相关的事件,判断是否有用户界面,如果有的话,用户在界面会发出一个命令(点击按钮、提交表单),通过命令驱动各个事件的执行
- 串联成完成流程:把用户界面 --> 命令 —> 事件,按照时间先后顺序串联起来,形成完整的流程
- 划分履约上下文:在完整的履约流程中,找出来哪些事情是履约上下文要解决的,进行上下文划分
方法论说完之后,开始对履约有界上下文划分进行实操:
- 第一步:召开事件风暴会议
- 第二步:根据时间梳理事件
履约中的事件执行流程为:
- 第三步:梳理用户界面和命令
在履约环节中,主要就是预分仓之后,进行人工审核的时候,需要工作人员参与一下
先通过对履约单进行风控拦截,被风控拦截到的有风险的订单(刷单、黄牛)会交给人工审核:审核通过、取消订单、重分仓
- 第四步:串联起来形成完整流程
也就是上图中的流程
- 第五步:找出履约上下文需要做的事件
对于上图的流程,下库房之后的拣货、复核、商品打包、物流配送的一些操作,都不是履约需要负责的事件了,这些都是仓储所需要负责的
战略设计:确定子域
划分好有界上下文之后,接下来需要将每个有界上下文跟子域一一对应起来
每个子域都有自己的类型:
- 核心子域:具备核心功能的子域,比如电商系统中的商品子域、订单子域、支付子域、履约子域、会员子域
- 支持子域:提供支持作用的子域,也就是为了支持核心子域的功能而出现的,比如仓储子域、财务子域、报表子域
- 通用子域:不是公司自己开发的,使用第三方通用的系统,比如第三方支付平台、第三方物流平台都是通用子域
那么在履约中所设计的上下文都有:订单上下文、仓储上下文、风控上下文、物流上下文,他们和子域的对应关系,以及对应的子域类型如下图
战略设计:上下文之间的映射
这里的映射指的就是各个有界上下文之间的交互关系
映射有以下几种:
- separate way:没有交互关系,很少见
cumtomer-supplier:消费者、供应者关系(cs),互相之间可以商量接口的定义,一般同一个项目组中的各个小团队之间可以使用这种映射,距离比较近,商量起来很方便publish-subscribe:发布、订阅关系(ps),一方发布一个事件,另一方监听这个事件并进行处理anti corruption layer:防腐层(acl),acl 映射关系一般是和其他映射关系结合使用的,比如和 ps、cs 结合使用,以 ps 为例,发布者和订阅者刚开始约定了 8 个字段,但是后来可能一方要改变某些字段,如果修改两方的代码导致对代码入侵性太强了,可以加入防腐层,将双方的字段进行一个转化和适配conformist:双方没商量的映射关系,比如一方给另一方提供接口,这两方在不同的部门中,提供接口的一方按照自己的计划进行迭代升级,如果你使用的话,必须遵守提供接口方的规定,没有商量的余地- partnership:强耦合、合作的映射关系,常用于中小型系统中,各个子域之间的耦合度比较高,一起进行开发、修改、上线,很少见
open host service + published language:OHS+PL 映射关系,指的一般都是第三方的支付平台或第三方物流平台等等,他们开放出来平台接口,一般是开放出 HTTP 接口供我们去调用,这就是 OHS + PL 映射关系- shared kernel:共享内核映射关系,两个有界上下文之间,共享一个数据模型,两个团队一起维护,不过现在很少见
上边的几种映射关系,只有 separate way、partnership、shared kernel 不常见,其他的都是比较常用的
接下来就开始分析履约相关的一些上下文之间的映射关系了:
订单和履约的映射关系:ps 关系,订单发布事件,履约收到事件,进行处理
履约和仓储的映射关系:conformist 关系,仓储对外提供接口,履约按照指定的接口规范调用即可,仓储作为上游提供服务,履约作为下游调用
履约和物流:conformist 关系,物流团队也是对外提供接口,履约按照指定的接口规范调用即可,物流作为上游提供服务,履约作为下游调用
物流和第三方物流:acl + OHS + PL 关系,通过 acl 防腐层进行接口之间的数据的适配,第三方物流对外提供指定的 HTTP 接口,物流按照指定格式调用即可
战略设计:通用语言的制定
这里还是再说一下为什么要指定通用语言吧
就比如说对于 Order 订单来说
- 在订单上下文中,有着自己对订单的理解,自己定义 Order 的细节
- 而在履约上下文中,也有着自己对订单的理解,自己定义履约中 Order 的细节
那么他们说的其实都是一个东西,但是在不同的上下文中,对于同样的 Order 的理解不同,以及具体的定义细节也是不同的,因此需要有统一的一套通用语言,在每一个上下文中,所有的名词、命名规范、业务操作、业务事件、业务语义都按照统一的一套规则和规范去做
至此,DDD 业务建模中的战略设计,也就是理论部分就完成了,接下来说一下战术设计,即具体的细节,该作何来做