开篇词|学好了DDD,你能做什么?
- 应用DDD的两大关键:
-
- 理解ddd的核心思想,和他与微服务、中台之间的关系.
其中中台是业务模型,微服务是业务模型的系统落地,DDD作为一种设计思想,它可以同时指导中台业务 建模和微服务设计,它们之间就是这样的⼀个铁三⻆关系。
DDD强调领域模型和微服务设计的⼀体性,先有领域模型然后才有微服务,⽽不是脱离领域模型来谈微服务设计。 - 通过战略设计,建立领域模型,确定微服务边界
- 然后通过战术设计,将领域模型转转向微服务的设计与落地,最终打造一个边界清晰,可持续演进的微服务应用架构
- 理解ddd的核心思想,和他与微服务、中台之间的关系.
基础篇

1、领域驱动设计:微服务设计为什么要选择DDD?
软件架构模式的演进

- 单机架构:通常是C/S架构,围绕数据库进行开发,面向过程
- 三层架构:容易使系统变得臃肿,可拓展性和弹性伸缩性较差
- 微服架构:能够很好的实现应用间的解耦
微服务设计和拆分的困境
- 作者认为**微服务拆分困境产⽣的根本原因就是不知道业务或者微服务的边界到底在什么地⽅。**这会导致出现微服拆分过度,拆分错误,无法达到既定的目标,例如提高可扩展性,敏捷开发等
- DDD核⼼思想是通过领域驱动设计⽅法定义领域模型,从⽽确定业务和应⽤边界,保证业务模型与代码模型的⼀致性。
- DDD实际上直到直到Martin Fowler提出微服务架构,DDD才 真正迎来了⾃⼰的时代,可以使用DDD划分领域模型,划分领域边界,再跟据这些边界来切分微服务,从而实现高内聚,低耦合
为什么DDD适合微服务
DDD是⼀种处理⾼度复杂领域的设计思想,它试图分离技术实现的复杂性,并围绕业务概念构建领域模型来 控制业务的复杂性,以解决软件难以理解,难以演进的问题。DDD不是架构,⽽是⼀种架构设计⽅法论,它通过边界划分将复杂业务领域简单化,帮我们设计出清晰的领域和应⽤边界,可以很容易地实现架构演进。
个人总结:DDD的核心作用之一是 分离技术实现的复杂性,相较于数据驱动,领域驱动描述了具体业务行为,以业务为核心,顺着业务的脉络就能理清代码,反过来也一样
- DDD包括战略设计和战术设计
-
- 战略设计主要从业务视⻆出发,建⽴业务领域模型(领域模型可以用来划分微服务),划分领域边界,建⽴通⽤语⾔的限界上下⽂,限界上下 ⽂可以作为微服务设计的参考边界。
- 战术设计则从技术视⻆出发,侧重于领域模型的技术实现,完成软件开发和落地,包括:聚合根、实体、值 对象、领域服务、应⽤服务和资源库等代码逻辑的设计和实现。
- 战略设计:会建立领域模型,事件⻛暴是建⽴领域模型的主 要⽅法,它是⼀个从发散到收敛的过程。
-
- 它通常采⽤⽤例分析、场景分析和⽤⼾旅程分析,尽可能全⾯不遗 漏地分解业务领域,并梳理领域对象之间的关系,这是⼀个发散的过程。
- 事件⻛暴过程会产⽣很多的实体、 命令、事件等领域对象,我们将这些领域对象从不同的维度进⾏聚类,形成如聚合、限界上下⽂等边界,建 ⽴领域模型,这就是⼀个收敛的过程
- 三步划定领域模型和微服务边界
-
- 第⼀步:在事件⻛暴中梳理业务过程中的⽤⼾操作、事件以及外部依赖关系等,根据这些要素梳理出领域实 体等领域对象。
- 第⼆步:根据领域实体之间的业务关联性,将业务紧密相关的实体进⾏组合形成聚合,同时确定聚合中的聚合根、值对象和实体。在上图⾥,聚合之间的边界是第⼀层边界,它们在同⼀个微服务实例中运⾏,这个边界是逻辑边界,所以⽤虚线表⽰。
- 第三步:根据业务及语义边界等因素,将⼀个或者多个聚合划定在⼀个限界上下⽂内,形成领域模型。在这个图⾥,限界上下⽂之间的边界是第⼆层边界,这⼀层边界可能就是未来微服务的边界 ,不同限界上下⽂内的领域逻辑被隔离在不同的微服务实例中运⾏,物理上相互隔离,所以是物理边界,边界之间⽤实线来表⽰。
- 上面两层边界的确定非常重要,这个过程完成后 领域模型的设计就算是完成了,也基本确定了应用端的服务边界,从业务模型向微服务端落地时 就是战略设计向战术设计的实施过程,
我们会将领域模型中的 领域对象与代码模型中的代码对象建⽴映射关系,将业务架构和系统架构进⾏绑定。当我们去响应业务变化 调整业务架构和领域模型时,系统架构也会同时发⽣调整,并同步建⽴新的映射关系。
DDD与微服务的关系
- DDD是⼀种架构设计⽅法,微服务是⼀种架构⻛格,两者从本质上都是为了追求⾼响应⼒,⽽从业务视⻆去分离应⽤系统建设复杂度的⼿段。
- 两者都强调从业务出发,其核⼼要义是强调根据业务发展,合理划分领域边界,持续调整现有架构,优化现有代码,以保持架构和代码的⽣命⼒,也就是我们常说的演进式架构。
- DDD主要关注:从业务领域视⻆划分领域边界,构建通⽤语⾔进⾏⾼效沟通,通过业务抽象,建⽴领域模型,维持业务和代码的逻辑⼀致性。
- 微服务主要关注:运⾏时的进程间通信、容错和故障隔离,实现去中⼼化数据管理和去中⼼化服务治理,关注微服务的独⽴开发、测试、构建和部署。
总结:从上可以看出DDD中的战略设计与微服划分是高度相关的,而在以往接触过的微服项目中 都是以数据驱动作为底层开发思想,可以通过这一点去联系和描述DDD的用途,特别是在传统开发的项目中
DDD可以带来的收益
- DDD是⼀套完整⽽系统的设计⽅法,它能带给你从战略设计到战术设计的标准设计过程,使得你的设计思路能够更加清晰,设计过程更加规范。
- DDD善于处理与领域相关的拥有⾼复杂度业务的产品开发,通过它可以建⽴⼀个核⼼⽽稳定的领域模型,有利于领域知识的传递与传承。
- DDD强调团队与领域专家的合作,能够帮助你的团队建⽴⼀个沟通良好的氛围,构建⼀致的架构体系。
- DDD的设计思想、原则与模式有助于提⾼你的架构设计能⼒。
- ⽆论是在新项⽬中设计微服务,还是将系统从单体架构演进到微服务,都可以遵循DDD的架构原则。
- DDD不仅适⽤于微服务,也适⽤于传统的单体应⽤。
2、领域、子域、核心域、通用域和支撑域
领域和子域
-
DDD会按照一定规则对业务领域进行划分,划分后会将问题范围限定在特定的边界内,在这个边界内建立领域模型,总结:DDD的领域就是这个边界内要解决的业务问题域。
-
可以将大的领域进一步划分,划分成多个子领域,每个子领域对应更小的业务范围或者一个问题
-
同自然科学的研究方法进行类比
主要过程就是确定好一个研究对象,然后进行一层一层的细分,其中第一步到第三步就是在进行领域划分,到第四部 相当于确定了研究的最小单元,和最小边界
-
实际业务举例:选择自己熟悉的业务进行举例
-
领域建模和微服务建设的过程和⽅法基本类似,其核⼼思想就是将问题域逐步分解,降低业务理解和 系统实现的复杂度。
核心域、通用域和支撑域
子域根据自身功能和属性 再划分为三个域,分别是核心域、通用域、支撑域,用桃树举例 对于园丁而言,在桃花盛开的季节,核心域就是桃花,桃树的枝叶则可以是支撑域和通用域,要注意修剪
- 核心域:决定产品的核心竞争力,是最重要的功能,没有太多个性化的需求
- 通用域:是通用的系统,比如鉴权认证之类的功能
- 支撑域:具有企业特性,不具有通用性,例如数据字典系统
3、限界上下文:定义领域边界的利器
通用语言:
-
是什么:在事件⻛暴过程中,通过团队交流达成共识的,能够简单、清晰、准确描述 业务涵义和规则的语⾔就是通⽤语⾔
-
什么价值:不同角色的人员之间无交流障碍,确保业务需求的正确表达
-
哪里用:通用语言中的术语和一些用例 要在代码或者领域设计中能直接找到,这样开发出的代码可读性也就更好
-
从事件风暴中建立通用语言到代码落地的过程
-
示例:用表格来记录事件风暴和微服设计过程中产生的领域对象和其从属
限届上下文
- 用来封装通用语言和领域对象 ,提供上下文环境(语义环境),保证在领域之内的⼀些术语、业务相关对象等(通⽤语⾔)有⼀个确切的含义,没有⼆义性。(补充:产品在不同流程 会产生不同的语义环境,比如商品 在销售阶段就是商品,在物流阶段则会是货物)
- 这个边界定义了模型的适⽤范围,使团队所有成员能够明确地知道什么应该在模型中实现,什么不应该在模型中实现。
限界上下⽂和微服务的关系

模型先被分为四个子领域,然后还进一步拆分的更小,比如支付被拆为收款和付款,收款和付款此时的领域边界 实际上就是上下文限界,对于投保 子域本身的边界就是限界上下文,理论上限界上下⽂就是微服务的边界,是微服拆分的重要依据
4、实体和值对象:从领域模型的基础单元看系统设计
实体和值对象是组成领域模型的基础单元。
实体
拥有唯⼀标识符,且标识符在历经各种状态变更后仍能保持⼀致的对象,核心是其持续性和标识
- 实体的业务形态
-
- 在战略设计中 它是领域模型的一个重要对象,包含多个属性和行为
- 在事件风暴中,通过命令、操作或者事件找出这些行为对应的实体对象,多个有一定联系的实体对象可组成一个聚合
- 实体的代码形态
-
- 就是一个实体类,包含属性和方法,并且是充血的模式,包含自身的业务逻辑
- 实体的运行形态
-
- 以DO(领域对象)的状态存在,每个DO都有一个ID,ID不变就会是同一个实体(结合业务场景进行考虑,比如一件商品,价格可能会被不同逻辑更改,但商品仍然是这件商品)
- 实体的数据库形态
-
- DDD中是先构建领域模型,再去创建实体对象和行为,再将实体对象映射到持久化存储空间
- 实体对象与持久化对象是n对n的,实体对象可能会有持久化对象来生成
值对象
-
书中概念:通过对象属性值来识别的对象,它将多个相关属性组合为⼀个概念整体。
-
简单解释:值对象描述了领域中的一件东西,这个东西是不可变的,他将不同的相关属性组合成了一个概念整体
-
进一步解释:值对象就是一个集合,集合中包含有若干个 用于描述目的,具有整体概念和不可修改的属性,如下例,人员实体中的地址,抽出来作为一个 地址属性集合,也就是值对象
-
业务形态
-
- 也是DDD领域模型中的一个基础对象,来源于事件风暴所构建的领域模型,它包含了若干个属性,与实体一起构成聚合
- 与实体相较:实体是一个业务对象,包含业务属性、业务行为和业务逻辑,值对象则是若干个属性的集合,只有数据初始化操作和不修改数据的行为,基本不包含业务逻辑,逻辑上属于实体属性的一部分,用于描述实体的特征,例如上例中的人员地址
- 代码形态
代码中有两种形态
-
- 如果值对象是单⼀属性,则直接定义为实体类的属性;
- 如果值对象是属性 集合,则把它设计为Class类,Class将具有整体概念的多个属性归集到属性集合,这样的值对象没有ID,会 被实体整体引⽤。
- 运行形态
-
- 值对象以属性嵌入或者整体序列化的方式嵌入实体对象中,如下例
- 值对象以属性嵌入或者整体序列化的方式嵌入实体对象中,如下例
- 数据库形态
-
- DDD引⼊值对象是希望实现从"数据建模为中⼼"向"领域建模为中⼼"转变,减少数据库表的数量和表与 表之间复杂的依赖关系,尽可能地简化数据库设计,提升数据库性能。
- 传统数据驱动的方式开发:严格遵守数据范式,一个实体一张表,也会关联多张表,例如上面的人员案例,将有两种设计方式,第一种 涉及人员表和地址表,缺点是增加了数据设计的复杂性,第二种只创建一个表,把地址相关的数据都放到人员表中,缺点是缺失了业务含义和概念完整性
- **领域驱动的方式:扬长避短,人员作为实体 创建人员表,地址作为值对象,不创建表,值对象中的属性保存在人员表中 ,**这样兼顾了业务含义表达与数据库复杂度的控制
- 值对象的优势与局限
-
- 优点是简化数据库设计,提高数据库性能
- 缺点是搜索值对象的属性会变的困难,而且如果实体对象引用值对象过多 会导致实体堆积一堆缺乏概念完整性的属性,值对象失去含义,操作不便
- 实体和值对象的关系
-
- 实体和值对象是微服务底层的最基础的对象,⼀起实现实体最基本的核⼼领域逻辑。
- 值对象和实体在某些场景下可以互换
5、聚合和聚合根:怎样设计聚合?
聚合(Aggregate)
- 实体⼀般对应业务对象,它具有业务属性和业务⾏为;⽽值 对象主要是属性集合,对实体的状态和特征进⾏描述。但实体和值对象都只是个体化的对象,它们的⾏为表 现出来的是个体的能⼒。
- 实体和值对象相当于个体,而让个体和值对象协同工作的组织就是聚合,它⽤来确保这些领 域对象在实现共同的业务逻辑时,能保证数据的⼀致性。
-
- 聚合就是由业务和逻辑紧密关联的实体和值对象组合⽽成的,聚合是数据修改和持久化的 基本单元,每⼀个聚合对应⼀个仓储,实现数据的持久化。
- 聚合包含一个聚合根和上下文边界,聚合内高内聚,聚合之间则是松耦合的
聚合根(AggregateRoot)
- 聚合根的主要⽬的是为了避免由于复杂数据模型缺少统⼀的业务规则控制,⽽导致聚合、实体之间数据不⼀ 致性的问题。
- 聚合根也称为根实体,它不仅是实体,还是聚合的管理者,在聚合内部负责协调实体和值对象按照固定的业务规则协同完成共同的业务逻辑
- 在聚合之间,它还是聚合对外的接⼝⼈,以聚合根ID关联的⽅式接受外部任务和请求,在上下⽂内实现聚合之间的业务协同,注意要反问其它聚合内的实体 必须先访问聚合,然后才能访问内部实体
怎样设计聚合
- 聚合构建案例
-
- 事件风暴:分析场景、用例、用户旅程
- 选择聚合根
-
-
- 是否有独⽴的⽣命周期?
- 是否有全局唯⼀ID?
- 是否可以创建或修改其它对象?
- 是否有专⻔的模块来管这个实体。
-
-
- 找出跟这个聚合根实体相关联的实体和值对象,最终构建一个聚合
- 画出对象的引用依赖模型(实体、值对象、聚合根)
- 多个聚合根据业务语义和上下文划分到同一个限界上下文中
聚合设计的一些原则
- 在⼀致性边界内建模真正的不变条件 :聚合⽤来封装真正的不变性,⽽不是简单地将对象组合在⼀起。
聚合内有⼀套不变的业务规则,各实体和值对象按照统⼀的业务规则运⾏,实现对象数据的⼀致性,边界之
外的任何东西都与该聚合⽆关,这就是聚合能实现业务⾼内聚的原因。(聚合之间互不影响-高内聚) - 设计⼩聚合 :如果聚合设计得过⼤,聚合会因为包含过多的实体,导致实体之间的管理过于复杂,⾼频
操作时会出现并发冲突或者数据库锁,最终导致系统可⽤性变差。⽽⼩聚合设计则可以降低由于业务过⼤导
致聚合重构的可能性,让领域模型更能适应业务的变化。 - 通过唯⼀标识引⽤其它聚合: 聚合之间是通过关联外部聚合根ID的⽅式引⽤,⽽不是直接对象引⽤的⽅
式。外部聚合的对象放在聚合边界内管理,容易导致聚合的边界不清晰,也会增加聚合之间的耦合度。 - 在边界之外使⽤最终⼀致性: 聚合内数据强⼀致性,⽽聚合之间数据最终⼀致性。在⼀次事务中,最多
只能更改⼀个聚合的状态。如果⼀次业务操作涉及多个聚合状态的更改,应采⽤领域事件的⽅式异步修改相
关的聚合,实现聚合之间的解耦(相关内容我会在领域事件部分详解)。 - 通过应⽤层实现跨聚合的服务调⽤: 为实现微服务内聚合之间的解耦,以及未来以聚合为单位的微服务
组合和拆分,应避免跨聚合的领域服务调⽤和跨聚合的数据库表关联。
进阶篇
6、领域事件:解耦微服务的关键
领域事件
- 领域事件可以切断领域之间的强依赖关系,就如MQ中的生产者,发出的事件无需消费者同步结果
- 微服内的领域事件
-
- 按照一次事务只更新一次聚合的原则,如果一次事件要更新多个聚合就可以考虑使用事件总线
- 微服之间的领域事件
-
- 跨微服务的领域事件会在不同的限界上下⽂或领域模型之间实现业务协作,其主要⽬的是实现微服务解耦, 减轻微服务之间实时服务访问的压⼒。
相关案例

- 第⼀个领域事件:缴费通知单已⽣成 (1、2)
- 第⼆个领域事件:缴费已完成(3、4)
- 第三个领域事件:保单已⽣成(5、6)
- 省略。。。。
领域事件架构
领域事件处理包括:事件构建和发布、事件数据持久化、事件总线、消息中间件、事件接收和处理等。

- 领域事件的构建与发布
-
-
事件基本属性:事件唯⼀标识、发⽣时间、事件类型和事件源
-
业务属性:业务相关数据
-
事件实体:由事件属性和业务属性构成,并且依赖聚合根
-
事件基类:为保障事件结构的统一,事件基类如下:
-
事件发布之前要注意先持久化
-
- 事件数据持久化
-
- 持久化之后可以核对数据,保障上下文数据一致性
- 持久化两种方案,一种也是用业务库,创建并插入事件表,共用本地事务,第二种单独使用事件库,但要注意跨库的事务问题
- 事件总线
-
- 主要提供接收和分发事件等功能
- 如上图,如果是微服内,则直接进行分发,跨微服则先持久化,然后发送给mq
- 如果同时存在微服内和微服外,则 内->持久化->异步分发
- 消息中间件
- 事件接受和处理
- 领域事件运行机制相关案例
-
- 事件起点:出单员⽣成投保单,核保通过后,发起⽣成缴费通知单的操作。
- 分别创建缴费通知单、缴费通知单事件
- 持久化事件(避免了分布式事务)
- 获取事件增量,并发布到mq
- 接收消息、并持久化
- 完成缴费业务
- 返回完成事件

7、DDD分层架构:有效降低层与层之间的依赖
什么是DDD分层架构
因为领域层才是软件的核心,所以有了传统四层架构到采用依赖倒置四层架构的演变,而后来引用层和领域层之间增加了上下文层(context),由此五层架构DCI就形成了

优化后的四层架构各层主要职责的具体介绍

- 用户接口层:主要向用户显示信息,这里用户指:普通用户、自动化测试脚本等等
- 应用层
-
- 主要面向用例和流程相关的操作,一般不包含业务逻辑
- 协调多个聚合的服务和领域对象完成服务编排和组合,协作完成业务操作。
- 调⽤其它微服务的应⽤服务,完成微服务之间的服务组合和编排。
- 注意:不要再应用层防止过多业务逻辑,否则会退化为三层架构,业务逻辑也会变的十分混乱
- 总结:应⽤服务是在应⽤层的,它负责服务的组合、编排和转发,负责处理业务⽤例的执⾏顺序以及结果的拼装,以粗粒度的服务通过API⽹关向前端发布。还有,应⽤服务还可以进⾏安全认证、权限校验、事务控制、发送或订阅领域事件等
- 领域层:
-
- 负责实现核心业务逻辑,主要体现领域模型的业务能力,用它来表达业务概念、业务状态、业务规则
- 领域层包含聚合根、实体、值对象、领域服务等领域模型中的领域对象
- 不同领域对象之间的关系:领域模型的业务逻辑主要是由实体和领域服务来实现的,实体和领域对象在实现业务逻辑上不是同级的,当领域中的某些功能,单⼀实体(或者值对象)不能实现时,领域服务就会出⻢,它可以组合聚合内的多个实体(或者值对象),实现复杂的业务逻辑。
- 基础层:
-
- 为其它各层提供通用的技术和基础服务,例如第三方工具、驱动、中间件、网关、文件、存储
- 采用依赖倒置原则,在例如切换数据源这种场景下,可以从容应对**(需要再做了解)**
- DDD分层架构的原则:每层只能与位于其下方的层发生耦合
-
- 严格分层架构:上述中优化后的架构,只能与直接下方耦合,推荐使用这种方式,更简洁明了,发生变更只需通知依赖自己的上层
- 松散分层架构:优化前的架构,可以与下方任意层发生依赖
DDD分层架构如何推动架构演进
-
聚合的重组迁移或拆分会引起领域模型和微服务较大的变化
如果上图有设计好聚合和上下文边界将能很快完成变更
三层架构如何演进到DDD分层架构

- 其中在用户接口层引入 数据传输对象(DTO)(Data Transfer Object),给前端提供了更多的可使用数据和更高的展示灵活性
- DDD对三层架构中的业务逻辑层进行了更细致的划分,改善原有核心业务逻辑混乱的问题、代码改动相互影响较大的问题,
- 基础层采用仓储设计模式,通过依赖倒置实现各层对基础资源的解耦,仓储分为仓储接口和仓储实现,接口放在领域层,实现放在基础层
- 仓储模式概念补充
-
- 是为了在程序的数据访问层和业务逻辑层之间创建的一个抽象层
- 根据Eric Evans的《领域驱动设计》一书,"存储库是一种封装存储,检索和搜索行为的机制,它模仿对象的集合。"同样,根据企业应用程序体系结构的模式,它"使用类似集合的接口访问域对象,在域和数据映射层之间进行中介"。
8、微服务架构模型:几种常见模型的对比和分析
整洁架构
-
又名洋葱架构,主要体现了分层的设计思想
-
整洁架构外层依赖内层,越往内层代码级别越高,越是核心能力
-
领域模型是核心业务逻辑,主体是实体,领域服务涉及多个实体,封装复杂业务逻辑,应用服务负责服务的组合与编排,最外层提供与用户和基础资源的适配能力
-
红圈内是软件的核心业务能力
六边形架构
-
又名端口适配器架构,核心理念是应用是通过端口与外部进行交互的
-
红圈内的六边形实现应⽤的核⼼业务逻辑;
外六边形完成外部应⽤、驱动和基础资源等的交互和访问,对前端应⽤以API主动适配的⽅式提供服务, 对基础资源以依赖倒置被动适配的⽅式实现资源访问。
架构对比

- 三种架构都体现出了高内聚低耦合的设计原则
- 图中三种架构的红框是重要的分割线,作用都是将核心业务逻辑与外部应用、基础资源进行了隔离
- 应⽤层实现⾯向⽤⼾操作相关的⽤例和流程,对外提供粗粒度的API服务。 它就像⼀个⻮轮⼀样进⾏前台应 ⽤和领域层的适配,接收前台需求,随时做出响应和调整,尽量避免将前台需求传导到领域层 。应⽤层作为 配速⻮轮则位于前台应⽤和领域层之间。(个人理解,考虑前台的需求会不断变更,使用应用层作为变速齿轮,尽量不将变更传导到领域层,应用层只做服务编排,提供粗粒度的能力,这个能力由多个能提供细粒度能力的领域模型提供,也正是因为领域服务是细粒度的并且是核心逻辑 ,所以会有变更止步于应用层),
所以三种架构都考虑了前端需求的变与领域模型的不变, 有外向内受需求变更的影响逐渐减少,保障了领域层的长期稳定,对于前台灵活、中台稳固的架构也很有帮助 - 中台与微服设计的关键:领域模型和微服务的合理分层设计
从三种架构看中台与微服务设计
中台本质可能涉及核心域、通用域或支撑域,阿里的中台则可能是通用域
- 中台建设要聚焦领域模型
-
- 中台需要站在全企业的⾼度考虑能⼒的共享和复用
- 微服务要有合理的架构分层
-
- 两种级别的微服务
-
-
- 项目级微服务:服务与前端集成,一起完成特定的业务
- 企业级中台微服务:需要多个职责单一的中台微服务组合才能完成业务流程
-
-
-
项目级微服务:遵循分层架构,各层各司其职,其中在应用层进行自己的领域服务,和其它微服务之间的编排
-
企业级中台微服务
-
-
-
- 相较于项目级微服务它不能在某一个微服务内完成跨服的服务组合和编排,所以**增加BFF(服务于前端的后端,Backend for Frontends),**它的主要职能就是处理跨中台微服务的服务组合和编排,以及微服务之间的协调(目前感觉就是在不同中台微服务的应用层之上 又加了一层应用层来做编排)
-
- 应用和资源的解耦与适配
-
- 传统以数据为中心的设计 会对存储等系统造成强依赖,例如不同的缓存技术, 一旦变更则可能会对应用造成很大的影响所以需要做解耦
- DDD中则是通过仓储模式来完成这种解耦,切断上述中的依赖,屏蔽基础资源变更对业务代码的影响
9、中台:数字转型后到底应该共享什么?
平台到底是不是中台
平台只是将部分通⽤的公共能⼒独⽴为共享平台,没有和企业内的其它平台或应⽤,实现⻚⾯、业务流程和数据从前端到 后端的全⾯融合,没有将核⼼业务服务链路作为⼀个整体⽅案考虑,各平台仍然是分离且独⽴的,并且只属于
平台解决了公共能⼒复⽤的问题,但离中台的⽬标显然还有⼀段差距!
中台到底是什么
- 是一个基础的理念和架构,是企业级能力的复用,
数字化转型中台应该共享什么?

在中台设计和规划时,我们需要整体考虑企业内前台、中台以及后台应⽤的协同**,实现不同渠道应⽤**
的前端⻚⾯、流程和服务的共享,还有核⼼业务链路的联通以及前台流程和数据的融合、共享,⽀持业务和
商业模式的创新。
如何实现前中后台的协同
- 前台
-
-
早期竖井式系统架构
-
而现在的前台建设要有⼀套综合考虑业务边界、流程和平台的整体解决⽅案,以实现各不同中台前端操作、流程和界⾯的联通、融合。不管后端有多少个中台,前端⽤⼾感受到的就是只有⼀个前台,并且最好能使用微前端页面进行动态组件组合
-
- 中台
-
-
业务中台的建设可采⽤领域驱动设计⽅法,通过领域建模,将可复⽤的公共能⼒从各个单体剥离,沉淀并组 合,采⽤微服务架构模式,建设成为可共享的通⽤能⼒中台。
-
中台可向前台、第三⽅和其它中台提供API服务,实现通⽤能⼒和核⼼能⼒的复⽤。
-
数据中台的主要⽬标是打通数据孤岛,实现业务融合和创新
-
-
-
- ⼀是完成企业全域数据的采集与存储,实现各不同业务类别中台数据的汇总和集中管理。
- ⼆是按照标准的数据规范或数据模型,将数据按照不同主题域或场景进⾏加⼯和处理,形成⾯向不同主题
- 和场景的数据应⽤,⽐如客⼾视图、代理⼈视图、渠道视图、机构视图等不同数据体系。三是建⽴业务需求驱动的数据体系,基于各个维度的数据,深度萃取数据价值,⽀持业务和商业模式的创新。
-
-
- 数据中台建设三步走:
-
-
- 第⼀步实现各中台业务数据的汇集,解决数据孤岛和初级数据共享问题。
- 第⼆步实现企业级实时或⾮实时全维度数据的深度融合、加⼯和共享。
- 第三步萃取数据价值,⽀持业务创新,加速从数据转换为业务价值的过程
-
- 后台
- 阿里对前中后台的定义:前台主要⾯向客⼾以及终端销售者,实现营销推⼴以及交易转化;中台主要⾯向运营⼈员,完成运营⽀撑;后台主要⾯向后台管理⼈员,实现流程审核、内部管理以及后勤⽀撑,⽐如采购、⼈⼒、财务和OA等系统。
10、DDD、中台和微服务:它们是如何协作的?
中台是抽象出 来的业务模型,微服务是业务模型的系统实现,DDD作为⽅法论可以同时指导中台业务建模和微服务建设, 三者相辅相成,完美结合。
DDD的本质
一些核心概念

中台的本质
中台的本质其实就是提炼各个业务板块的共同需求,进⾏业务和系统抽象,形成通⽤的可复⽤的业务模型, 打造成组件化产品,供前台部⻔使⽤。前台要做什么业务,需要什么资源,可以直接找中台,不需要每次都去改动⾃⼰的底层。
DDD、中台和微服务的协作模式
-
传统企业可以将需要共享的能力进行领域建模,建设可共享的通用中台 ,也可将核⼼能⼒进⾏领域建模,建设⾯向不同渠道的可复⽤的核⼼中台
-
从DDD视角看整个企业业务是一个领域,然后进行领域切分,从中台视角看业务域细分后的业务中台可分为通用中台和核心中台。另外,领域模型所在的限界上下⽂对应微服务。
-
协作模式:
-
- 将DDD的⽅法引⼊中台设计时,我们要先建⽴中台和DDD的通⽤语⾔。这⾥的⼦域与中台是⼀致的,那我们就可以将⼦域统⼀为中台。
- 中台通过事件⻛暴可以进⼀步细分,最终完成业务领域建模。
- 中台业务领域的功能不同,限界上下⽂的数量和⼤⼩就会不⼀样,领域模型也会不⼀样。当完成业务建模后,我们就可以采⽤DDD战术设计,设计出聚合、实体、领域事件、领域服务以及应⽤服务等领域对象,再利⽤分层架构模型完成微服务的设计。
中台如何建模
- 第⼀步:按照业务流程(通常适⽤于核⼼域)或者功能属性、集合(通常适⽤于通⽤域或⽀撑域),将业务 域细分为多个中台,再根据功能属性或重要性归类到核⼼中台或通⽤中台。核⼼中台设计时要考虑核⼼竞争 ⼒,通⽤中台要站在企业⾼度考虑共享和复⽤能⼒。
- 第⼆步:选取中台,根据⽤例、业务场景或⽤⼾旅程完成事件⻛暴,找出实体、聚合和限界上下⽂。依次进 ⾏领域分解,建⽴领域模型。
- 第三步:以主领域模型为基础,扫描其它中台领域模型,检查并确定是否存在重复或者需要重组的领域对 象、功能,提炼并重构主领域模型,完成最终的领域模型设计。
- 第四步:选择其它主领域模型重复第三步,直到所有主领域模型完成⽐对和重构。
- 第五步:基于领域模型完成微服务设计,完成系统落地。(这一步是对应DDD战术设计,上面的都是战略设计)

答疑:有关3个典型问题的讲解
问题1:有关于领域可以划分为核⼼域、通⽤域和⽀撑域,以及⼦域和限界上下⽂关系的话题,还有是否有 边界划分的量化标准?
目前看没有可量化标准,主要依赖领域专家经验,以及团队在事件风暴中不断地权衡和分析
问题2:关于聚合设计的问题?领域层与基础层为什么要依赖倒置(DIP)?
- 在聚合设计时有两个重要的设计模式:工厂模式和仓储模式,推荐阅读 《实现领域驱动设计》⼀书的第11章和第12章。
- 使用工厂模式来创建大量且复杂的聚合内的对象
- 传统的DDD模式中,所有的层都依赖基础层,基础层的代码耦合在应用层中,一旦基础层发生变更,应用层也会发生大量变更,所以要进行依赖倒置,例如就在应用层和基础层中间加上仓储层,也就是仓储模式,让变更只限于仓储层,来对应用逻辑和基础资源进行解耦
问题3:领域事件采⽤消息异步机制,发布⽅和订阅⽅数据如何保证⼀致性?微服务内聚合之间领域事件是 否⼀定要⽤事件总线?
- 对于一致性可以首先保障事件数据落库,然后保障MQ不丢失,另外可以使用类似定时对账和补偿机制来进行处理
- 微服务内不一定使用
实战篇
11、DDD实践:如何用DDD重构中台业务模型?
传统企业应用分析
电商行业与传统行业(保险)的功能差异性

如何避免重复造轮子
站在企业⾼度,将重复的需要共享的通⽤能⼒、核⼼能⼒沉淀到中台,将分离的业务能⼒重组为完整 的业务板块,构建可复⽤的中台业务模型。前端个性能⼒归前端,后端管理能⼒归后台。建⽴前、中、后台 边界清晰,融合协作的企业级可复⽤的业务模型。
如何构建中台业务模型
-
自顶向下策略:适⽤于全新的应⽤系统建设,或旧系统推倒重建的情况。
-
自底向上策略:适⽤于遗留系统业务模型的演进式重构
-
- 锁定系统所在业务域,完成领域建模
- 对齐业务域,构建中台业务模型
- 中台业务模型构建示例
-
- 构建多业务域的中台业务模型的过程,就是找出同⼀业务域内所有同类业务的领域模型,对⽐分析域内领域模型和聚合的差异和共同点,打破原有的模型,完成新的中台业务模型重组或归并的过程。
12、领域建模:如何用事件风暴构建领域模型?
领域专家与项⽬团队通过头脑⻛暴的形 式,罗列出领域中所有的领域事件,整合之后形成最终的领域事件集合,然后对每⼀个事件,标注出导致该 事件的命令,再为每⼀个事件标注出命令发起⽅的⻆⾊。命令可以是⽤⼾发起,也可以是第三⽅系统调⽤或 者定时器触发等,最后对事件进⾏分类,整理出实体、聚合、聚合根以及限界上下⽂。⽽事件⻛暴正是DDD 战略设计中经常使⽤的⼀种⽅法,它可以快速分析和分解复杂的业务领域,完成领域建模。
事件风暴需要准备些什么
-
事件风暴的参与者:领域专家、DDD专家、架构师、产品经理、项⽬经理、开发⼈员和测试⼈ 员等项⽬团队成员。
-
要准备的材料:可以用贴着表达出每个人不同的想法
-
事件风暴的场地
-
事件风暴分析的关注点
如何用事件风暴构建领域模型
- 产品愿景
-
- 参与角色:领域专家、业务需求⽅、产品经理、项⽬经理和开发经理
- 思考点
-
-
- 用户中台到底能够做什么?
- 它的业务范围、⽬标⽤⼾、核⼼价值和愿景,与其它同类产品的差异和优势在哪⾥?
-
- 业务场景分析
-
- 是从⽤⼾视⻆出发的,根据业务流程或⽤⼾旅程,采⽤⽤例和场景分析,探索领域中的典型场景,找出领域事件、实体和命令等领域对象,⽀撑领域建模。事件⻛暴参与者要尽可能地遍历所有业务细节,充分发表意⻅,不要遗漏业务要点。
- 参与角色:领域专家、产品经理、需求分析⼈员、架构师、项⽬经理、开发经理和测试经理。
- 示例:
- 领域建模
-
- 领域建模时,我们会根据场景分析过程中产⽣的领域对象,⽐如命令、事件等之间关系,找出产⽣命令的实体,分析实体之间的依赖关系组成聚合,为聚合划定限界上下⽂,建⽴领域模型以及模型之间的依赖。领域模型利⽤限界上下⽂向上可以指导微服务设计,通过聚合向下可以指导聚合根、实体和值对象的设计。
- 参与角色:领域专家、产品经理、需求分析⼈员、架构师、项⽬经理、开发经理和测试经理。
- 步骤
-
-
-
第⼀步:从命令和事件中提取产⽣这些⾏为的实体。⽤绿⾊贴纸表⽰实体。通过分析⽤⼾中台的命令和事件等⾏为数据,提取了产⽣这些⾏为的⽤⼾、账⼾、认证票据、系统、菜单、岗位和⽤⼾⽇志七个实体。
-
第⼆步:根据聚合根的管理性质从七个实体中找出聚合根
-
第三步:划定限界上下⽂,根据上下⽂语义将聚合归类。
-
-
- 微服拆分与设计
-
- 领域的拆分会作为微服拆分的一个重要依据,此外还要考虑服务的粒度、分层、边界划分、依赖关系和集成关系,还需要考虑将敏态与稳态业务的分离、⾮功能性需求(如弹性伸缩要求、安全性等要求)、团队组织和 沟通效率、软件包⼤⼩以及技术异构等⾮业务因素。
- 参与角色:领域专家、产品经理、需求分析⼈员、架构师、项⽬经理、开发经理和测试经理。
- 补充:
-
- 中型规模的项⽬,领域建模的时间⼤概在两周左右
- 有边界清晰的领域模型,才能设计出清晰的微服务边界,这两个阶段⼀前⼀后是刚需不能忽略
13、代码模型(上):如何使用DDD设计微服务代码模型?
DDD分层架构与微服务代码模型
- 微服务的落地首先要确定微服务的代码结构
- DDD没有给出标准代码模型
- 回顾07讲分层架构
微服务代码模型

- 微服务一层架构
-
- Interfaces(⽤⼾接⼝层):与前端交互,解析用户请求,传输数据给application层,封装各类数据
- application(应用层):应⽤服务向下基于微服务内的领 域服务或外部微服务的应⽤服务完成服务的编排和组合,向上为⽤⼾接⼝层提供各种应⽤数据展现⽀持服 务。应⽤服务和事件等代码会放在这⼀层⽬录⾥。
- Domain(领域层):它主要存放领域层核⼼业务逻辑相关的代码。领域层可以包含多个聚合代码包,它们共同实现领域模型的核⼼业务逻辑。聚合以及聚合内的实体、⽅法、领域服务和事件等代码会放在这⼀层⽬录⾥。
- Infrastructure(基础层):它主要存放基础资源服务相关的代码,为其它各层提供的通⽤技术能⼒、三⽅ 软件包、数据库服务、配置和基础资源服务的代码都会放在这⼀层⽬录⾥。
- Interfaces
-
- Assembler:实现DTO与领域对象之间的相互转换和数据交换。
- DTO:数据传输载体,我们可以通过DTO把内部的领域对象与外界隔离,它里面不包含业务逻辑
- Facade:提供较粗粒度的调⽤接⼝,将⽤⼾请求委派给⼀个或多个应⽤服务进⾏处理。
- application
-
- Event:下面存放发布和订阅相关代码,注意实现代码放在领域层
- service:对多个领域服务或外部应⽤服务进⾏封装、编 排和组合,对外提供粗粒度的服务
- Domain
-
- Aggregate:聚合软件包的根目录,聚合之间清晰的代码边界,可以更轻松的实现聚合为单位的微服务重组
- Entity(实体):它存放聚合根、实体、值对象以及⼯⼚模式(Factory)相关代码。实体类采⽤充⾎模 型,同⼀实体相关的业务逻辑都在实体类代码中实现。跨实体的业务逻辑代码在领域服务中实现。
- Event(事件):它存放事件实体以及与事件活动相关的业务逻辑代码。
- Service(领域服务):它存放领域服务代码。⼀个领域服务是多个实体组合出来的⼀段业务逻辑。你可以将聚合内所有领域服务都放在⼀个领域服务类中,你也可以把每⼀个领域服务设计为⼀个类。如果领域服务 内的业务逻辑相对复杂,我建议你将⼀个领域服务设计为⼀个领域服务类,避免由于所有领域服务代码都放 在⼀个领域服务类中,⽽出现代码臃肿的问题。领域服务封装多个实体或⽅法后向上层提供应⽤服务调⽤。
- Repository(仓储):它存放所在聚合的查询或持久化领域对象的代码,通常包括仓储接⼝和仓储实现⽅法。为了⽅便聚合的拆分和组合,我们设定了⼀个原则:⼀个聚合对应⼀个仓储。 特别说明:按照DDD分层架构,仓储实现本应该属于基础层代码,但为了在微服务架构演进时,保证代码拆分和重组的便利性,我是把聚合仓储实现的代码放到了聚合包内。这样,如果需求或者设计发⽣变化导致聚 合需要拆分或重组时,我们就可以将包括核⼼业务逻辑和仓储代码的聚合包整体迁移,轻松实现微服务架构 演进。
- Infrastructure
-
- Config:主要存放配置相关代码。
- Util:主要存放平台、开发框架、消息、数据库、缓存、⽂件、总线、⽹关、第三⽅类库、通⽤算法等基础 代码,你可以为不同的资源类别建⽴不同的⼦⽬录。
14、代码模型(下):如何保证领域模型与代码模型的一致性?
领域对象的整理
-
将事件风暴中产生的各个领域对象记录到下面的表格中
-
从领域模型到微服务落地
-
- 事件⻛暴中提取的领域对象,还需要经过⽤⼾故事或领域故事分析,以及微服务设计,才能⽤于微服务系统开发。这个过程会⽐事件⻛暴来的更深⼊和细致。主要关注内容如下:
-
-
- 分析微服务内有哪些服务?
- 服务所在的分层?
- 应⽤服务由哪些服务组合和编排完成?
- 领域服务包括哪些实体的业务逻辑?
- 采⽤充⾎模型的实体有哪些属性和⽅法?
- 有哪些值对象?
- 哪个实体是聚合根等?
- 最后梳理出所有的领域对象和它们之间的依赖关系,我们会给每个领域对象设计对应的代码对象,定义它 们所在的软件包和代码⽬录。
-
- 参与者:DDD专家、架构师、设计⼈员和开发经理。
领域层的领域对象
- 设计实体:大多数情况下,与数据驱动时的数据实体相对应,采用重写模式,放在entity目录下
- 找出聚合根:
-
- 在个⼈客⼾聚合⾥,个⼈客⼾这个实体是聚合根,它负责管理地址、电话以及银⾏账号的⽣命周期。个⼈客⼾聚合根通过⼯⼚和仓储模式,实现聚合内地址、银⾏账号等实体和值对象数据的初始化和持久化。
- 聚合根是⼀种特殊的实体,它有⾃⼰的属性和⽅法。聚合根可以实现聚合之间的对象引⽤,还可以引⽤聚合 内的所有实体。聚合根类放在代码模型的Entity⽬录结构下。聚合根有⾃⼰的实现⽅法,⽐如⽣成客⼾编 码,新增和修改客⼾信息等⽅法。
- 设计值对象:需要将某些实体的某些属性或属性集设计为值对象,也是entity下,比如客户聚合中的证件类型,需要确定什么时候设计成值对象,什么时候设置成实体类
- 设计领域事件:领域事件实体和处理类放在领域层的Event⽬录结构下。领域事件的发布和订阅类我建议放在应⽤层的Event⽬录结构下
- 设计领域服务:
-
- 如果⼀个业务动作或⾏为跨多个实体,我们就需要设计领域服务。领域服务通过对多个实体和实体⽅法进⾏组合,完成核⼼业务逻辑 ,你可以认为领域服务是位于实体⽅法之上和应用层之下的⼀层业务逻辑。按照严格分层架构层的依赖关系,如果实体的⽅法需要暴露给应⽤层,它需要封装成领域服务后才可以被应⽤服务调⽤。所以如果有的实体⽅法需要被前端应⽤调⽤,我们会将它封装成领域服务,然后再封装为应⽤服务。
- 个⼈客⼾聚合根这个实体创建个⼈客⼾信息的⽅法,被封装为创建个⼈客⼾信息领域服务。然后再被封装为创建个⼈客⼾信息应⽤服务,向前端应⽤暴露。领域服务类放在领域层的Service⽬录结构下。
- 设计仓储
每⼀个聚合都有⼀个仓储,仓储主要⽤来完成数据查询和持久化操作。仓储包括仓储的接⼝和仓储实现,通过依赖倒置实现应⽤业务逻辑与数据库资源逻辑的解耦。仓储代码放在领域层的Repository⽬录结构下。
应用层的领域对象
- 应⽤层的主要领域对象是应⽤服务和事件的发布以及订阅。
- 在时间风暴中 我们在应用层设计时需要分析
-
- 在应⽤层和领域层分别会发⽣哪些业务⾏为;
- 各层分别需要设计哪些服务或者⽅法;
- 这些⽅法和服务的分层以及领域类型(⽐如实体⽅法、领域服务和应⽤服务等),它们之间的调⽤和组合的依赖关系
- 严格分层架构模式下,服务从下到上为:实体方法-领域服务-应用服务,夸层调用需要逐层封装
-
- 实体方法的封装:实体方法-领域服务-应用服务
- 领域服务的组合和封装:领域服务对多个实体方法进行组合编排
- 应用服务的组合和编排:应⽤服务会对多个领域服务进⾏组合和编排,暴露给⽤⼾接⼝层,供前端应⽤调⽤。
领域对象与微服务代码对象的映射
- 典型的领域模型
-
- 层:定义领域对象位于分层架构中的哪⼀层,⽐如:接⼝层、应⽤层、领域层以及基础层等。
- 领域对象:领域模型中领域对象的具体名称。
- 领域类型:根据DDD知识体系定义的领域对象的类型,包括:限界上下⽂、聚合、聚合根、实体、值对象、领域事件、应⽤服务、领域服务和仓储服务等领域类型。
- 依赖的领域对象:根据业务对象依赖或分层调⽤的依赖关系,建⽴的领域对象的依赖关系,⽐如:服务调⽤依赖、关联对象聚合等。
- 包名:代码模型中的包名,对应领域对象所在的软件包。
- 类名:代码模型中的类名,对应领域对象的类名。
- ⽅法名:代码模型中的⽅法名,对应领域对象实现或操作的⽅法名。
- 非典型的领域模型
-
- 对于实体类之间松耦合、但业务上是高内聚,依然可以用之前的方法进行设计聚合
16、视图:如何实现服务和数据在微服务各层的协作?
服务和实体在各层之间的协作
服务的协作
- 服务的类型
-
- Facade服务:位于⽤⼾接⼝层,包括接⼝和实现两部分。⽤于处理⽤⼾发送的Restful请求和解析⽤⼾输⼊的配置⽂件等,并将数据传递给应⽤层。或者在获取到应⽤层数据后,将DO组装成DTO,将数据传输到前端应⽤。
- 应⽤服务:位于应⽤层。⽤来表述应⽤和⽤⼾⾏为,负责服务的组合、编排和转发,负责处理业务⽤例的执 ⾏顺序以及结果拼装,对外提供粗粒度的服务。
- 领域服务:位于领域层。领域服务封装核⼼的业务逻辑,实现需要多个实体协作的核⼼领域逻辑。它对多个 实体或⽅法的业务逻辑进⾏组合或编排,或者在严格分层架构中对实体⽅法进⾏封装,以领域服务的⽅式供 应⽤层调⽤。
- 基础服务:位于基础层。提供基础资源服务(⽐如数据库、缓存等),实现各层的解耦,降低外部资源变化 对业务应⽤逻辑的影响。基础服务主要为仓储服务,通过依赖倒置提供基础资源服务。领域服务和应⽤服务 都可以调⽤仓储服务接⼝,通过仓储服务实现数据持久化。
- 服务的调用
-
- 微服务内夸层调用
-
-
- 应用服务的两种调用方式
-
-
-
-
- 第⼀种是应⽤服务调⽤并组装领域服务。此时领域服务会组装实体和实体⽅法,实现核⼼领域逻辑。领域 服务通过仓储服务获取持久化数据对象,完成实体数据初始化。
- 第⼆种是应⽤服务直接调⽤仓储服务。这种⽅式主要针对像缓存、⽂件等类型的基础层数据访问。这类数 据主要是查询操作,没有太多的领域逻辑,不经过领域层,不涉及数据库持久化对象。
-
-
-
- 微服务之间的服务调用
-
-
- 应用服务之间可直接访问,也可走网关,注意分布式事务
-
-
- 领域事件驱动
-
-
- 微服内通过总线、微服间通过mq
-
- 服务的封装与组合
-
- 基础层:主要包括仓储服务,供应⽤层或者领域层服务调⽤,仓储实现服务,完成领域对象的持久化或数据初始化。
- 领域层:
-
-
- 领域层实现核⼼业务逻辑,负责表达领域模型业务概念、业务状态和业务规则。主要的服务形态有实体⽅法
- DDD提倡富领域模型,尽量将业务逻辑归属到实体对象上,实在⽆法归属的部分则设计成领域服务。领域服 务会对多个实体或实体⽅法进⾏组装和编排,实现跨多个实体的复杂核⼼业务逻辑。和领域服务。
-
-
- 应用层
-
-
- 应⽤层⽤来表述应⽤和⽤⼾⾏为,负责服务的组合、编排和转发,负责处理业务⽤例的执⾏顺序以及结果的拼装,负责不同聚合之间的服务和数据协调,负责微服务之间的事件发布和订阅。
- 通过应⽤服务对外暴露微服务的内部功能,这样就可以隐藏领域层核⼼业务逻辑的复杂性以及内部实现机制。应⽤层的主要服务形态有:应⽤服务、事件发布和订阅服务。
- 应⽤服务内还可以完成安全认证、权限校验、初步的数据校验和分布式事务控制等功能。
- 为了实现微服务内聚合之间的解耦,聚合之间的服务调⽤和数据交互应通过应⽤服务来完成。原则上我们应该禁⽌聚合之间的领域服务直接调⽤和聚合之间的数据表关联。
-
-
- 应用接口层
-
-
- ⽤⼾接⼝层是前端应⽤和微服务之间服务访问和数据交换的桥梁。它处理前端发送的Restful请求和解析⽤ ⼾输⼊的配置⽂件等,将数据传递给应⽤层。或获取应⽤服务的数据后,进⾏数据组装,向前端提供数据服 务。主要服务形态是Facade服务。
- Facade服务分为接⼝和实现两个部分。完成服务定向,DO与DTO数据的转换和组装,实现前端与应⽤层数 据的转换和交换。
-
- 两种分层架构的服务依赖关系
-
- 松散分层架构的服务依赖:松散架构下任何服务都可以直接暴露给上层
- 松散分层架构的服务依赖:松散架构下任何服务都可以直接暴露给上层
-
-
- 两个缺点:容易暴露核心层,领域层的实现逻、领域层一旦变更,难以找到哪些服务对齐有调用或组合,不方便通知所有的调用方
-
-
- 严格分层架构的服务依赖
-
-
- 夸层调用必须封装,可避免应用层变的臃肿,而且一旦一层发生变更,只需要通知上层
-
数据对象视图
- 微服内有哪些数据对象,他们之间如何协作和转换
-
- 数据持久化对象PO(Persistent Object),与数据库结构⼀⼀映射,是数据持久化过程中的数据载体。
- 领域对象DO(Domain Object),微服务运⾏时的实体,是核⼼业务的载体。
- 数据传输对象DTO(Data Transfer Object),⽤于前端与应⽤层或者微服务之间的数据组装和传输,是 应⽤之间数据传输的载体。
- 视图对象VO(View Object),⽤于封装展⽰层指定⻚⾯或组件的数据
- 基础层:DO与PO持久化或序列化时相互转换
- 领域层:DO是实体和值对象的数据和业务⾏为载体,承载着基础的核⼼业务逻辑。通 过DO和PO转换,我们可以完成数据持久化和初始化。
- 应用层:应⽤层的主要对象是DO对象,⽤⼾接⼝层先完成DTO到DO的转换,然后应⽤服务接收DO进⾏业务处理,如果DTO与DO是⼀对多的关系,这时就需要进⾏DO数据重组,跨微服DO->DTO
- 用户接口层:DO与DTO的互转,会把多个DO进行组装成DTO返回给前端
- 前端对象:VO
17、从后端到前端:微服务后,前端如何设计?
前端单体的困境
能力集中化,单体项目面对过多api难以管理
从单体前端到微前端
- 在前端设计时我们需要遵循单⼀职责和复⽤原则,按照领域模型和微服务边界,将前端⻚⾯进⾏拆分。同时 构建多个可以独⽴部署、完全⾃治、松耦合的⻚⾯组合,其中每个组合只负责特定业务单元的UI元素和功 能,这些⻚⾯组合就是微前端。
业务单元的组合形态
业务单元包括微前端和微服务,可以独⽴开发、测试、部署和运维,可以⾃ 包含地完成领域模型中部分或全部的业务功能。

- 单一业务单元
- 组合业务单元:1对n,n不能太多,否则会变成单体
- 通用共享业务单元:一个微前端与一个或多个通用微服务组合,这种方式下的微前端产出的是中台共享能力
微前端的集成方式

- 微前端与前端主⻚⾯的集成:微前端通过主⻚⾯的微前端加载器,利⽤⻚⾯路由和动态加载等技术,将特定业务单元的微前端⻚⾯动态加载到前端主⻚⾯,实现前端主⻚⾯与微前端⻚⾯的"拼图式"集成。
- 微前端与微服务的集成:与传统方式没有区别
团队职责边界
- 前端项⽬团队只需要完成企业级前端主⻚⾯与业务单元的融合,前端只关注前端主⻚⾯与微前端⻚⾯ 之间的集成。
- 中台项⽬团队关注业务单元功能的完整性和⾃包含能⼒,完成业务单元内微服务和微前端开发、集成和部署,提供业务单元组件。
设计案例
- 若采用单体会面临的困境
-
- 页面开发和设计的复杂性
- 前端与微服务集成的复杂性
- 全后端软件版本的协同发布
- 设计案例
-
- 微服务:核心为服务和通用微服务
- 微前端
- 业务单元
- 前端主页面
- 业务流程说明
18、知识点串讲:基于DDD的微服务设计实例
项目实战案例
项目基本信息
- 填写请假单和提交审批
- 根据考勤规则,核销数据,输出考勤统计
战略设计
- 是什么,怎么做,谁参与
-
- 战略设计是根据⽤⼾旅程分析,找出领域对象和聚合根,对实体和值对象进⾏聚类组成聚合,划分限界上下⽂,建⽴领域模型的过程。
- 战略设计采⽤的⽅法是事件⻛暴 ,包括:产品愿景、场景分析、领域建模和微服务拆分等⼏个主要过程。
- 战略设计阶段建议参与⼈员:领域专家、业务需求⽅、产品经理、架构师、项⽬经理、开发经理和测试经理。
- 产品愿景
-
- 产品愿景是对产品顶层价值设计,对产品⽬标⽤⼾、核⼼价值、差异化竞争点等信息达成⼀致,避免产品偏离⽅向。
- 事件⻛暴时,所有参与者针对每⼀个要点,在贴纸上写出⾃⼰的意⻅,贴到⽩板上。事件⻛暴主持者会对每个贴纸,讨论并对发散的意⻅进⾏收敛和统⼀,形成下⾯的产品愿景图,如果对系统目标和需求非常清晰明确,这一步可以忽略
- 场景分析
-
-
从⽤⼾视⻆出发,探索业务领域中的典型场景,产出领域中需要⽀撑的场景分类、⽤例操作以及不同⼦域之间的依赖关系,⽤以⽀撑领域建模,根据不同角色的旅程和场景分析,尽可能全⾯地 梳理从前端操作到后端业务逻辑发⽣的所有操作、命令、领域事件以及外部依赖关系等信息。
-
案例:以请假和人员两个场景举例,确定每个场景参与的人员,和具体用例
-
- 领域建模:是一个收敛的过程,分下面三步
-
-
第一步,找出实体和值对象等领域对象
根据场景分析,分析并找出发起或产⽣这些命令或领域事件的实体和值对象。将与实体或值对象有关的命令 和事件聚集到实体。 -
第二步:定义聚合(若一些实体类找不出聚合,但有业务强相关,依然可以设计一个聚合,采用传统方法来管理实体)
-
定义限界上下文(定义了请假和考勤两个限界上下文,两个领域模型)
-
- 微服务拆分:一般一个限界上下文就可以是一个微服务,但也要考虑其它因素,职责单⼀性、敏态与稳态业务分离、⾮功能性需求(如弹性伸缩、版本发布频率和安全等要求)、软件包⼤⼩、团队沟通效率和技术异构等⾮业务要素。
战术设计
- 战术设计
-
- 战术设计是根据领域模型进⾏微服务设计的过程。
- 这个阶段主要梳理微服务内的领域对象、梳理领域对象之间的关系 、确定它们在代码模型和分层架构中的位置、建⽴领域模型与微服务模型的映射关系、以及服务之间的依赖关系。
- 战术设计阶段建议参与⼈员:领域专家、产品经理、架构师、项⽬经理、开发经理和测试经理等。 战术设计包括以下两个阶段:分析微服务领域对象和设计微服务代码结构。
- 分析微服务领域对象
-
- 服务的识别和设计(以命令作为分析的起点)
-
-
- 根据命令设计应⽤服务,确定应⽤服务的功能,服务集合,组合和编排⽅式。服务集合中的服务包括领域服务或其它微服务的应⽤服务。
- 根据应⽤服务功能要求设计领域服务,定义领域服务。这⾥需要注意:应⽤服务可能是由多个聚合的领域 服务组合⽽成的。
- 根据领域服务的功能,确定领域服务内的实体以及功能。
- 设计实体基本属性和⽅法。
- 以提交审批这个动作为例
-
-
-
-
- 应⽤层:提交审批应⽤服务。
- 领域层:领域服务有查询审批规则、修改请假流程信息服务、根据审批规则查询审批⼈,分别位于请假和⼈员组织关系聚合。请假单实体有修改请假流程信息⽅法,审批规则值对象有查询审批规则⽅法。⼈员实体有根据审批规则查询审批⼈⽅法。下图是我们分析出来的服务以及它们之间的依赖关系。
-
-
-
- 聚合中的对象
-
-
- 请假聚合关系图(请假单是聚合根)
- 请假聚合关系图(请假单是聚合根)
-
-
- 对象清单
- 对象清单
- 设计微服代码结构
-
-
应用层的结构:应⽤层包括:应⽤服务、DTO以及事件发布相关代码。在LeaveApplicationService类内实现与聚合相关的应⽤服务,在LoginApplicationService封装外部微服务认证和权限的应⽤服务。
-
领域层的结构:包括⼀个或多个聚合的实体类、事件实体类、领域服务以及⼯⼚、仓储相关代码。⼀个聚合对应⼀个 聚合代码⽬录,聚合之间在代码上完全隔离,聚合之间通过应⽤层协调。
-
后续工作
- 详细设计:实体属性、数据库表和字段、实体与数据库表映射、服务参数规约及功能实现等。
- 代码开发和测试:开发⼈员只需要按照详细的设计⽂档和功能要求,找到业务功能对应的代码位置,完成代码开发就可以了。
19、总结(一):微服务设计和拆分要坚持哪些原则?
20、总结(二):分布式架构关键设计10问
结束语|所谓高手,就是跨过坑和大海!