领域驱动设计(DDD)详解:微服务拆分神器

@[TOC]

一、领域驱动设计概念

1、基本概念

(1)通用语言

领域驱动设计,作为一个技术、产品、用户通用的语言进行沟通,极大地降低了沟通成本与沟通失真问题。

(2)领域设计4层模型

(3)DDD适合的场景

DDD既不是UI导向(SMART UI)、也不是数据导向(UML),而是以产品为导向,并不是用户所使用的产品,而是整个产品的业务逻辑。 适合中大型项目、API经济、中台化,可以借鉴DDD进行对微服务进行拆分。

2、领域、子域、界限上下文

领域(Domain):具备一个完整的,在一个市场里面赚钱的能力。比如说二手车市场、电商领域、宠物托管平台。

领域可以进一步划分为子领域。我们把划分出来的多个子领域称为子域,每个子域对应一个更小的问题域或更小的业务范围。 子域(SubDomain):比如支付子域、商品子域、用户认证子域。

界限上下文(Context):所谓上下文,就是为了解决子域的问题的。比如支付上下文,认证上下文。

子域提出问题空间,界限上下文提供解决空间。

3、核心子域、支撑子域、通用子域

核心域:核心域就是一个领域的核心。 比如说电商平台有哪些核心域:产品信息核心域、支付交易核心域、物流域,自然也就对应着产品信息上下文、支付上下文、物流上下文。

支撑子域:支撑核心域正常工作的子域。比如用户行为分析域、风控域,自然也有对应的界限上下文。

通用子域:一些业内通用的子域,比如用户认证系统,可以通过购买第三方的平台来实现。

4、界限上下文的关系

界限上下文的内容,就代表着对应的子域的功能。

界限上下文的上游(U-upstream)提供服务,下游(D-downstream)接收服务。

Conformist:跟随者关系。一定要跟某个上游系统绑定,但别人是主,本系统是从。

ACL(Anticorruption Layer):Open Host Service(RPC、消息队列等)/Published Language(xml、json等) ,反腐层。集成遗留系统,又不能强制老系统更新,新系统要做个适配器层来转换模型。

partnership:更紧密的合作伙伴关系。

Shared Kernel:共享内核。两服务之间紧密合作,代码模型可以提取成通用组件共享。

Separate Ways:分离模式。两个微服务没有任何联系。

Customer Supplier Teams(客户供应者模式):强依赖,上下游系统开发合作顺利,对模型逻辑修改反应迅速。常见于消息队列的两端。

Single Bounded Context(合并上下文模式):单个界限上下文,两服务如一家人,紧密到无法分开。一切模式要素都是共享的。

5、领域模型的要素 - 实体、值对象、聚合

(1)实体

(比如说一个学生) 唯一标识(用户提供、应用生成UUID/GUID、持久化生成)。 数据可变。 生命周期管理。(订单状态管理) 实体的唯一标识是实体与实体,聚合与聚合之间的纽带。

(2)值对象(Value Object)

(比如说一个学生中的某个属性,居住地、性别、性格等等) 无标识。(不唯一) 数据不可变,可复制,可替代。 整体性。(比如:¥100 - 两个概念一个整体,山东省济南市 - 两个概念一个整体) 通常用来做实体的度量和描述。

(3)聚合(Aggregate)

(比如一个班级,有学生、书) 事务一致性边界。(各种动作的数据一致性、行为一致性,比如说所有学生一起上课、下课) 聚合之间通过聚合根(通常为聚合同名实体)进行沟通。 尽量缩小聚合(通常使用最终一致性和领域消息)。(缩小聚合事务复杂度就缩小了) 聚合是创建、发布领域事件和操作资源库的操作主体。

(4)案例分析

6、构建领域模型 - 工厂、库、领域服务

(1)工厂(Factory)

用于创建聚合和实体,可以用工厂类、工厂方法模式、创建者模式来实现。 实现了对象的解耦。 封装复杂操作过程。

(2)资源库(Repository)

实现对聚合的增删改查。 对接持久化机制(如Hibernate)。 和DAO、Mapper类似,但更侧重集合的处理。 封装复杂操作过程。

(3)领域服务(Domain Service)

无状态。 无法归为实体和值对象。 业务操作过程,对领域对象进行转换。 如:密码加密服务、文字转换服务、应收账款和应付账款对账。

7、反腐层

反腐层(Anti-corruption layer,简称 ACL)介于新应用和旧应用之间,用于确保新应用的设计不受老应用的限制。是一种在不同应用间转换的机制。

创建一个反腐层,以根据客户端自己的域模型为客户提供功能。该层通过其现有接口与另一个系统进行通信,几乎不需要对其进行任何修改。因此,反腐层隔离不仅是为了保护你的系统免受异常代码的侵害,还在于分离不同的域并确保它们在将来保持分离。

反腐层是将一个域映射到另一个域,这样使用第二个域的服务就不必被第一个域的概念"破坏"。

二、领域建模方法论

1、企业架构法

2、面向服务设计法(SOA)

3、用例分析法

4、四色建模法

红色:时标型(Moment-Interval)对象。 绿色:PPT(Party/Place/Thing)对象。 黄色:角色(Role)对象。 蓝色:描述(Description)对象。

5、初识Event Storming事件风暴

演进式架构和迭代式开发。 微服务拆分和向前兼容。 如何和产品业务人员沟通。 有没有一个可以在喝茶聊天中完成微服务拆分的方法?

6、领域模型的选择 - 贫血、充血模型

所谓的血,就是业务逻辑。

贫血:getter+setter方法,每个领域并没有太多业务逻辑,更多的业务逻辑在更上层。 充血:更符合领域驱动设计,应用逻辑为主、数据管理为辅。get、set方法是私有的,对外暴露的是更加丰富的有血有肉的方法动作。

贫血模型和充血模型各有优势: 贫血模型:上手快、发展受限,适合应用逻辑简单、信息记录类型的业务。 充血模型:上限高、适合三高项目,适合逻辑复杂、信息处理类型的业务。

7、洋葱圈模型

三、领域事件

1、初识领域事件Domain Event

异步通信,符合事件驱动风格。 通常用消息队列(MQ),可以实现削峰填谷。 但是要处理消息丢失、消息重复的问题。

2、领域事件,代码实例

(1)生产者发布事件

(2)消费者订阅事件

(3)EventStore做事件存储

(4)定时任务轮询投递事件

3、领域事件与CQRS

(1)什么是CQRS

CQRS:Command Query Responsibility Separation。(写和读的责任分离) Command:执行动作,返回void。(行动可能会改变聚合、实体、值对象的内容) Query:只查询,不修改对象状态。

适用CQRS的风格:事件驱动系统风格、管道过滤器风格。

(2)CQRS和ES事件溯源

普通CQRS:做数据的增删改查,对于数据无法溯源。

事件溯源:数据只做增和查,可以做到事件溯源。

四、案例:敏捷项目管理系统

1、功能分析

项目管理系统,涉及项目发布、代办、状态、任务等等。

2、子域划分

3、定义实体、值对象、聚合

(1)聚合根

领域驱动设计中,对外提供功能的只有聚合根的功能,聚合根里面的实体尽量只对聚合根提供服务。 聚合根的子对象,尽量都用实体对象封装。

(2)值对象

值对象不提供独有的ID,全部通过快速复制快速创建,永不修改来实现这些值对象的描述性的信息。

(3)实体

把子对象用实体的形式进行封装,成员变量private,set和get方法private,让它们更加生动的操作protected,让其他成员来访问。,聚合根里面的实体尽量只对聚合根提供服务。

(4)聚合

把聚合根、值对象、实体打包起来,就形成了聚合。

4、落地工厂、库、领域服务

(1)工厂

(2)资源库

(3)领域服务

5、落地反腐层

(1)完整图示

(2)领域服务

(3)适配器:进行适配+调用上有服务

6、应用服务

应用服务的方法与工厂、资源库之间的关联:

7、建模的核心要素 - 隐性的概念显性化

隐性的概念显性化:多种不同的逻辑封装到一起,按情况进行处理。

隐形的上下文显性化。

封装多对象行为。

8、规则选择 - 策略模式

9、规则拼装 - 组合模式

10、事件风暴 - Event Storming

(1)事件Event

事件即事实,即在业务领域中那些已经发生的事件就是事实,并可能需要保存下来或者让"别人"响应。

事件是对系统产生了业务上的影响的动作,相对的,如果仅仅是数据查询操作,则只会对系统产生技术上的影响,如CPU上升或者内存上升等。

注意:一般查询操作都不会触发事件的产生,所以查询操作不是事件,如点击了查询按钮显示了数据列表,一般情况下不会有类似于:数据已查询或列表已查询,这样的事件。

事件使用正方形橘黄色的便利贴表示,并且是过去式,如:用户已注册(User Registered),激活邮件已发送(ActivationEmail Sended)等。

(2)痛点/问题/关键点(IDEAS, RISKS)

关键点用红颜色的贴纸表示。

表示不确定的点、有风险的点或者需要特别注意的点,一般贴在事件旁边,代表这件事情值得特别关注。

(3)命令Command

决策命令产生了事件,可理解为产生事件的动作,与事件一一对应。如用户已注册(User Registered)事件对应的决策命令就是注册用户(Register User)。

决策命令用正方形蓝色便利贴表示,在实践中只需要将事件"反过来"就行了。

(4)聚合Aggregate

某个Actor在某个聚合调用某种Command产生了某个Event。

比如前面的用户已注册(User Registered)事件,是由普通用户(Normal User)在注册薄(Register)上调用注册用户(Register User)这个命令而产生。

聚合使用紫色即时贴表示。

(5)外部系统External System

Event不一定由前面所说的某个Actor触发Command而产生,也可能是由外部系统或者某种规则自动触发Command而产生。

外部系统使用绿色即时贴表示。

(6)第一阶段成果

(7)构建微服务间关联关系

(8)形成类图

(9)事件风暴核心思想

由下而上,更快:平时我们拆分都是从上层架构师进行总的模块拆分,再分到每一个模块里面。事件风暴从一个个事件开始,从下往上的考虑,出手更快。

事件驱动,更新:事件风暴是由事件驱动的,非常容易更新,当整个架构定下来以后,一旦用户体验有所变化,只需要改变对应的聚合。

团队破冰,更嗨:面前贴一张白纸,通过这种沟通,团队之间心平气和的把服务拆分的非常完美。

10、DDD模型下的代码分层模型

DDD实践_如何使用DDD设计代码模型

五、案例:电商场景领域模型设计

1、子域

核心子域:买家、支付、履约、卖家、市场、用户、风控、客服、搜索、财务、产品、定价、认证、内部、推荐、社交、合作、库存。

通用和支撑子域:数据平台、数据科学、负载管理、内容管理、消息通告、安全加固、基础架构、应用平台、质量保证、集成发布、遥测监控、合规审计。

2、上下文

认证上下文:注册认证、用户登录、访客登录、内部登录、身份验证、令牌管理。

用户上下文:用户联系、用户服务、用户设备、用户喜好、用户背调、用户支付、用户行为、用户设置、用户订单、用户发布、用户折扣、会籍管理。

市场上下文:折扣策略、优惠券、促销管理、用户粘性、SEO、SEM。

搜索上下文:公共搜索、个人搜索、信息编目。

客服上下文:语音客服、机器人、客户关系。

买家支付上下文:支付方式、支付网关、支付交易、保险。

卖家支付上下文:支付方式、支付网关、支付交易、税务。

履约上下文:卖家履约、买家验收、物流。

风控上下文:风控模型、支付风险、账户风险、交易风险。

推荐上下文:个性推荐、趋势推荐、广告推荐。

定价上下文:价格限制、价格推荐、费用计算。

买家上下文:下单、订单、购物车、跨境交易。

卖家上下文:发布管理、一手平台、二手平台、订单。

财务上下文:子账、收入、利润、税收、对账、应收应付。

参考资料

zhuanlan.zhihu.com/p/399103071 blog.csdn.net/wanghaiping...

相关推荐
2401_857610031 小时前
SpringBoot社团管理:安全与维护
spring boot·后端·安全
凌冰_2 小时前
IDEA2023 SpringBoot整合MyBatis(三)
spring boot·后端·mybatis
码农飞飞2 小时前
深入理解Rust的模式匹配
开发语言·后端·rust·模式匹配·解构·结构体和枚举
一个小坑货2 小时前
Rust 的简介
开发语言·后端·rust
monkey_meng3 小时前
【遵守孤儿规则的External trait pattern】
开发语言·后端·rust
Estar.Lee3 小时前
时间操作[计算时间差]免费API接口教程
android·网络·后端·网络协议·tcp/ip
新知图书4 小时前
Rust编程与项目实战-模块std::thread(之一)
开发语言·后端·rust
盛夏绽放4 小时前
Node.js 和 Socket.IO 实现实时通信
前端·后端·websocket·node.js
Ares-Wang4 小时前
Asp.net Core Hosted Service(托管服务) Timer (定时任务)
后端·asp.net
uzong4 小时前
7 年 Java 后端,面试过程踩过的坑,我就不藏着了
java·后端·面试