这个系列是我学习 DDD 的一些笔记,内容可能有些跳跃,如果觉得看不下去,建议不要继续,因为这真的只是笔记。
软件架构模式演进
B/CS 两层架构
主要还是客户端 UI 和数据库两层,整个系统围绕 DB 驱动设计和开发,设计从数据库和字段的设计开始;
三层架构
- 采用面向对象的设计方法,采用业务接入层,业务逻辑层和数据库层的经典三层架构;
- 容易让系统臃肿,难以扩展和弹性伸缩
分层架构
- 分布式微服务架构
- 应用解耦
- 解决单体应用扩展性和弹性伸缩能力不足的问题
微服务遇到的问题
- 微服务的粒度要多大
- 如何拆分和设计微服务
- 微服务的边界在哪里
其实核心归根为一条:
- 微服务的边界在哪里
DDD
概述
- 核心思想是通过领域驱动设计方法定义领域模型,从而确定业务和应用边界,保证业务模型与代码模型的一致性。
- 熟悉 DDD 设计的工程师发现通过 DDD 设计方法来建立领域模型,划分领域边界再根据这些领域边界从业务视角来划分微服务边界,这样划分出来的微服务的业务和应用边界非常合理,于是很多人就将 DDD 作为微服务设计指导思想;
内涵
- DDD 不是架构,而是一种架构设计方法论
- 通过边界划分,将复杂业务领域简单化,帮助设计出清晰的领域和应用边界
- 包含战略设计和战术设计两个方面
战略设计
- 从业务视角出发,建立业务领域模型,划分领域边界,建立通用语言的限界上下文
- 限界上下文可以作为微服务设计的参考边界
DDD 如何进行战略设计
- 事件风暴是建立领域模型的主要方法,是一个从发散到收敛的过程
- 通常采用用例分析/场景分析/用户旅程分析,尽可能全面不遗漏地分解业务领域,并疏理领域对象之间的关系
- 事件风暴会产生很多实体/命令/事件等领域对象,将这些领域对象从不同纬度进行聚类,形成聚合/限界上下文等边界,建立了领域模型
战术设计
- 从技术视角出发,侧重于领域模型的技术实现,完成软件开发和落地
- 包含:聚合根/实体/值对象/领域服务/应用服务 和 资源库等代码逻辑的设计和实现
概念
领域
- 领域是用来确定范围的,范围即边界;
- 在研究和解决业务问题时,DDD 会按照一定的规则将业务领域进行划分,当领域细分到一定程度后,DDD 会将问题范围限定在特定的边界之内;
- 在这个边界内建立领域模型,进而用代码实现领域模型,解决相应的业务问题;
- 领域越大,相应的业务范围也就越大。
子域
- 领域可以进一步划分为子领域,也就是子域;
- 每个子域对应一个更小的问题域或者更小的业务范围;
核心域
- 决定产品和公司核心竞争力的子域
- 是业务成功的主要因素和公司的核心竞争力
- 没有太多个性化的诉求
通用域
- 同时被多个子域使用的通用功能子域
- 例如认证/权限
- 没有企业特点限制,不需要太多的定制化
支撑域
- 即不包含决定产品和公司核心竞争力的功能
- 也不包含通用功能的子域
- 具有企业特性,并且不具有通用性(例如数据字典等)
子域划分的原因
- 商业模型的不同会导致核心域的认定解决不一样,需要区分领域功能属性和重要性
- 在公司领域细分,建立领域模型和系统建设时,要结合公司战略重点和商业模式,找到核心域,并且重点关注核心域
通用语言
在 DDD 中,因为参与者众多,有领域专家/产品经理/项目经理/架构师/开发经理和测试经理等等,所以产生了两个重要概念:
- 通用语言:定义上下文含义
限界上下文:定义领域边界
具体概念:
- 在事件风暴过程中,通过团队交流达成共识的,能够简单/清晰和准确描述业务含义和规则的语言就是通用语言。
- 设计过程中,我们可以用一些表格来记录事件风暴和微服务设计过程中产生的领域对象和属性。
限界上下文
- 限界:领域的边界
- 上下文::语义环境
- 用来封装通用语言和领域对象,提供上下文环境,保证在领域之内的一些术语/业务相关对象等又一个切确的含义,没有二义性
- 通过将限界上下文内的领域模型映射到微服务,就完成了从问题域到软件的解决方案‘
实体
实体和值对象都是领域模型中的领域对象,也是微服务底层最基础的对象,对于 DDD 从战略层面到战术层面有着重要的作用。
- 实体是领域模型中的核心对象,一般有着唯一的持久标示,实体注重的是唯一性和延续性,这个唯一标示将伴随着系统的生命周期甚至超出该系统的生命周期;
- 实体在代码中就是一个 Class,一般采用充血模型,也就是实体相关的业务都写在实体的方法中,跨越多个实体的业务则在领域服务中实现;
值对象
- 值对象则是实体一系列相关属性的集合,可以是一个属性,也可以包含多个属性;
- 值对象本质上就是一个集,相对于实体来说没有唯一的标示
- 值对象是不可变的,这使得它天然适合被重用
- DDD 提供从领域模型设计出发,而不是先设计数据模型,值对象的诞生,在一定程度上,和实体是互补的。
对比
- 实体在乎唯一性和延续性,不在乎属性的表化;而值对象着重描述性,对属性的变化很敏感,属性变化之后,此值对象就不是彼值对象了;
- 战略上的思考框架稳定不变,战术上的模型设计(数据模型)却灵活多变。实体和值都可以根据系统业务关注点的不同而变换位置(实体 <-> 值对象)
聚合和聚合根
- 聚合就是实体的集合,是领域模型中最底层的边界,可以作为拆分微服务的最小单位;
- 在 DDD 中,根据限界上下文将相关的若干实体组合成一个聚合,保证实体之间的数据一致性;
- 聚合内封装不变的业务规则,各实体和值对象按照统一的业务规则运行,实现对象数据的一致性;
- 而聚合根就是关联多个实体的实体,也具有聚合根 ID,本身和实体差不多;
设计聚合的一些原则
- 在一致性边界内建模真正的不变条件(高内聚)
- 设计小聚合(聚合要小,减小复杂度)
- 通过唯一标示引用其他聚合(减小聚合耦合度)
- 在边界之外使用最终一致性(聚合之间更改异步进行)
- 通过应用层实现跨聚合的服务调用(聚合可以作为拆分微服务的最小单位,微服务之间通过应用层调用)
DDD 和 微服务之间的关系
- DDD 是一种架构设计方法
- 微服务是一种架构风格
- 两者本质上都是追求高响应力,从业务视角去分离应用系统建立复杂度的手段
- 两者都强调根据业务发展,持续调整现有架构,以保持架构和代码的生命力,即演进式架构
DDD 主要关注
- 从业务领域视角划分领域边界,构建通用语言进行高效沟通、
- 通过业务抽象,建立领域模型,维持业务和代码的逻辑一致性
微服务主要关注
- 运行时的进程间通信,容错和故障隔离
- 实现去中心化数据管理和去中心化服务治理
- 关注微服务的独立开发/测试和构建/部署