DDD 实战
DDD 架构设计
- 微服务
- 在单机和集中架构这两种模式下, 软件无法快速响应需求和业务的变化, 导致错失发展良机
- 微服务架构很好的实现应用之间的解耦, 解决单体应用扩展性和弹性伸缩能力不足, 小规模团队的敏捷开发等问题
- 在得到这些好处的同时, 潜在的, 微服务在实践中产生了很多争论和疑惑
- 微服务的粒度应该多大?
- 微服务到底应该如何拆分和设计? (缺乏原则和方法论)
- 微服务到底怎么拆分和设计才算合理, 拆多小才叫微服务
- 微服务的边界在哪里?
- 目前没有一套系统的理论和方法来指导微服务的拆分
- 包含微服务架构模式的提出者 Martin Fowler, 也没有告诉我们究竟应该如何拆分微服务
- 微服务拆分的困境产生的根本原因是 不知道业务或微服务的边界在什么地方
- 确定了业务边界和应用边界, 这个困境也就解除了
- 中台
- 作为中台, 需要将 通用的可复用的业务能力 沉淀到中台业务模型, 实现 企业级能力复用
- 中台的本质是业务模型, 微服务是业务模型的落地, DDD 是一种设计思想
- DDD 强调领域模型和微服务设计的一致性, 先有领域模型然后才有微服务, 而不是脱离领域模型来谈微服务设计
- 通过战略设计, 建立领域模型, 划分微服务边界
- 通过战术设计, 从领域模型转向微服务设计和落地
- DDD 进行微服务设计
- DDD 分层架构
- 通过领域事件解耦微服务
- 微服务分层设计
- 层与层之间的服务协作
- 中台设计的核心思想
- 前中后台的协同融合
- DDD 的核心思想是通过领域驱动设计方法定义领域模型, 从而确定业务和应用边界, 保证 业务模型和代码模型 的 一致性, DDD 不是架构, 是一种架构设计方法论
- 试图分离技术实现的复杂性, 围绕业务概念建模, 控制业务的复杂性, 解决软件难以理解, 难以演进的问题
- 通过边界划分将复杂业务领域简单化
- 辅助设计出清晰的领域和应用边界
- DDD 包含战略设计和战术设计两个部分
- 战略设计主要从业务视角出发, 建立业务领域模型, 划分领域边界, 建立通用语言的限界上下文
- 限界上下文可以作为微服务设计的参考边界
-
事件风暴 是建模的主要方法, 从一个发散到收敛的过程
- 通过用例分析,场景分析,用户旅程分析
- 尽可能全面不遗漏的分解业务领域, 梳理领域对象之间的关系, 这是一个发散的过程
- 在事件风暴过程中产生很多的实体, 命令, 事件等领域对象
- 将这些领域对象从不同的维度进行聚类, 形成聚合, 限界上下文等边界, 建立模型, 这是一个收敛的过程
- 聚合是第一层边界
- 限界上下文是第二次边界 (可能就是未来微服务的边界)
- 通过用例分析,场景分析,用户旅程分析
- 战术设计则从技术视角出发, 侧重于 领域模型的技术实现, 完成软件的开发和落地
- 聚合根, 实体, 值对象, 领域服务, 应用服务和资源库等代码逻辑的设计和实现
- 从业务模型向微服务落地的过程中, 将领域模型中的领域对象和代码模型中的代码对象 建立映射关系
- 将业务架构和系统架构进行绑定
- 当我们去响应业务变化调整业务架构和领域模型时, 系统架构也会同时发生调整, 并同步建立新的映射关系
- 战略设计主要从业务视角出发, 建立业务领域模型, 划分领域边界, 建立通用语言的限界上下文
- DDD 分层架构
- 演进式架构
- 根据业务发展, 合理划分领域边界, 持续调整现有架构, 优化现有代码, 以保持架构和代码的生命力
- DDD 与微服务的关注点不同
- DDD 重点关注从业务领域视角划分领域边界, 构建通用语言进行高效沟通, 通过业务抽象, 建立领域模型, 维持业务和代码的逻辑一致性
- 微服务重点关注运行时的进程间通信, 容错和故障隔离, 实现去中心化数据管理和去中心化服务治理, 关注微服务的独立开发, 测试, 构建, 部署
DDD 的核心概念
-
领域
- 领域就是用来确定业务范围 (范围即边界), 并 在这个边界内解决业务问题的领域
-
子域
- 领域进一步划分为多个子领域 (子域)
- 每个子域对应一个更小的问题域或更小的业务范围
- 核心思想就是将问题域逐步分解, 降低业务理解和系统实现的复杂度
- 子域可以根据自身重要性和功能属性划分为三类子域
- 核心域
- 决定产品和公司核心竞争力
- 通用域
- 同时被多个子域使用的通用功能
- 比如认证, 权限
- 支撑域
- 必要的,但不包含以上两者
- 数据字典等
- 核心域
- 划分核心域, 支撑域, 通用域的目的是为了
- 通过领域划分, 区分开不同子域在公司内的功能属性和重要性
- 据此来针对不同的子域采取不同的资源投入和建设策略
-
注意 这里对于不同的角色(或组织), 在不同的场景下, 对核心域的理解是不同的
- 很多公司的业务, 表面看起来相似,
- 但商业模式和战略方向是存在很大差异的, 公司不同阶段的关注点也会不一样
- 要结合公司战略重点和商业模式, 找到核心域, 且 重点关注和优先投入核心域
- 将核心域的建设排在首位, 有绝对的掌控能力和自主研发能力
- 资源有限的情况下, 可以在支撑域或通用域上通过采购/外部合作点方式来想想办法
- 很多公司的业务, 表面看起来相似,
- 通过领域划分, 区分开不同子域在公司内的功能属性和重要性
-
限界上下文
- 通用语言定义 上下文含义, 限界上下文定义 领域边界
- 不同的角色(领域专家/产品/项目/开发/测试), 对相同的领域知识有不同的理解, 交流起来存在障碍
- 领域模型存在于边界之内
- 通用语言
- 团队交流达成共识的, 能够简单, 清晰, 准确描述业务涵义和规则的语言就是通用语言
- 通用语言是团队统一的语言, 不管在团队中承担什么角色, 在同一个领域的软件全生命周期里使用统一语言进行交流
- 确保业务需求的正确表达, 确保语义的唯一性
- 交流中出现 "不知道", "不一定"是不同的概念, 拥有不同的含义
- 设计过程中我们可以使用一些表格, 来记录事件风暴和微服务设计过程中产生的领域对象及其属性
- 要确保 业务模型和代码模型的一致, 实现业务语言与代码语言的统一
- 确保业务需求的正确表达, 确保语义的唯一性
- 限界上下文
- DDD 在战略设计上提出了 "限界上下文" 这个概念, 用来 确定语义所在的领域边界
- 限界即 领域的边界, 上下文即 语义环境
- 我们在统一的领域边界内用统一的语言来进行交流
- 用来封装通用语言和领域对象, 提供上下文环境, 保证在领域之内的一些术语, 业务相关的对象 (通用语言) 有一个确切的含义
- 定义了模型的适用范围, 即团队所有成员能够明确地知道什么应该在模型中实现, 什么不应该在模型中实现
- 语言离不开它的语义环境
- "今天应该穿几件衣服呀?"
- "能穿多少就穿多少!"
- 我们不大可能用过一个简单的术语没有歧义地去描述一个复杂的业务领域
- 而限界上下文就是用来细分领域, 从而定义通用语言所在的边界
- "今天应该穿几件衣服呀?"
- 每个领域模型都有它对应的限界上下文
- 子域可能包含多个限界上下文, 也有可能子域本身的边界就是限界上下文的边界
- 理论上限界上下文就是微服务的边界
- 限界上下文是微服务设计和拆分的主要依据
- 微服务的拆分还是有很多限制因素的 (技术异构, 团队沟通等外部因素)
- 通用语言定义 上下文含义, 限界上下文定义 领域边界
-
实体和值对象
- 实体和值对象是组成领域模型的基础单元
- 实体一般对应业务对象, 具有 业务属性和业务行为
- 值对象主要是属性集合, 对 实体的状态和特征进行描述
- 实体
- 它们拥有 唯一标识符, 重要的不是其属性, 而是其延续性和标识
- 对象的延续性和标识会跨越甚至超过软件的生命周期
- 实体一般会持久化, 但与数据库持久化对象不一定是一对一的关系
- 实体可以引用聚合内的聚合根, 其他实体和值对象
- 实体的形态
- 业务形态
- 按照一定的业务规则将依存度高和业务关联紧密的多个实体对象和值对象进行聚类, 形成聚合
- 代码形态
- 在 DDD 中, 这些实体类通常采用充血模型
- 与这个实体相关的所有业务逻辑都在实体类中实现
- 跨多个实体的领域模型则在领域服务中实现
- 在 DDD 中, 这些实体类通常采用充血模型
- 运行形态
- 只有拥有相同的 ID, 仍然是同一个实体
- 我们对一个实体对象进行多次修改, 修改后的数据和原来的数据很可能不同
- 只有拥有相同的 ID, 仍然是同一个实体
- 实体的数据库形态
- DDD 先构建领域模型, 针对实际业务场景构建实体对象和行为, 再将实体对象映射到数据库持久化对象
- 大部分情况下实体与持久化对象是一对一的
- 一个实体可能对应 0 个, 1 个或多个数据库持久化对象
- 1..0
- 有些实体只是暂驱静态内存中的一个运行时实体, 它不需要持久化
- 1..n (即一个实体对应两个持久化对象)
- 基于多个价格配置数据计算后生成的折扣实例
- 权限实体由用户和角色两个持久化对象生成
- n..1 (即多个实体对应一个持久化对象)
- 为了避免数据库的联表查询, 提升系统性能, 会将客户信息和账户信息两类数据保存到同一张数据库表中
- 客户和账户两个实体可根据需要从一个持久化对象中生成
- 1..0
- DDD 先构建领域模型, 针对实际业务场景构建实体对象和行为, 再将实体对象映射到数据库持久化对象
- 业务形态
- 它们拥有 唯一标识符, 重要的不是其属性, 而是其延续性和标识
- 值对象
- 特点
- 无 ID
- 通过属性值来判断其相等性
- 不可变
- 无生命周期
- 用完即扔
- 值对象尽量只引用值对象
- 无 ID
- 在 DDD 中用来描述领域的特定方面, 并且是一个 没有标识符 的对象
- 通过对象属性值来识别的对象
- 值对象描述了领域中的一件东西, 这个东西是不可变的
- 值对象创建后就不允许修改了, 只能用另一个值对象来整体替换
- 将多个相关属性组合为一个整体概念
- 本质上是一个对象属性的集合
- 属性用于描述实体的特征, 具有整体概念和不可修改
- 集合保证属性归类的清晰和概念的完整, 避免属性零碎
- 物理上独立出来, 逻辑上仍然是实体属性的一部分
- 本质上是一个对象属性的集合
- 业务形态
- 实体是看得见, 摸得着的实实在在的业务对象
- 实体具有业务属性, 业务行为和业务逻辑
- 值对象不包含业务逻辑
- 只有数据初始化操作和有限的不涉及修改数据的行为
- 共享的标准类型的值对象
- 比如数据字典
- 拥有自己的限界上下文
- 有自己的持久化对象
- 实体是看得见, 摸得着的实实在在的业务对象
- 代码形态
- 值对象是单一属性, 直接定义为实体类的属性
- 值对象是多个属性的集合 (具有整体概念), 整体被实体引用
- 运行形态
- 属性展开嵌入到实体中
- 会导致实体堆积一堆缺乏概念完整性的属性, 这些值对象会失去业务涵义, 操作起来不方便
- 整体序列化成一个大对象
- 字段本身序列化为 JSON
- 无法满足基于值对象的快速查询, 会导致搜索值对象属性值变得异常困难
- 字段本身序列化为 JSON
- 属性展开嵌入到实体中
- 数据库形态
- 以 "数据建模为中心" 转换到 "领域模型为中心"
- 原则
- 减少数据库表的数量和表与表之间负载的依赖关系
- 尽可能的简化数据库设计, 提升数据库性能
- 我们可以将部分对象设计为值对象, 保留对象的业务涵义, 同时减少了实体的数量
- 数据建模时, 我们将值对象嵌入实体, 减少实体表的数量, 简化数据库设计
- 值对象的属性值和实体对象的属性值保存在同一张数据库表中
- 特点
- 实体和值对象是组成领域模型的基础单元
-
聚合和聚合根
- 让实体和值对象协同工作来完成业务逻辑
- 并确保在实现时数据的一致性
- 聚合就是由业务和逻辑紧密关联的实体和值对象组合而成
- 聚合是数据修改和持久化的基本单元, 每个聚合对应一个仓储, 实现数据的持久化
- 聚合有一个聚合根和上下文边界
- 根据业务单一职责和高内聚低耦合的原则
- 聚合内(实体和值对象)是高内聚的, 聚合边界是松耦合
- 根据业务单一职责和高内聚低耦合的原则
- 聚合在 DDD 分层架构中属于领域层
- 聚合内实体以充血模型实现个体业务能力, 以及业务逻辑的高内聚
- 跨多个实体的业务逻辑通过领域服务来实现
- 跨多个聚合的业务逻辑通过应用服务来实现 (在应用层通过组合来实现)
- 聚合根
- 为了避免由于复杂数据模型缺乏统一的业务规则控制, 而导致聚合, 实体之间数据不一致的问题
- 传统数据模型每一个实体都是对等的
- 任由实体进行无控制地调用和数据修改, 很可能导致实体之间数据逻辑的不一致
- 采用锁的方式则会增加软件的复杂度, 也会降低系统的性能
- 找到聚合根
- 聚合根是实体
- 有独立的生命周期
- 有全局的唯一 ID
- 实体在聚合内唯一即可
- 生命周期由聚合根管理
- 实体在聚合内唯一即可
- 一个聚合只有一个聚合根
- 在聚合内对实体和值对象采用直接对象引用的方式进行组织和协调
- 聚合根与聚合根之间通过 ID 关联的方式实现聚合之间的协同
- 聚合的设计原则
- 在一致性边界内建模真正的不变条件
- 聚合用来封装真正的不变性
- 聚合内有一套不变的业务规则
- 各实体和值对象按照统一的业务规则运行, 实现对象数据的一致性
- 优先设计小聚合
- 聚合过大(包含过多的实体), 导致实体之间的管理过于复杂
- 高频操作时会出现并发冲突或数据库锁, 最终导致系统可用性变差
- 通过唯一标识引用其它聚合
- 聚合之间通过关联外部聚合根 ID 的方式进行引用, 而不是直接对象引用的方式
- 在边界之外使用最终一致性
- 聚合内数据强一致性, 聚合之间数据最终一致性
- 在一次事务中, 最多只能更改一个聚合的状态
- 如果一次业务操作涉及多个聚合状态的修改, 应采用领域事件的方式异步修改相关的聚合, 实现聚合之间的解耦
- 在应用层实现跨聚合的服务调用
- 避免跨聚合的领域服务调用和跨聚合的数据库表关联
- 未来可能以聚合为单位进行微服务的组合和拆分
- 避免跨聚合的领域服务调用和跨聚合的数据库表关联
- 聚合作为微服务最小的拆分单元
- 一个微服务一般包括多个聚合
- 聚合之间的边界是微服务内的逻辑边界
- 在微服务架构演进时以聚合为单位进行拆分和组合
- 不建议对微服务进行过度拆分
- 对性能有极致要求的场景, 独立为一个微服务, 以满足版本的高频发布和极致的弹性伸缩能力
- 一个微服务一般包括多个聚合
- 在一致性边界内建模真正的不变条件
- 让实体和值对象协同工作来完成业务逻辑
-
领域事件
- 表达领域中发生的事件
- 发生后通常会导致进一步的业务操作
- 比如, 当 密码连续输错 3 次 的时候, 会触发 锁定账号 的动作
- 领域事件驱动切断领域模型之间的强依赖
- 维护领域模型的独立性和数据的一致性
- 微服务之间的数据不必要求强一致性, 而是基于事件的最终一致性
- 事件发布完成之后, 发布方不必关心后续订阅事件处理是否成功
- 维护领域模型的独立性和数据的一致性
- 发生后通常会导致进一步的业务操作
- 微服务内的领域事件
- 一般发生在同一个进程内, 尽量不要引入消息中间件
- 微服务内的事件总线, 会增加开发的复杂度, 要结合应用复杂度和收益进行综合考虑
- 微服务内的应用服务, 可以通过跨聚合的服务编排和组合, 以服务调用的方式完成跨聚合的访问
- 采用分布式事务, 以保证发布方和订阅方的数据都更新成功
- 一般发生在同一个进程内, 尽量不要引入消息中间件
- 微服务之间的领域事件
- 在不同的限界上下文或领域模型之间实现业务协作
- 通过领域事件驱动的异步化机制, 主要目的是实现微服务解耦
- 减轻微服务之间服务访问的压力, 提升用户体验
- 通过领域事件驱动的异步化机制, 主要目的是实现微服务解耦
- 可以采用服务直接调用的方式, 实现数据和服务的实时访问
- 弊端就是跨微服务的数据同时变更需要引入分布式事务, 以确保数据的一致性
- 分布式事务机制会影响系统性能, 增加微服务之间的耦合, 应该尽量避免使用分布式事务
- 引入消息中间件
- 确保消息至少被消费一次
- 弊端就是跨微服务的数据同时变更需要引入分布式事务, 以确保数据的一致性
- 事件的构建和发布
- 事件唯一标识(全局)
- 事件的基本属性 (记录事件自身以及事件发生背景的数据)
- 发生时间
- 事件类型和事件源
- 事件的业务属性
- 用于记录事件发生那一刻的业务数据
- 事件实体对象依赖聚合根
- 领域事件发生后, 事件中的业务数据不再修改
- 业务数据可以以序列化值对象的形式保存
- 方便消息中间件中解析和获取
- 事件的发布
- 发布事件到事件总线或者消息中间件
- 从事件表中利用定时程序或数据库 binlog 日志捕获技术获取增量事件数据
- 事件数据的持久化
- 用于系统之间的数据对账, 实现发布方和订阅方事件数据的审计
- 遭遇到消息中间件, 订阅方系统宕机或网络中断的故障, 故障恢复后仍可继续后续业务流转, 保证数据的一致性
- 本地事件表, 利用本地事务保证业务和事件数据的一致性
- 共享的事件数据库, 需要引入分布式事务机制保证业务和事件数据的 强一致性
- 用于系统之间的数据对账, 实现发布方和订阅方事件数据的审计
- 事件总线
- 实现 微服务内聚合 之间领域事件的重要组件, 提供事件分发和接受服务
- 进程内模型, 会在微服务内聚合之间遍历订阅者列表, 采用同步或异步的模式传递数据
- 消息中间件
- 跨微服务的领域事件大多用到消息中间件, 实现跨微服务的事件发布和订阅
- 消息中间件产品非常成熟, 可选的技术组件非常多, 比如 Kafka, RabbitMQ
- 在领域服务中实现事件的接受和处理
- 跨微服务的领域事件大多用到消息中间件, 实现跨微服务的事件发布和订阅
- 在不同的限界上下文或领域模型之间实现业务协作
- 表达领域中发生的事件
-
DDD 分层架构
- 微服务架构模型
- 整洁架构
- CQRS
- 六边形架构
- DDD 分层架构
- 架构边界变得越来越清晰
- 核心原则, 每层只能与位于其下方的层发生耦合
- 4 层架构
- 用户接口层
- 用户显示信息
- 用户可以是人/自动化程序/脚本等
- 解释用户指令
- 用户显示信息
- 应用层
- 很薄的一层
- 理论上不应该有业务规则或逻辑
- 主要面向用例和流程相关的操作
-
服务编排, 组合, 转发
- 协调多个聚合服务和领域对象完成业务操作
- 调用其它微服务的应用服务
- 不要把本该放在领域层的业务逻辑放到应用层来实现
- 庞大的应用层会使模型失焦
- 应用服务可以进行安全认证, 权限校验, 事务控制, 发送或订阅领域事件等
- 很薄的一层
- 领域层
- 包含聚合根, 实体, 值对象, 领域服务等领域模型中的领域对象
- 领域模型的业务能力
- 用它来表达业务概念, 业务状态和业务规则
- 业务逻辑主要是由实体和领域服务来实现
- 实体采用充血模型来实现所有与之相关的业务功能
- 实体和领域对象在实现业务逻辑上不是同级
- 领域服务组合聚合内的多个实体 (或值对象) , 实现复杂的业务逻辑
- 基础层
- 为其他各层提供通用的技术和基础服务
- 最常见的是提供数据持久化
- 还包括第三方工具, 驱动, 消息中间件, 网关, 文件, 缓存等
- 依赖倒置设计
- 包含基础服务, 实现应用层, 领域层与基础层的解耦, 降低外部资源变化对应用的影响
- 为其他各层提供通用的技术和基础服务
- 用户接口层
- 每种架构模式虽然提出的时代和背景不同
- 核心理念都是为了设计出 "高内聚低耦合" 的架构
- 轻松实现架构演进
- DDD 分层架构如何推动架构演进
- 领域模型不是一成不变的,业务的变化会影响领域模型, 而领域模型的变化则会影响微服务的功能和边界
- 领域模型的对象层次从内到外
- 值对象 -> 实体 -> 聚合 -> 限界上下文
- 实体或值对象的简单变更, 一般不会让领域模型或微服务发生大的变化
- 聚合的重组和拆分, 将引起业务模块和系统功能的变化
- 领域模型的对象层次从内到外
- 聚合作为一个整体,
- 在不同的领域模型之间重组或拆分 (领域模型发生变更)
- 或者直接将一个聚合独立为一个微服务(面临性能瓶颈)
- 微服务内服务的演进
- 领域服务 组合和封装 实体的方法
- 应用服务 组合和封装 领域服务
- 领域层通常只提供原子服务
- 随着系统功能增强和外部接入越来越多, 应用服务需要进行整理
- 当两个领域服务同时多次被多个应用服务调用, 可以考虑将其合并, 并 下沉到领域层, 演进成新的领域服务
- 减少服务的数量, 降低上层服务组合和编排的复杂度
- 随着系统功能增强和外部接入越来越多, 应用服务需要进行整理
- 通过分层解耦依赖, 变化落到最适合的层中去解决
- 将业务逻辑拆分到了应用层和领域层
- 应用层快速响应前端的变化
- 领域层实现领域模型的能力
- 将业务逻辑拆分到了应用层和领域层
- 领域模型不是一成不变的,业务的变化会影响领域模型, 而领域模型的变化则会影响微服务的功能和边界
- 微服务架构模型
-
微服务架构模型
- 整洁架构
- 又名 "洋葱架构"
- 最重要的原则是依赖原则
- 定义了各层的依赖关系
- 越往里依赖越低, 代码级别越高, 越是核心能力
- 外圆代码依赖只能指向内圆, 内圆不需要知道外圆的任何情况
- 各层的职责
- 领域模型实现领域内核心业务逻辑, 它封装了企业级的业务规则
- 领域模型的主体是实体, 一个实体可以是一个带方法的对象, 也可以是一个数据结构和方法集合
- 领域服务实现涉及多个实体的复杂业务逻辑
- 应用服务实现与用户操作相关的服务组合与编排
- 包括了应用特有的业务流程规则
- 封装和实现了系统所有的用例
- 最外层主要提供适配的能力
- 主动适配
- 实现外部用户, 网页, 批处理和自动化测试等对内层业务逻辑访问适配
- 被动适配
- 实现核心业务逻辑对基础资源访问的适配, 比如数据库, 缓存, 文件系统和消息中间件
- 主动适配
- 领域模型实现领域内核心业务逻辑, 它封装了企业级的业务规则
- 六边形架构
- 又名 "端口适配器架构"
- 六边形架构的核心理念
- 应用是通过端口与外部进行交互的
- 微服务架构下 API 网关盛行
- 核心业务逻辑 (应用程序和领域模型) 与外部资源 (包括 app, web 应用已经数据库资源) 完全隔离
- 仅通过适配器进行交互
- 解决了业务逻辑与用户界面的代码交错问题
- 分为两层
- 内六边形实现应用的核心业务逻辑
- 外六边形完成外部应用, 驱动和基础资源等的交互和访问
- 对前端应用以 API 主动适配的方式提供服务
- 对基础资源以依赖倒置被动适配的方式实现资源访问
- 六边形架构的一个端口可能对应多个外部系统
- 不同的外部系统可能会使用不同的适配器
- 由适配器负责协议转换
- 使得应用程序以一致的方式被用户, 程序, 自动化测试和批处理脚本使用
- 不同的外部系统可能会使用不同的适配器
- 三种架构对比分析
- 共性
- 将核心业务逻辑与外部应用, 基础资源进行隔离
- 核心业务逻辑的分层
- 领域层
- 实现面向领域模型, 实现领域模型的核心业务逻辑
- 属于原子模型
- 需要保持领域模型和业务逻辑的稳定
- 对外提供稳定的细粒度的领域服务 (处于架构的核心位置)
- 应用层
- 面向用户的用例和流程编排能力
- 对外提供粗粒度的 API 服务
- 作为配速齿轮位于前台应用和领域层之间
- 领域层
- 都考虑了前端需求的变化与领域模型的不变
- 不管前端如何变化, 企业没有大的变革, 核心领域逻辑基本不会大变, 所以领域模型相对稳定
- 用例和流程则会随着外部应用需求而随时调整
- 架构模式通过分层的方式来控制需求变化从外到里对系统的影响, 从外向里受需求影响逐步减少
- 面向用户的前端可以快速响应外部需求进行调整和发布, 灵活多变
- 应用层通过服务组合和编排来实现业务流程的快速适配上线
- 减少传导到领域层的需求, 使领域层保持长期稳定
- 保证领域层的核心业务逻辑不会因为外部需求和流程的变动而调整, 帮助建立前台灵活, 中台稳固的架构
- 面向用户的前端可以快速响应外部需求进行调整和发布, 灵活多变
- 中台和微服务设计
- 设计的关键
- 领域模型和微服务的合理分层设计
- 中台需要站在全企业的高度考虑能力的共享和复用
- 中台设计时, 我们需要建立中台内所有限界上下文的领域模型
- 聚焦领域模型, 将它放在核心位置
- DDD 建模过程中会考虑架构演进和功能的重新组合
- 领域模型建立的过程会对业务和应用进行清晰的逻辑和物理边界 (微服务) 划分
- 领域模型的结果会影响到后续的系统模型, 架构模型和代码模型, 最终影响到微服务的拆分和项目落地
- 中台设计时, 我们需要建立中台内所有限界上下文的领域模型
- 微服务要有合理的架构分层
- 微服务设计要有分层的设计思想, 让各层各式其职, 建立松耦合的层间关系
- 不要把与领域无关的逻辑放在领域层实现, 保证领域层的纯洁和领域逻辑的稳定, 避免污染领域模型
- 不要把与领域模型的业务逻辑放在应用层, 这样会导致应用层过于庞大, 最终领域模型会失焦
- 引入防腐层, 进行新老系统适配和转换, 过渡期完成后, 可以直接将防腐层代码抛弃
- 微服务设计要有分层的设计思想, 让各层各式其职, 建立松耦合的层间关系
- 微服务之间的服务集成
- 项目级微服务
- 同前端应用集成, 一起完成特定的业务
- 集成发生在应用层
- 企业级中台微服务
- 将职责单一的中台微服务组合起来
- 增加一层, BFF(服务于前端的后端)
- 处理跨中台微服务的服务组合和编排, 以及微服务之间的协调
- 项目级微服务
- 应用和资源的解耦与适配
- 应用层, 领域层和基础层解耦是通过仓储模式, 采用依赖倒置的设计方法来实现
- 设计的关键
- 共性
- 整洁架构
-
平台与中台
- 阿里中台
- 业务中台的前身是共享平台
- 当做资源团队, 承接各业务方的需求, 并为业务方在基础服务商做定制开发
- 阿里业务中台的目标是把核心服务链路整体当做一个平台产品来做
- 包括会员, 商品, 交易, 营销, 店铺, 资金结算
- 为前端业务提供的是 业务解决方案, 而不是彼此独立的系统
- 阿里前中后台定位
- 前台主要面向客户以及终端销售者, 实现营销推广以及交易转化
- 中台主要面向运营人员, 完成运营支撑
- 后台主要面向后台管理人员, 实现流程审核, 内部管理以及后勤支撑
- 比如采购, 人力, 财务和 OA 系统
- 业务中台的前身是共享平台
- 传统企业大平台战略
- 平台只解决公共能力复用的问题, 离中台的目标还差一段差距
- 平台只是将部分通用的公共能力独立为共享平台
- 但并没有和企业内的其他平台或应用, 实现页面, 业务流程和数据端到端的全面融合
- 没有将核心业务服务链路作为一个整体方案考虑
- 各平台仍然是分离且独立的
- 中台
- 中台来源于平台, 中台和平台相比, 更多体现的是一种理念的转变
- 对前台业务的 快速响应
- 企业级复用能力
- 从前台, 中台到后台的设计, 研发, 页面操作, 流程服务和数据的 无缝联通, 融合能力
- 中台就是企业级能力复用平台
- 共享
- 联通
- 前台以及中台之间的联通
- 融合
- 前台流程和数据的融合
- 创新
- 所有的基础服务用中台的思路建设, 进行联通, 共同支持上端的业务
- 业务中台
- 更多的是支持在线业务
- 通用能力中心
- 对应 DDD 的通用域或支持域
- 实现通用能力的沉淀, 共享和复用
- 核心能力中心
- 对应 DDD 的核心域
- 需要解决核心业务链路的联通和不同渠道服务共享的问题
- 对于传统企业非常重要, 以满足不同聚道的核心业务能力共享和复用的需求
- 考虑前台,中台及后台应用的协同
- 实现不同渠道应用的前端页面, 流程和服务的共享
- 前台作为作战部队, 需要根据前线的战场需求, 对业务中台的能力进行调度
- 实现能力融合和效率最大化
- 中台好比陆军, 火箭军, 空军等专业的军种, 发挥战术专业能力
- 数据中台就是信息情报中心和联合作战总指挥部, 汇集各种数据, 完成分析, 制定战略和战术计划
- 后台就是后勤部队, 提供技术支持
- 不管后端有多少个中台, 前端用户感受到的就是只有一个前台
- 数据中台
- 提供基础数据处理能力和很多的数据产品给所有业务方使用
- 打通各业务 (微服务拆分) 之间的数据孤岛, 实现数据融合共享与业务创新
- 实现企业全域数据的采集和存储, 实现各不同业务类型中台数据的汇总和集中管理
- 按照标准的数据规范和数据模型, 将数据按照不同主题域或场景进行加工和处理
- 形成面向不同主题和场景的数据应用, 比如客户视图, 代理人视图, 渠道视图, 机构视图等不同数据体系
- 建立业务需求驱动的数据体系, 基于各个维度的数据, 深度荟取数据价值, 支持业务和商业模式的创新
- 建设步骤
- 实现各中台业务数据的汇聚, 解决数据孤岛和初级数据共享问题
- 实现企业级实时和非实时全维度数据的深度融合, 加工和共享
- 萃取数据价值, 支持业务创新, 加速从数据转换为业务价值的过程
- 算法中台
- 业务中台
- 数字化转型中台应该共享什么
- 传统企业的中台建设策略与阿里中台战略有差异, 需要共享的内容不一样
- 传统企业的商业模式和 IT 系统建设发展的历程与互联网企业不完全一样
- 传统企业的中台建设策略与阿里中台战略有差异, 需要共享的内容不一样
- 微前端设计思想
- 根据核心链路和业务流程, 通过对微前端页面的动态组合和流程编排, 实现前台业务的融合
- 前端页面可以很自然的融合到不同的终端和渠道应用核心业务链路中, 实现前端页面, 流程和功能复用
- 传统系统的问题
- 单体系统的问题
- 忽高忽低的互联网业务场景
- 存在扩展性和缺乏弹性伸缩能力
- 数据类应用
- 多数通过 ETL 工具抽取数据实现数据建模, 统计和报表分析功能
- 数据的时效和融合能力不够, 再加上传统数据类应用本来就不是为前端而生的, 因此难以快速响应前端一线业务
- 多数通过 ETL 工具抽取数据实现数据建模, 统计和报表分析功能
- 单体系统的问题
- 业务中台的建设
- 可采用领域驱动设计方法, 通过领域建模, 将可复用的公共能力从各个单体剥离, 沉淀并组合
- 采用微服务架构模式, 建设成可共享的通用能力平台
- 微服务的好处和坏处
- 提升了应用的弹性和高可用能力
- 由于微服务的物理隔离, 原来一些系统内的调用会变成跨微服务调用
- 微服务的拆分会导致数据进一步分离, 增加企业级应用集成的难度
- 处理不好前中后台的关系, 将会进一步加剧前后流程和数据的孤岛化, 碎片化
- 后台中实现内部管理的要求
- 很多人习惯性将这些管理要求嵌入到核心业务流程中
- 一般来讲, 内控管理需求对权限, 管控规则和流程等要求比较高
- 在设计流程审核和管理类功能的时候, 我们可以考虑按角色或岗位进行功能聚合, 将复杂的管理需求从通用的核心业务链路中剥离
- 参考小程序的建设模式, 通过特定程序入口嵌入前台 app 或应用中
- 很多人习惯性将这些管理要求嵌入到核心业务流程中
- 中台来源于平台, 中台和平台相比, 更多体现的是一种理念的转变
- 阿里中台
-
DDD, 中台和微服务
- 中台是抽象出来的业务模型
- 中台在企业架构上更多偏向业务模型, 形成中台的过程实际上也是业务领域不断细分的过程
- 在这个过程中我们将同类通用的业务能力通过聚合和业务重组, 再根据限界上下文和业务内聚的原则建立领域模型
- DDD 作为方法论可以同时指导中台业务建模和微服务建设
- 中台业务抽象的过程就是业务建模的过程, 对应 DDD 的战略设计
- 核心中台设计时考虑核心竞争力
- 通用中台要站在企业高度考虑共享和复用能力
- 在某个子域下, 根据用例, 业务场景或用户旅程完成事件风暴, 找出实体, 聚合和限界上下文
- 依次进行领域分解, 建立领域模型
- 检查是否存在重复或重组的领域对象, 功能, 提炼并重构主领域模型
- 一个不可分割的领域模型可以映射为一个微服务
- 系统抽象实现的过程就是微服务的建设过程, 对应 DDD 的战术设计
- 中台业务抽象的过程就是业务建模的过程, 对应 DDD 的战略设计
- DDD 的本质
- DDD 按照一定的规则将业务领域进行细分, 领域细分到一定的程度后, DDD 会将问题范围限界在特定的边界内
- 并在这个边界内建立领域模型
- 进而用代码实现该领域模型
- DDD 按照一定的规则将业务领域进行细分, 领域细分到一定的程度后, DDD 会将问题范围限界在特定的边界内
- 中台的本质
- 提炼各个业务板块的共同需求, 进行业务和系统抽象, 形成通用的可复用的业务模型, 打造成组件化产品
- 前台要做什么业务, 需要什么资源, 可以直接找中台, 不需要每次都去改动低层
- 中台是抽象出来的业务模型
-
如何用 DDD 重构中台业务模型
- 为了保证业务模型的完整性, 在构建中台业务模型时, 考虑将两部分模型重组为一个完整的业务模型
- 面向移动互联网用户和面向柜台传统业务
- 在构建中台业务模型时, 互联网电商平台和传统核心功能独立建设
- 对不同的渠道分别对待
- 传统核心应用主要面向柜台, 不需要互联网电商平台的在线客户、话务、订单和购物车等功能
- 互联网电商平台主要面向个人客户, 不需要后端比较重的再保、佣金、打印等功能
- 将面向后端业务管理的应用沉淀到后台,将前端能力构建为面向互联网渠道的通用中台, 比如订单等
- 对不同的渠道分别对待
- 中台按照"高内聚, 低耦合"的原则, 实现企业级的能力复用
- 把相关的业务行为聚集在一起, 把不相关的行为放在其他地方
- 站在企业高度, 将重复的需要共享的通用能力, 核心能力沉淀到中台, 将分离的业务能力重组为完整的业务板块
- 前端个性能力归前端
- 后端管理能力归后台
- 建模策略
- 自顶向下
- 先做顶层设计
- 从最高领域逐级分解为中台, 分别建立领域模型
- 根据业务属性分为通用中台和核心中台
- 主要基于业务现状, 不考虑系统现状
- 适用于全新的应用系统建设, 或旧系统推倒重建的情况
- 先做顶层设计
- 自低向上
- 基于业务和系统现状完成领域建模
- 首先分别完成系统所在业务域的领域建模
- 对齐业务域, 找到具有同类或相似业务功能的领域模型
- 对比分析领域模型的差异, 重组领域对象, 重构领域模型
- 沉淀公共和复用的业务能力, 将分散的业务模型整合
- 适用于遗留系统业务模型的演进式重构
- 基于业务和系统现状完成领域建模
- 自顶向下
- 建模过程
- 分域建模型, 找准基准域, 划定上下文, 聚合重归类
- 中台业务模型的重构过程, 也是微服务架构演进的过程
- 业务边界即微服务边界, 业务边界做好了, 微服务的边界也就清晰了
- 为了保证业务模型的完整性, 在构建中台业务模型时, 考虑将两部分模型重组为一个完整的业务模型
-
如何使用事件风暴构建领域模型
-
事件风暴是 DDD 战略设计中经常使用的一种方法
- 它可以快速分析和分解复杂的业务领域, 完成领域建模
-
过程
- 领域专家和项目团队通过头脑风暴的形式, 罗列出领域中所有的领域事件, 整合之后形成最终的领域事件集合
- 对每个事件, 标注出导致该事件的命令, 为每个事件标注出命令发起方的角色
- 命令可以是用户发起, 也可以是第三方系统调用或者定时器触发等
- 最后对事件进行分类, 整理出实体, 聚合, 聚合根以及限界上下文
-
领域专家
- 对业务或问题域有深刻见解的主题专家
- 了解业务和系统是怎么使用的, 也深刻理解为什么要这么设计
- 对业务或问题域有深刻见解的主题专家
-
准备的材料
- 用不同颜色的贴纸区分领域行为
- 蓝色表示命令
- 绿色表示实体
- 橙色表示领域事件
- 黄色表示补充信息
- 外部依赖, 前提假设等
- 用不同颜色的贴纸区分领域行为
-
重点关注业务的语言和行为
- 某些业务动作或行为 (事件) 是否会触发下一个业务动作
- 这个动作 (事件) 的输入和输出是什么
- 是谁 (实体) 发出的什么动作 (命令), 触发了这个动作 (事件)
-
阶段
- 产品愿景
- 用户中台到底能够做什么?
- 业务范围, 目标用户, 核心价值和愿景, 与其他同类产品的差异和优势在哪?
- 产出物
- 为了 (目的) ?
- 管理外部 2B 用户
- 管理外部 2C 用户
- 管理内部业务应用
- 他们的?
- 通过接口获取权限
- 单点登录
- 资源的权限管理
- 记录用户行为和日志
- 是一个?
- 集中管理认证和授权
- 而不是?
- 系统各自授权
- 他可以?
- 减少重复建设
- 终态?
- 逐步覆盖所有业务范围
- 为了 (目的) ?
- 场景分析
- 从用户视角出发
- 梳理业务流程或用户旅程
- 探讨典型的使用场景
- 找出领域事件, 实体, 命令等领域对象
- 尽可能的遍历所有业务细节, 充分发表意见, 不要遗漏业务要点
- 从用户视角出发
- 领域建模
- 找出产生命令的实体
- 分析实体之间的依赖关系组成聚合
- 为聚合划定限界上下文
- 产品愿景
-
微服务的设计
- 原则上一个领域模型就可以设计为一个微服务
- 只能作为微服务拆分的一个重要依据
- 考虑服务的粒度, 分层, 边界划分, 依赖关系和集成关系等非业务因素
- 敏态和维态业务的分离, 非功能需求 (弹性伸缩要求, 安全性等要求)
- 团结组织和沟通效率
- 技术异构
- 比如用户登陆日志数量巨大, 大到需要采用大数据的技术类实现
- 将用户基本信息管理和用户日志管理拆分为两个技术异构的微服务
- 原则上一个领域模型就可以设计为一个微服务
-
-
微服务的代码结构
- 建立标准的微服务代码模型和代码规范
- 更好的理解代码, 更轻松的代码重构和架构演进
- 根据代码规范实现团队协作
- 将领域对象所对应的代码对象放在合适的软件包目录结构中, 业务逻辑从领域层, 应用层到用户接口层逐层封装 (分工) 和协作
- 用户接口层
- 面向前端提供服务适配, 面向资源提供资源适配, 聚集了接口适配相关的功能
- interface
- dto && convertor
- facade
- 应用层
- 实现服务组合和编排, 适应业务流程快速变化的需求, 聚集应用服务和事件相关的功能
- application
- event
- publish
- subscribe
- service
- event
- 领域层
- 实现领域的核心业务逻辑, 聚集了领域模型的聚合, 聚合根, 实体, 值对象, 领域服务和事件等领域对象, 以及他们组合所形成的业务能力
- domain
- aggregate
- entity
- valueobject
- event
- serivce
- repository
- dao
- entity
- aggregate
- 基础设施层
- 为上诉各层提供基础资源服务, 聚集了各种低层资源相关的服务和能力
- infra
- config
- utils
- driver
- eventbus
- mq
- 用户接口层
- 原则
- 聚合之间的代码边界一定要清晰, 通过应用层来组合进行调用
- 不允许聚合之间直接调用领域服务
- 领域模型的核心逻辑代码一定要在领域层实现
- 聚合之间的代码边界一定要清晰, 通过应用层来组合进行调用
- 建立标准的微服务代码模型和代码规范
-
领域模型和代码模型的一致性
- DDD 强调先构建领域模型然后设计微服务
- 保证了领域模型和微服务的一致性
- 对领域对象进行设计和转换, 让领域对象与代码对象建立映射关系
- 通过事件风暴得出
- 领域子模型 -> 聚合 -> 领域对象(类型包括实体,值对象,命令,事件,查询)
- 经过用户故事或领域故事分析, 找出各种角色
- 哪些是聚合根
- 工厂/仓储模式
- 对象的方式引用其他实体
- 存在着有些确实找不到聚合根的情况
- 实体有哪些属性和方法
- 充血模型
- 哪些值对象
- 某些实体的某些属性(集)设计为值对象
- 枚举
- 领域事件
- 领域事件发生在微服务内还是微服务外
- 事件的逻辑处理放在领域层
- 发布和订阅的逻辑放在应用层
- 领域服务
- 一个业务动作或行为跨多个实体
- 设计仓储
- 每一个聚合都有一个仓储
- 用来完成数据查询和持久化操作
- 每一个聚合都有一个仓储
- 应用服务
- 对领域服务的组合和编排
- 这里根据实际发生的调用情况进行重构
- 事件发布与订阅
- 对领域服务的组合和编排
- 哪些是聚合根
- 通过事件风暴得出
- DDD 强调先构建领域模型然后设计微服务
-
微服务的各种边界在架构演进中的作用
- 微服务的设计要涉及逻辑边界, 物理边界和代码边界等
-
演进式架构 就是以支持 增量的, 非破坏性的变更 作为第一个原则
- 同时支持在应用程序结构层面的多维度变化
- 如何判断微服务设计是否合理? 衡量的标准是什么?
- 随着业务的发展或需求的变更, 在不断重复拆分或者组合成新的微服务的过程中, 不会大幅增加软件开发和维护的成本
- 看微服务设计是否能够支持架构长期,轻松的演进
- 微服务不是小单体
- 只是按照业务功能将原来单体应用的一个软件包拆分为多个软件包
- DDD 方法设计的微服务
- 通过限界上下文和聚合实现微服务内外的解耦
- 很容易地实现业务功能搭积木式的重组和模块化的更新
- DDD 的两层边界
- 聚合
- 根据实体对象之间的业务关联性, 业务紧密相关的多个实体进行组合现成聚合体
- 聚合之间是第一层边界
- 限界上下文
- 根据业务及语义边界等因素将一个或多个聚合划定在一个限界上下文内, 形成领域模型
- 限界上下文之间的边界是第二层边界
- 聚合
- 微服务的边界
- 逻辑边界
- 不同聚合之间的边界
- 同一业务领域或应用内紧密关联的对象所组成
- 虚拟的边界, 强调业务的内聚
- 也就意味着每个聚合可以单独领出来变成一个微服务
- 聚合新微服务的最小单位
- 也就意味着每个聚合可以单独领出来变成一个微服务
- 微服务内聚合之间的边界就是逻辑边界
- 业务端以聚合为单位进行业务能力的重组
- 相应的在微服务端以聚合的代码目录为单位进行微服务代码的重组
- 如果某个微服务遭遇到了高性能的挑战, 需要将部分业务能力独立出去, 就可以以聚合为单位, 将聚合代码拆分独立为一个新的微服务
- 可以对多个微服务内有相似功能的聚合进行功能和代码重组, 组合为新的聚合和微服务, 独立为通用微服务
- 不同聚合之间的边界
- 物理边界
- 微服务之间的边界
- 从部署和运行的视角来看待微服务
- 不同的微服务部署位置和运行环境相互物理隔离, 分别运行在不同的进程中
- 关注的是微服务的服务调用, 容错和运行等
- 微服务之间的边界
- 代码边界
- 微服务不同职能代码之间的隔离
- 不同层和聚合之间代码目录的边界
- 强调的是代码之间的隔离, 方便架构演进时代码的重组
- 不同层和聚合之间代码目录的边界
- 微服务不同职能代码之间的隔离
- 微服务的拆分可以参考领域模型, 也可以参考聚合
- 微服务的过度拆分会让软件维护成本上升
- 集成成本/发布成本/运维/监控/问题定位成本
- 项目初期如果不具备较强的微服务管理能力, 不宜做微服务过细拆分
- 当具备一定的业务能力, 业务逻辑和代码边界清晰后, 可以根据拆分出新的微服务
- 微服务内聚合之间的服务调用和数据库依赖需要符合高内聚合低耦合
- 注重平时的设计原则和开发规划, 为后面微服务架构的演进
- 微服务的过度拆分会让软件维护成本上升
- 不同的边界之间能相对需要能够够 match 起来, 只是从不同的视图空间来看待同一个问题
- 逻辑边界
-
如何实现服务和数据在微服务各层之间的协作
-
领域分层
- 根据领域对象的属性和依赖关系
-
服务的协作
- 微服务内跨层服务调用
- 应用服务调用并组装领域服务
- 应用服务直接调用仓储服务
- 主要针对缓存, 文件等类型的基础数据访问
- 主要是查询操作, 没有太多领域逻辑, 不经过领域层, 不涉及数据持久化对象
- 微服务之间服务调用
- 微服务之间的应用服务可以之间调用
- 也可以通过 API 网关访问
- 在进行数据新增和修改操作时, 关注分布式事务, 保证数据的一致性
- 领域事件驱动
- 微服务内的事件
- 通过事件总线 (EventBus) 完成聚合之间的异步处理
- 微服务之间事件
- 通过消息中间件完成
- 异步化的领域事件驱动新一种间接的服务访问方式
- 业务服务逻辑处理 完成之后, 发生领域事件, 可调用事件发布服务, 完成事件发布
- 微服务内的事件
- 微服务内跨层服务调用
-
领域层
- 实体采用充血领域模型, 尽量将业务逻辑归属到实体对象上
- 实在无法归属的部分设计成领域服务
- 领域服务会对多个实体和实体方法进行组装和编排
- 实现跨多个实体的复杂核心业务逻辑
- 实体采用充血领域模型, 尽量将业务逻辑归属到实体对象上
-
应用层
- 应用服务
- 组合和编排服务, 主要来源与领域服务, 可以新外部微服务的应用服务
- 安全认证, 权限校验, 初步的数据校验和分布式事务控制
- 聚合之间的服务调用和数据交互应通过应用服务来完成
- 事件发布和订阅服务
- 应用服务
-
数据对象
- 数据对象在不同的阶段有不同的形态
- VO
- 用于封装展示层指定页面或组件的数据
- DTO
- 前端与应用层或者微服务之间数据组装和传输, 是应用之间数据传输的载体
- DAO
- 数据持久化过程中的载体
- DO
- 微服务运行时的实体, 核心业务的载体
- PO
- 数据持久化过程中的数据载体
- DO 和 PO 不是一一对应的
-
-
微前端设计
- 前端聚合, 后端解耦
- 问题点
- 虽然后端拆分成了微服务, 前端却是一个单体 (用户可不期望安装那么多 app)
- 需要集成成千上万的 API 服务, 需要相当高的沟通成本和技术要求
- 微前端设计
- 将前端页面进行拆分, 同时构建多个可以独立部署, 完全自洽, 松耦合的页面组合
- 其中每个组合只负责特定业务单元的 UI 元素和功能, 这些页面组合就是微前端
- 将前端的单体应用, 按照规则拆分, 并重组为多个可以独立开发, 独立测试, 独立部署和独立运维, 松耦合的微服务
- 适应业务快速变化及分布式多团队并行开发的要求
- 只包含业务单元前端操作必需的页面元素, 它只是企业级完整业务流程中的一个业务拼图块, 不包含页面导航
- 将前端页面进行拆分, 同时构建多个可以独立部署, 完全自洽, 松耦合的页面组合
- 业务单元的组合形态
- 参照领域模型和微服务边界, 建立与微服务对应的前端操作界面
- 业务单元包括微前端和微服务
- 可以自包含地完成领域模型中部分或全部的业务功能
- 微前端和微服务独立部署
- 微前端不宜与过多的微服务组合, 否则容易变成单体前端
- 通过共享微前端可以共享页面的方式与其他微前端页面协作, 完成业务流程
- 订单/支付等微服务对应的订单和支付微前端页面
- 业务单元的功能应该自包含, 业务单元之间的边界清晰
- 业务单元之间要避免功能交叉出现耦合, 一旦出现就会影响项目团队职责边界 (进而影响业务单元独立开发, 测试, 部署和运维等)
- 微前端与前端主页面的集成
- 前端页面是企业级的前端页面
- 微前端是业务单元的前端页面
- 微前端通过主页面的微前端加载器, 利用页面路由和动态加载等技术
- 将特定业务单元的微前端页面动态加载到前端主页面, 实现前端主页面和微前端页面的 "拼图式" 集成
- 团队职责边界
- 前端项目团队只需要完成企业级前端主页面与业务单元的融合, 前端只关注前端主页面和微前端页面之间的集成
- 中台项目团队关注业务单元功能的完整性和自包含能力, 完成业务单元内微服务和微前端开发, 集成和部署, 提供业务单元组件
- 端到端的完成领域逻辑功能开发, 以业务组件的方式整体提供服务
- 业务单元在代码, 逻辑和物理边界都是隔离的, 可降低应用之间的依赖性
- 出现问题时快速定位和修复, 问题控制在一个业务单元内
- 用户体验
- 虽然后端有很多业务单元在支持, 但在用户所有的页面操作和流转是在一个前端主页面完成的
- 前端的融合和中台的解耦
- 虽然后端有很多业务单元在支持, 但在用户所有的页面操作和流转是在一个前端主页面完成的
-
微服务实战
-
战略设计
- 产品愿景
- 通过事件风暴, 对齐产品目标
- 参与者针对每一个要点, 在贴纸上写出自己的意见
- 最后得出
- 用户是谁?
- 给他们带来了什么价值
- 主要功能是什么?
- 做什么不做什么?
- 竞品差异在哪?
- 用户是谁?
- 通过事件风暴, 对齐产品目标
- 场景分析
- 从用户视角
- 业务领域中的典型场景
- 梳理从前端操作到后端业务逻辑发生的所有操作
- 业务流程
- 命令
- 领域事件
- 外部依赖 (假设/条件)
- 梳理从前端操作到后端业务逻辑发生的所有操作
- 业务领域中的典型场景
- 总结所有的场景, 归类
- 从用户视角
- 领域建模
- 找出领域实体和值对象
- 找出聚合根, 根据实体, 值对象同聚合根的依赖关系, 建立聚合
- 根据业务及语义边界等因素, 定义限界上下文
- 产品愿景
-
战术设计
- 服务的识别和设计
- 事件风暴的命令可以理解为微服务对外提供的能力
- 领域服务
- 应用服务
- 意味着可以通过服务组合和编排来完成
- 如果应用服务逻辑复杂, 一个应用服务就可以构建一个类
- 事件风暴的命令可以理解为微服务对外提供的能力
- 聚合中的对象
- 值对象
- 业务流程中的对象
- 其他聚合中的部分信息
- 枚举值类型
- 实体
- 需要持久化
- 值对象
- 详细设计
- ERD
- 实体属性
- 数据库表和字段
- 实体与数据库表映射
- interface
- 先写接口再写实现
- ERD
- 服务的识别和设计
-
微服务演进策略
- 绞杀者策略
- 类似于建筑拆迁, 完成部分新建筑物后, 然后拆除部分旧建筑物
- 修缮者策略
- 类似于古建筑修复, 将存在问题的部分功能重建或者修复后, 重新加入到原有的建筑中, 保持建筑原貌和功能不变
- 另起炉灶
- 大量未知的潜在技术风险和新的开发模式下项目团队磨合等不确定因素
- 微服务拆分的原则
- 从业务视角
- 理论上一个限界上下文内的领域模型可以设计为一个微服务
- 复杂领域, 可以继续拆分为子领域
- 随着业务发展, 可以将聚合作为一个微服务从中拆分出来
- 业务需求变化频率
- 将业务变动较高和功能相对稳定的业务进行分离
- 有效减低频繁变动的敏态业务对稳态业务的影响
- 将业务变动较高和功能相对稳定的业务进行分离
- 从技术视角
- 从应用性能角度
- CQRS
- 从安全边界
- 有特殊安全要求, 比如加解密
- 技术异构
- 大数据架构
- 团队沟通等外部因素
- 从应用性能角度
- 从业务视角
- 绞杀者策略
-