领域驱动设计是一种设计思想,来源于 Eric Evans 的一本书 Domain-Driven Design –Tackling Complexity in the Heart of Software。它倡导通过建立领域模型来驱动软件的设计,也就是从业务知识出发设计业务人员和技术人员都能理解的模型。
统一语言是领域驱动设计的关键概念之一。领域建模的核心难点就在于业务人员和技术人员使用了不同的概念(词汇)来描述他们对软件的理解。如果能使用同样的语言交流,那么复杂软件的设计就变得更加容易。
领域模型就是跨越业务领域作为问题空间和软件解决方案空间的桥梁。
01 使用模型表达业务实体
使用模型来表达业务概念和知识,并指导数据库、API 等软件的进一步设计。模型思维是软件工程中重要的思维之一,它可以简化复杂问题,并从某一个视角出发让人们更加容易理解问题。
模型是对现实世界的简化,例如地图就是一种有效的模型,帮助人们理解道路和街道。
领域模型就是对业务领域简化的模型。
02 识别模型的边界
领域模型集合之间由于业务的相关性可能形成松散的边界,这些边界就是我们分解复杂、大型问题为局部、消息问题的契机。
通过辨析模型的相关性,找到边界就能为软件模块的划分(单体架构)、服务的划分(微服务架构)提供指导。
在领域驱动中,识别出来的边界被称为界限上下文。
03 识别聚合
在数据库的关系模型中,模型为一张网络结构。这样对于代码实现存在困扰,因为难以处理业务的一致性问题。例如,订单、订单项目、商品之间,订单和订单项目的关系更加密切,具有相同的业务生命周期。在领域驱动设计理念中,我们使用聚合代表一组模型的从属关系,其中起到关键带头作用的模型被叫做聚合根,除此之外被叫做实体和值对象。
如果一个聚合只有一个实体,那么聚合根就是这个实体。
04 区分实体和值对象
除了聚合根和实体之外,有一些模型看起来就像一次性的,他们没有自己的 ID 来标明身份,更多的是作为某个实体的一部分,表达几个字段的集合。
例如,在电商系统中,用户设定的常用地址,就是典型的实体,它有自己的 ID 作为身份。但当用户为订单选择地址时,这时的地址只是订单上的若干字段,我们就会把它处理为值对象。
05 操作模型
在领域驱动设计中,为了操作这些模型,又衍生了一些作为“操作者”的对象。
工厂:处理领域模型创建过程的对象,但有时候不是必须的。服务:用来处理某些业务逻辑的对象。例如,为订单计算总价,或者校验一些业务规则。仓储:负责将领域模型持久化到数据库中或从数据库中重建的对象,它的目的是为了隔离领域模型和技术实现之间的差异。
06 对架构分层
为了更好的组织项目中各种各样的对象,我们需要像计算机网络一样分层,来简化复杂项目的复杂性。
在领域驱动设计中,推荐使用四层架构:
- 用户接入层:处理用户接入的数据结构,例如 RESTful API,或者事件。
- 应用层:处理用户的业务操作逻辑,也就是用例,它和用户的使用场景相关。
- 领域层:处理通用的领域逻辑,也就是较为专业的业务逻辑,例如订单价格计算。
- 基础设施层:用来和基础设施适配,例如连接数据库,操作 Redis等。
07 建立领域模型
为了从业务知识中提取出领域模型,人们发明了很多种方法。
事件风暴是一种流行的软件建模方法。它的形式是通过工作坊引导业务人员和技术人员共同创作领域模型,以业务事件为线索,探索系统中可能的领域模型。
除了事件风暴之外,彩色建模也是一种常用的建模方法。它通过颜色区分不同领域模型的特点,来澄清领域模型的职责。彩色建模在过去的很多年里曾非常流行。