一、微服务设计&选择DDD的缘由
1. 架构演进
1.1. 单机架构
①面向过程设计
②客户端UI+数据库双层
③C/S架构
④数据库驱动设计和开发
1.2. 集中式架构
①面向对象设计
②业务接入层、业务逻辑层和数据层
③经典三层或SOA架构
1.3. 分布式微服务架构
①解耦
②解决设计开发独立分裂造成的信息丢失
③解决单机和集中式架构无法满足快速响应需求和业务变化
2. 微服务设计和拆分
困境: 拆分过度,导致项目复杂度高,无法上线和维护
根本原因:业务和微服务的边界不清楚
3. DDD
3.1. 概述
核心思想
通过领域驱动设计方法定义领域模型,确定业务和应用边界,保证业务模型和代码模型一致性
什么是DDD?
DDD是一种处理高度复杂领域的设计思想,是一种架构设计方法论,它试图分离技术实现的复杂性,围绕业务概念构建领域模型来控制业务复杂性,以解决软件难以理解难以演进的问题。
3.2. 战略设计和战术设计
3.2.1. 什么是战略设计和战术设计
战略设计
主要从业务视角出发,建立业务领域模型,划分领域边界,建立通用语言的限界上下文,限界上下文可以作为微服务设计的参考边界。
战术设计
从技术视角出发,侧重于领域模型的技术实现,完成软件开发和落地,包括:聚合根、实体、值对象、领域服务、应用服务和资源库等代码逻辑的设计和实现。
3.2.2. 战略设计流程
事件风暴
一种建立领域模型的主要方法,一种由发散到收敛的过程。
先发散:通常采用用例分析(了解谁会做什么),场景分析(了解在哪些场景下活动),和用户旅程分析(了解用户使用的过程),尽可能全面不遗漏地分解业务领域,并梳理领域对象之间的关系。
再收敛:事件风暴会产生很多实体,命令,事件等领域对象,对这些对象从不同的维度进行聚合,形成如聚合、限界上下文等边界,从而建立领域模型。
(说人话就是,先把一堆业务要做的事罗列出来,然后再分组、聚合在一起,形成要处理的领域对象)
划定领域模型和微服务边界的三步
- 在事件风暴中梳理业务过程中的用户操作、事件以及外部依赖关系等,根据这些要素梳理出领域实体等领域对象。
- 根据领域实体之间的业务关联性,将业务紧密相关的实体进行组合形成聚合,同时确定聚合中的聚合根、值对象和实体。聚合之间的边界是第一层边界
- 根据业务及语义边界等因素,将一个或者多个聚合划定在一个限界上下文内,形成领域模型。限界上下文之间的边界是第二层边界
4. DDD与微服务
各自关系
DDD 是一种架构设计方法,微服务是一种架构风格,两者从本质上都是为了追求高响应力,而从业务视角去分离应用系统建设复杂度的手段。
相同点
两者都强调从业务出发,其核心要义是强调根据业务发展,合理划分领域边界,持续调整现有架构,优化现有代码,以保持架构和代码的生命力,也就是我们常说的演进式架构。
不同之处与主要关注
DDD 主要关注:从业务领域视角划分领域边界,构建通用语言进行高效沟通,通过业务抽象,建立领域模型,维持业务和代码的逻辑一致性。
微服务主要关注:运行时的进程间通信、容错和故障隔离,实现去中心化数据管理和去中心化服务治理,关注微服务的独立开发、测试、构建和部署。
二、领域、子域、核心域、通用域和支撑域
1. 理解领域和子域
领域:边界内要解决的业务问题域
子域:由领域划分出来的,更小的问题域或业务范围
领域建模和微服务建设的核心思想
将问题逐步分解,降低业务理解和系统实现的复杂度。
2. 核心域、通用域、支撑域
本质:子域根据自身重要性和功能属性进行的划分
2.1.1.1. 核心域
决定产品和项目核心竞争力的子域,是业务成功的主要因素和公司的核心竞争力。
通用域
没有太多个性化需求,同时被多个子域使用的通用功能子域。
支撑域
必需的但既不包含决定产品和公司核心竞争力的功能,也不包含通用功能的子域。
2.1. 核心域、通用域和支撑域划分的主要目的
主要目标
通过领域划分,区分不同子域在项目内的不同功能属性和重要性,从而项目可对不同子域采取不同的资源投入和建设策略,其关注度也会不一样。
桃树例
桃树生长在公园里,在园丁的眼里,他喜欢的是“人面桃花相映红”的阳春三月,这时花就是桃树的核心域。但如果这棵桃树生长在果园里,对果农来说,他则是希望在丰收的季节收获硕果累累的桃子,这时果实就是桃树的核心域。在不同的场景下,不同的人对桃树核心域的理解是不同的,因此对桃树的处理方式也会不一样。园丁更关注桃树花期的营养,而果农则更关注桃树落果期的营养,有时为了保证果实的营养供给,还会裁剪掉疯长的茎和叶(通用域或支撑域)。
三、通用语言和限界上下文
1. 什么是通用语言?
概念
在事件风暴过程中,通过团队交流达成共识的,能够简单、清晰、准确描述业务涵义和规则的语言。
作用
解决交流障碍这个问题,使领域专家和开发人员能够协同合作,从而确保业务需求的正确表达。
1.1. 通用语言域用例场景映射
通用语言贯穿 DDD 的整个设计过程。
通用语言中的名词可以给领域对象命名,如商品、订单等,对应实体对象;而动词则表示一个动作或事件,如商品已下单、订单已付款等,对应领域事件或者命令。
从通用语言到代码落地的流程
- 在事件风暴的过程中,领域专家会和设计、开发人员一起建立领域模型,在领域建模的过程中会形成通用的业务术语和用户故事。事件风暴也是一个项目团队统一语言的过程。
- 通过用户故事分析会形成一个个的领域对象,这些领域对象对应领域模型的业务对象,每一个业务对象和领域对象都有通用的名词术语,并且一一映射。
- 微服务代码模型来源于领域模型,每个代码模型的代码对象跟领域对象一一对应。
🏷️Tips
设计过程中我们可以用一些表格,来记录事件风暴和微服务设计过程中产生的领域对象及其属性。
2. 什么是限界上下文
限界和上下文
限界就是领域的边界。上下文则是语义环境
综合定义限界上下文
用来封装通用语言和领域对象,提供上下文环境,保证在领域之内的一些术语、业务相关对象等(通用语言)有一个确切的含义,没有二义性。
3. 进一步理解
由于业务的复杂性,我们需要借助限界上下文来细分领域,从而使得通用语言定义的业务在一定上下文场景中没有歧异。领域边界就是通过限界上下文来定义的。
两个例子
例1. 在一个明媚的早晨,孩子起床问妈妈:“今天应该穿几件衣服呀?”妈妈回答:“能穿多少就穿多少!”
例2. 电商领域的商品在不同的阶段有不同的术语,在销售阶段是商品,而在运输阶段则变成了货物。
在不同的场景(上下文环境)下,具体的几件衣服和对象到底叫商品还是货物(业务)是不同的,这就是限界上下文的作用。
4. 限界上下文和微服务
理论上限界上下文就是微服务的边界。将限界上下文内的领域模型映射到微服务,就完成了从问题域到软件的解决方案。
限界上下文是微服务设计和拆分的主要依据。在领域模型中,如果不考虑技术异构、团队沟通等其它外部因素,一个限界上下文理论上就可以设计为一个微服务。