DDD领域驱动设计
2021-08-31 10:51:43 19 举报
AI智能生成
DDD领域驱动设计,从战略和战术角度讲述DDD的概念
作者其他创作
大纲/内容
概念
DDD 核心思想是通过领域驱动设计方法定义领域模型,从而确定业务和应用边界,保证业务模型与代码模型的一致性。
DDD 不是架构,而是一种架构设计方法论,它通过边界划分将复杂业务领域简单化,帮我们设计出清晰的领域和应用边界,可以很容易地实现架构演进。
战略设计
概念
战略设计主要从业务视角出发,建立业务领域模型,划分领域边界,建立通用语言的限界上下文,限界上下文可以作为微服务设计的参考边界。
实现方法
事件风暴
事件风暴是建立领域模型的主要方法,它是一个从发散到收敛的过程。它通常采用用例分析、场景分析和用户旅程分析,尽可能全面不遗漏地分解业务领域,并梳理领域对象之间的关系,这是一个发散的过程。事件风暴过程会产生很多的实体、命令、事件等领域对象,我们将这些领域对象从不同的维度进行聚类,形成如聚合、限界上下文等边界,建立领域模型,这就是一个收敛的过程。
三步划分领域模型和微服务的边界
第一步
在事件风暴中梳理业务过程中的用户操作、事件以及外部依赖关系等,根据这些要素梳理出领域实体等领域对象。
第二步
根据领域实体之间的业务关联性,将业务紧密相关的实体进行组合形成聚合,同时确定聚合中的聚合根、值对象和实体。在这个图里,聚合之间的边界是第一层边界,它们在同一个微服务实例中运行,这个边界是逻辑边界,所以用虚线表示。
第三步
根据业务及语义边界等因素,将一个或者多个聚合划定在一个限界上下文内,形成领域模型。在这个图里,限界上下文之间的边界是第二层边界,这一层边界可能就是未来微服务的边界,不同限界上下文内的领域逻辑被隔离在不同的微服务实例中运行,物理上相互隔离,所以是物理边界,边界之间用实线来表示。
战术设计
概念
战术设计则从技术视角出发,侧重于领域模型的技术实现,完成软件开发和落地,包括:聚合根、实体、值对象、领域服务、应用服务和资源库等代码逻辑的设计和实现。
基础概念
领域
DDD 的领域就是这个边界内要解决的业务问题域。
子领域
领域可以进一步划分为子领域。我们把划分出来的多个子领域称为子域,
每个子域对应一个更小的问题域或更小的业务范围。
每个子域对应一个更小的问题域或更小的业务范围。
核心域
决定产品和公司核心竞争力的子域是核心域
通用域
是你需要用到的通用系统,比如认证、权限等等,这类应用很容易买到,没有企业特点限制
支撑域
具有企业特性,但不具有通用性,例如数据代码类的数据字典等系统
通用语言
在事件风暴过程中,通过团队交流达成共识的,能够简单、清晰、准确描述业务涵义和规则的语言就是通用语言。
限界上下文
用来封装通用语言和领域对象,提供上下文环境,保证在领域之内的一些术语、业务相关对象等(通用语言)有一个确切的含义,没有二义性。这个边界定义了模型的适用范围,使团队所有成员能够明确地知道什么应该在模型中实现,什么不应该在模型中实现。
实体
实体的业务形态
实体是领域模型的一个重要对象。领域模型中的实体是多个属性、操作或行为的载体。
实体的代码形态
在代码模型中,实体的表现形式是实体类,这个类包含了实体的属性和方法,通过这些方法实现实体自身的业务逻辑。
在 DDD 里,这些实体类通常采用充血模型,与这个实体相关的所有业务逻辑都在实体类的方法中实现,
跨多个实体的领域逻辑则在领域服务中实现。
在 DDD 里,这些实体类通常采用充血模型,与这个实体相关的所有业务逻辑都在实体类的方法中实现,
跨多个实体的领域逻辑则在领域服务中实现。
实体的运行形态
实体以 DO(领域对象)的形式存在,每个实体对象都有唯一的 ID。我们可以对一个实体对象进行多次修改,修改后的数据和原来的数据可能会大不相同。
但是,由于它们拥有相同的 ID,它们依然是同一个实体。
比如商品是商品上下文的一个实体,通过唯一的商品 ID 来标识,不管这个商品的数据如何变化,商品的 ID 一直保持不变,它始终是同一个商品。
但是,由于它们拥有相同的 ID,它们依然是同一个实体。
比如商品是商品上下文的一个实体,通过唯一的商品 ID 来标识,不管这个商品的数据如何变化,商品的 ID 一直保持不变,它始终是同一个商品。
实体的数据库形态
在领域模型映射到数据模型时,一个实体可能对应 0 个、1 个或者多个数据库持久化对象。大多数情况下实体与持久化对象是一对一。
在某些场景中,有些实体只是暂驻静态内存的一个运行态实体,它不需要持久化。比如,基于多个价格配置数据计算后生成的折扣实体。
体与持久化对象则可能是一对多或者多对一的关系。
在某些场景中,有些实体只是暂驻静态内存的一个运行态实体,它不需要持久化。比如,基于多个价格配置数据计算后生成的折扣实体。
体与持久化对象则可能是一对多或者多对一的关系。
实体的特点
有 ID 标识,通过 ID 判断相等性,ID 在聚合内唯一即可。状态可变,它依附
于聚合根,其生命周期由聚合根管理。实体一般会持久化,但与数据库持久化对象不一定是
一对一的关系。实体可以引用聚合内的聚合根、实体和值对象。
于聚合根,其生命周期由聚合根管理。实体一般会持久化,但与数据库持久化对象不一定是
一对一的关系。实体可以引用聚合内的聚合根、实体和值对象。
值对象
通过对象属性值来识别的对象,它将多个相关属性组合为一个概念整体。在 DDD 中用来描述领域的特定方面,并且是一个没有标识符的对象,叫作值对象。
值对象的业务形态
值对象是 DDD 领域模型中的一个基础对象,它跟实体一样都来源于事件风暴所构建的领域模型,都包含了若干个属性,它与实体一起构成聚合。
在值对象中也有部分共享的标准类型的值对象,它们有自己的限界上下文,有自己的持久化对象,可以建立共享的数据类微服务,比如数据字典。
值对象的代码形态
如果值对象是单一属性,则直接定义为实体类的属性;
如果值对象是属性集合,则把它设计为 Class 类,Class 将具有整体概念的多个属性归集到属性集合,这样的值对象没有 ID,会被实体整体引用。
值对象的运行形态
属性嵌入的方式
序列化大对象的方式
值对象的数据库形态
DDD 引入值对象是希望实现从“数据建模为中心”向“领域建模为中心”转变,减少数据库表的数量和表与表之间复杂的依赖关系,
尽可能地简化数据库设计,提升数据库性能。
尽可能地简化数据库设计,提升数据库性能。
在领域建模时,我们可以将部分对象设计为值对象,保留对象的业务涵义,同时又减少了实体的数量;在数据建模时,我们可以将值对象嵌入实体,减少实体表的数量,简化数据库设计。
值对象的特点
无 ID,不可变,无生命周期,用完即扔。值对象之间通过属性值判断相等
性。
它的核心本质是值,是一组概念完整的属性组成的集合,用于描述实体的状态和特征。
值对象尽量只引用值对象。
性。
它的核心本质是值,是一组概念完整的属性组成的集合,用于描述实体的状态和特征。
值对象尽量只引用值对象。
聚合
领域模型内的实体和值对象就好比个体,而能让实体和值对象协同工作的组织就是聚合,它
用来确保这些领域对象在实现共同的业务逻辑时,能保证数据的一致性。
用来确保这些领域对象在实现共同的业务逻辑时,能保证数据的一致性。
聚合在 DDD 分层架构里属于领域层,领域层包含了多个聚合,共同实现核心业务逻辑。
聚合内实体以充血模型实现个体业务能力,以及业务逻辑的高内聚。跨多个实体的业务逻辑通
过领域服务来实现,跨多个聚合的业务逻辑通过应用服务来实现。
过领域服务来实现,跨多个聚合的业务逻辑通过应用服务来实现。
聚合的特点
高内聚、低耦合,它是领域模型中最底层的边界,可以作为拆分微服务的最小
单位,但我不建议你对微服务过度拆分。但在对性能有极致要求的场景中,聚合可以独立作
为一个微服务,以满足版本的高频发布和极致的弹性伸缩能力。
单位,但我不建议你对微服务过度拆分。但在对性能有极致要求的场景中,聚合可以独立作
为一个微服务,以满足版本的高频发布和极致的弹性伸缩能力。
一个微服务可以包含多个聚合,聚合之间的边界是微服务内天然的逻辑边界。有了这个逻辑
边界,在微服务架构演进时就可以以聚合为单位进行拆分和组合了,微服务的架构演进也就
不再是一件难事了。
边界,在微服务架构演进时就可以以聚合为单位进行拆分和组合了,微服务的架构演进也就
不再是一件难事了。
聚合根
如果把聚合比作组织,那聚合根就是这个组织的负责人。聚合根也称为根实体,它不仅是实
体,还是聚合的管理者。
体,还是聚合的管理者。
首先它作为实体本身,拥有实体的属性和业务行为,实现自身的业务逻辑。
其次它作为聚合的管理者,在聚合内部负责协调实体和值对象按照固定的业务规则协同完成
共同的业务逻辑。
共同的业务逻辑。
最后在聚合之间,它还是聚合对外的接口人,以聚合根 ID 关联的方式接受外部任务和请
求,在上下文内实现聚合之间的业务协同。也就是说,聚合之间通过聚合根 ID 关联引用,
如果需要访问其它聚合的实体,就要先访问聚合根,再导航到聚合内部实体,外部对象不能
直接访问聚合内实体。
求,在上下文内实现聚合之间的业务协同。也就是说,聚合之间通过聚合根 ID 关联引用,
如果需要访问其它聚合的实体,就要先访问聚合根,再导航到聚合内部实体,外部对象不能
直接访问聚合内实体。
聚合根的特点
聚合根是实体,有实体的特点,具有全局唯一标识,有独立的生命周期。一
个聚合只有一个聚合根,聚合根在聚合内对实体和值对象采用直接对象引用的方式进行组织
和协调,聚合根与聚合根之间通过 ID 关联的方式实现聚合之间的协同。
个聚合只有一个聚合根,聚合根在聚合内对实体和值对象采用直接对象引用的方式进行组织
和协调,聚合根与聚合根之间通过 ID 关联的方式实现聚合之间的协同。
进阶概念
领域事件
一次事务最多只能更改一个聚合的状态。如果一次业务操作涉及多个聚合状态的更改,应采用领域事件的最终一致性
场景
1、发生在微服务内的聚合之间
如果数据的实时性、一致性要求较高
微服务内应用服务,可以在应用层通过跨聚合的服务编排和组合,以服务调用的方式完成跨聚合的访问,
如果数据的实时性、一致性要求较不高
通过event事件完成
2、发生在微服务之间
如果数据的实时性、一致性要求较高
直接调用的方式完成
如果数据的实时性、一致性要求较不高
消息中间件:MQ
分层架构
历史
依赖倒置:基础层外部包一层model,写一个接口,让基础层实现,依赖倒置
现在
1、用户接口层
用户接口层负责向用户显示信息和解释用户指令。这里的用户可能是:用户、程序、自动化
测试和批处理脚本等等。
测试和批处理脚本等等。
2、应用层
应用层是很薄的一层,理论上不应该有业务规则或逻辑,主要面向用例和流程相关的操作。
但应用层又位于领域层之上,因为领域层包含多个聚合,所以它可以协调多个聚合的服务和
领域对象完成服务编排和组合,协作完成业务操作。
但应用层又位于领域层之上,因为领域层包含多个聚合,所以它可以协调多个聚合的服务和
领域对象完成服务编排和组合,协作完成业务操作。
应用层也是微服务之间交互的通道,它可以调用其它微服务的应用服务,完成微服务
之间的服务组合和编排。
之间的服务组合和编排。
应用服务
一般命名为*ApplicationService
它负责服务的组合、编排和转发,负责处理业务用例的执行
顺序以及结果的拼装,以粗粒度的服务通过 API 网关向前端发布。还有,应用服务还可以
进行安全认证、权限校验、事务控制、发送或订阅领域事件等。
顺序以及结果的拼装,以粗粒度的服务通过 API 网关向前端发布。还有,应用服务还可以
进行安全认证、权限校验、事务控制、发送或订阅领域事件等。
3、领域层
领域层的作用是实现企业核心业务逻辑,通过各种校验手段保证业务的正确性。领域层主要
体现领域模型的业务能力,它用来表达业务概念、业务状态和业务规则。
体现领域模型的业务能力,它用来表达业务概念、业务状态和业务规则。
领域层包含聚合根、实体、值对象、领域服务等领域模型中的领域对象。
领域服务
可以组合聚合内的多个实体(或者值对象),实现复杂的业务逻辑。
4、基础层
基础层是贯穿所有层的,它的作用就是为其它各层提供通用的技术和基础服务,包括第三方
工具、驱动、消息中间件、网关、文件、缓存以及数据库等。比较常见的功能还是提供数据
库持久化。
工具、驱动、消息中间件、网关、文件、缓存以及数据库等。比较常见的功能还是提供数据
库持久化。
基础层包含基础服务,它采用依赖倒置设计,封装基础资源服务,实现应用层、领域层与基
础层的解耦,降低外部资源变化对应用的影响。
础层的解耦,降低外部资源变化对应用的影响。
分层架构最重要的原则?
每层只能与位于其下
方的层发生耦合。
方的层发生耦合。
而架构根据耦合的紧密程度又可以分为两种:
严格分层架构
任何层只能对位于其直接下方的层产生依赖。
松散分层架构
它允许某层与其任意下方的层发生依赖。
合理的架构分层
1、不要把与领域无关的逻辑放在领域层实现,保证领域层的纯洁和领域逻辑的稳定,避免污染
领域模型。
领域模型。
2、不要把领域模型的业务逻辑放在应用层,这样会导致应用层过于庞大,最终领
域模型会失焦。
域模型会失焦。
3、如果实在无法避免,我们可以引入防腐层,进行新老系统的适配和转换,过
渡期完成后,可以直接将防腐层代码抛弃。
渡期完成后,可以直接将防腐层代码抛弃。
从三层架构向 DDD 分层架构演进的过程
三层架构数据访问采用 DAO 方式;
DDD 分层架构的数据库等基础资源访问,采用了仓储(Repository)设计模式,通过依赖
倒置实现各层对基础资源的解耦。
DDD 分层架构的数据库等基础资源访问,采用了仓储(Repository)设计模式,通过依赖
倒置实现各层对基础资源的解耦。
仓储又分为两部分:仓储接口和仓储实现。仓储接口放在领域层中,仓储实现放在基础层。
原来三层架构通用的第三方工具包、驱动、Common、Utility、Config 等通用的公共的资
源类统一放到了基础层。
原来三层架构通用的第三方工具包、驱动、Common、Utility、Config 等通用的公共的资
源类统一放到了基础层。
常见的架构模型
整洁架构(洋葱架构)
六边形架构(端口适配器架构)
三种架构的共同点
DDD 分层架构、整洁架构、六边形架构都是以领域模型
为核心,实行分层架构,内部核心业务逻辑与外部应用、资源隔离并解耦。
为核心,实行分层架构,内部核心业务逻辑与外部应用、资源隔离并解耦。
中台的演化
项目级微服务
企业级中台微服务
平台和中台的区别?
平台只是将部分通用的公共能力独立为共享平台。虽然可以通过 API 或者数据对外提供公
共共享服务,解决系统重复建设的问题,但这类平台并没有和企业内的其它平台或应用,实
现页面、业务流程和数据从前端到后端的全面融合,并且没有将核心业务服务链路作为一个
整体方案考虑,各平台仍然是分离且独立的。
共共享服务,解决系统重复建设的问题,但这类平台并没有和企业内的其它平台或应用,实
现页面、业务流程和数据从前端到后端的全面融合,并且没有将核心业务服务链路作为一个
整体方案考虑,各平台仍然是分离且独立的。
中台概念
1、前台
传统企业的早期系统有不少是基于业务领域或组织架构来建设的,每个系统都有自己的前
端,相互独立,用户操作是竖井式,需要登录多个系统才能完成完整的业务流程。
端,相互独立,用户操作是竖井式,需要登录多个系统才能完成完整的业务流程。
中台后的前台建设要有一套综合考虑业务边界、流程和平台的整体解决方案,以实现各不同
中台前端操作、流程和界面的联通、融合。不管后端有多少个中台,前端用户感受到的就是
只有一个前台。
中台前端操作、流程和界面的联通、融合。不管后端有多少个中台,前端用户感受到的就是
只有一个前台。
在前台设计中我们可以借鉴微前端的设计思想,在企业内不仅实现前端解耦和复用,还可以
根据核心链路和业务流程,通过对微前端页面的动态组合和流程编排,实现前台业务的融
合。
根据核心链路和业务流程,通过对微前端页面的动态组合和流程编排,实现前台业务的融
合。
2、中台
业务中台的建设可采用领域驱动设计方法,通过领域建模,将可复用的公共能力从各个单体
剥离,沉淀并组合,采用微服务架构模式,建设成为可共享的通用能力中台。
剥离,沉淀并组合,采用微服务架构模式,建设成为可共享的通用能力中台。
数据中台
主要目标是打通数据孤岛,实现业务融合和创新
三个职能
一是完成企业全域数据的采集与存储,实现各不同业务类别中台数据的汇总和集中管
理。
理。
二是按照标准的数据规范或数据模型,将数据按照不同主题域或场景进行加工和处理,
形成面向不同主题和场景的数据应用,比如客户视图、代理人视图、渠道视图、机构视
图等不同数据体系。
形成面向不同主题和场景的数据应用,比如客户视图、代理人视图、渠道视图、机构视
图等不同数据体系。
三是建立业务需求驱动的数据体系,基于各个维度的数据,深度萃取数据价值,支持业
务和商业模式的创新。
务和商业模式的创新。
建设的三步走
第一步实现各中台业务数据的汇集,解决数据孤岛和初级数据共享问题。
第二步实现企业级实时或非实时全维度数据的深度融合、加工和共享。
第三步萃取数据价值,支持业务创新,加速从数据转换为业务价值的过程。
3. 后台
前台主要面向客户以及终端销售者,实现营销推广以及交易转化;中台主要面向运营人员,
完成运营支撑;后台主要面向后台管理人员,实现流程审核、内部管理以及后勤支撑,比如
采购、人力、财务和 OA 等系统。
完成运营支撑;后台主要面向后台管理人员,实现流程审核、内部管理以及后勤支撑,比如
采购、人力、财务和 OA 等系统。
在设计流程审核和管理类功能的时候,我们可以考虑按角色或岗位进行功能聚合,将复杂的
管理需求从通用的核心业务链路中剥离,参考小程序的建设模式,通过特定程序入口嵌入前
台 APP 或应用中。
管理需求从通用的核心业务链路中剥离,参考小程序的建设模式,通过特定程序入口嵌入前
台 APP 或应用中。
管理需求从前台核心业务链路剥离后,前台应用将具有更好的通用性,它可以更加容易地实
现各渠道前台界面和流程的融合。一个前台应用或 APP 可以无差别地同时面向外部互联网
用户和内部业务人员,从而促进传统渠道与互联网渠道应用前台的融合。
现各渠道前台界面和流程的融合。一个前台应用或 APP 可以无差别地同时面向外部互联网
用户和内部业务人员,从而促进传统渠道与互联网渠道应用前台的融合。
微服务代码模型
微服务一级目录结构
Interfaces(用户接口层)
它主要存放用户接口层与前端交互、展现数据相关的代码。前
端应用通过这一层的接口,向应用服务获取展现所需的数据。这一层主要用来处理用户发送
的 Restful 请求,解析用户输入的配置文件,并将数据传递给 Application 层。数据的组
装、数据传输格式以及 Facade 接口等代码都会放在这一层目录里。
端应用通过这一层的接口,向应用服务获取展现所需的数据。这一层主要用来处理用户发送
的 Restful 请求,解析用户输入的配置文件,并将数据传递给 Application 层。数据的组
装、数据传输格式以及 Facade 接口等代码都会放在这一层目录里。
Assembler
实现 DTO 与领域对象之间的相互转换和数据交换。一般来说 Assembler 与
DTO 总是一同出现。
DTO 总是一同出现。
Dto
它是数据传输的载体,内部不存在任何业务逻辑,我们可以通过 DTO 把内部的领域
对象与外界隔离。
对象与外界隔离。
Facade
提供较粗粒度的调用接口,将用户请求委派给一个或多个应用服务进行处理。
Application(应用层)
它主要存放应用层服务组合和编排相关的代码。应用服务向下基
于微服务内的领域服务或外部微服务的应用服务完成服务的编排和组合,向上为用户接口层
提供各种应用数据展现支持服务。应用服务和事件等代码会放在这一层目录里。
于微服务内的领域服务或外部微服务的应用服务完成服务的编排和组合,向上为用户接口层
提供各种应用数据展现支持服务。应用服务和事件等代码会放在这一层目录里。
Event(事件)
这层目录主要存放事件相关的代码。它包括两个子目录:publish 和
subscribe。前者主要存放事件发布相关代码,后者主要存放事件订阅相关代码(事件处理
相关的核心业务逻辑在领域层实现)。
subscribe。前者主要存放事件发布相关代码,后者主要存放事件订阅相关代码(事件处理
相关的核心业务逻辑在领域层实现)。
Service(应用服务)
这层的服务是应用服务。应用服务会对多个领域服务或外部应用服
务进行封装、编排和组合,对外提供粗粒度的服务。应用服务主要实现服务组合和编排,是
一段独立的业务逻辑。你可以将所有应用服务放在一个应用服务类里,也可以把一个应用服
务设计为一个应用服务类,以防应用服务类代码量过大。
务进行封装、编排和组合,对外提供粗粒度的服务。应用服务主要实现服务组合和编排,是
一段独立的业务逻辑。你可以将所有应用服务放在一个应用服务类里,也可以把一个应用服
务设计为一个应用服务类,以防应用服务类代码量过大。
Domain(领域层)
它主要存放领域层核心业务逻辑相关的代码。领域层可以包含多个聚
合代码包,它们共同实现领域模型的核心业务逻辑。聚合以及聚合内的实体、方法、领域服
务和事件等代码会放在这一层目录里。
合代码包,它们共同实现领域模型的核心业务逻辑。聚合以及聚合内的实体、方法、领域服
务和事件等代码会放在这一层目录里。
Aggregate(聚合)
它是聚合软件包的根目录,可以根据实际项目的聚合名称命名,比
如权限聚合。在聚合内定义聚合根、实体和值对象以及领域服务之间的关系和边界。聚合内
实现高内聚的业务逻辑,它的代码可以独立拆分为微服务。
如权限聚合。在聚合内定义聚合根、实体和值对象以及领域服务之间的关系和边界。聚合内
实现高内聚的业务逻辑,它的代码可以独立拆分为微服务。
Entity(实体)
它存放聚合根、实体、值对象以及工厂模式(Factory)相关代码。实体
类采用充血模型,同一实体相关的业务逻辑都在实体类代码中实现。跨实体的业务逻辑代码
在领域服务中实现。
类采用充血模型,同一实体相关的业务逻辑都在实体类代码中实现。跨实体的业务逻辑代码
在领域服务中实现。
Event(事件)
它存放事件实体以及与事件活动相关的业务逻辑代码。
Service(领域服务)
它存放领域服务代码。一个领域服务是多个实体组合出来的一段业
务逻辑。你可以将聚合内所有领域服务都放在一个领域服务类中,你也可以把每一个领域服
务设计为一个类。如果领域服务内的业务逻辑相对复杂,我建议你将一个领域服务设计为一
个领域服务类,避免由于所有领域服务代码都放在一个领域服务类中,而出现代码臃肿的问
题。领域服务封装多个实体或方法后向上层提供应用服务调用。
务逻辑。你可以将聚合内所有领域服务都放在一个领域服务类中,你也可以把每一个领域服
务设计为一个类。如果领域服务内的业务逻辑相对复杂,我建议你将一个领域服务设计为一
个领域服务类,避免由于所有领域服务代码都放在一个领域服务类中,而出现代码臃肿的问
题。领域服务封装多个实体或方法后向上层提供应用服务调用。
Repository(仓储)
它存放所在聚合的查询或持久化领域对象的代码,通常包括仓储接
口和仓储实现方法。为了方便聚合的拆分和组合,我们设定了一个原则:一个聚合对应一个
仓储。
口和仓储实现方法。为了方便聚合的拆分和组合,我们设定了一个原则:一个聚合对应一个
仓储。
Infrastructure(基础层)
它主要存放基础资源服务相关的代码,为其它各层提供的通用
技术能力、三方软件包、数据库服务、配置和基础资源服务的代码都会放在这一层目录里。
技术能力、三方软件包、数据库服务、配置和基础资源服务的代码都会放在这一层目录里。
Config
主要存放配置相关代码
Util
主要存放平台、开发框架、消息、数据库、缓存、文件、总线、网关、第三方类库、
通用算法等基础代码,你可以为不同的资源类别建立不同的子目录。
通用算法等基础代码,你可以为不同的资源类别建立不同的子目录。
数据对象视图
数据持久化对象 PO(Persistent Object)
与数据库结构一一映射,是数据持久化过程中
的数据载体。
的数据载体。
基础层
基础层的主要对象是 PO 对象。我们需要先建立 DO 和 PO 的映射关系。当 DO 数据需要
持久化时,仓储服务会将 DO 转换为 PO 对象,完成数据库持久化操作。当 DO 数据需要
初始化时,仓储服务从数据库获取数据形成 PO 对象,并将 PO 转换为 DO,完成数据初始
化。
持久化时,仓储服务会将 DO 转换为 PO 对象,完成数据库持久化操作。当 DO 数据需要
初始化时,仓储服务从数据库获取数据形成 PO 对象,并将 PO 转换为 DO,完成数据初始
化。
领域对象 DO(Domain Object)
微服务运行时的实体,是核心业务的载体。
领域层
领域层的主要对象是 DO 对象。DO 是实体和值对象的数据和业务行为载体,承载着基础
的核心业务逻辑。通过 DO 和 PO 转换,我们可以完成数据持久化和初始化。
的核心业务逻辑。通过 DO 和 PO 转换,我们可以完成数据持久化和初始化。
应用层
应用层的主要对象是 DO 对象。如果需要调用其它微服务的应用服务,DO 会转换为
DTO,完成跨微服务的数据组装和传输。用户接口层先完成 DTO 到 DO 的转换,然后应
用服务接收 DO 进行业务处理。如果 DTO 与 DO 是一对多的关系,这时就需要进行 DO
数据重组。
DTO,完成跨微服务的数据组装和传输。用户接口层先完成 DTO 到 DO 的转换,然后应
用服务接收 DO 进行业务处理。如果 DTO 与 DO 是一对多的关系,这时就需要进行 DO
数据重组。
数据传输对象 DTO(Data Transfer Object)
用于前端与应用层或者微服务之间的数
据组装和传输,是应用之间数据传输的载体。
据组装和传输,是应用之间数据传输的载体。
用户接口层
用户接口层会完成 DO 和 DTO 的互转,完成微服务与前端应用数据交互及转换。Facade
服务会对多个 DO 对象进行组装,转换为 DTO 对象,向前端应用完成数据转换和传输。
服务会对多个 DO 对象进行组装,转换为 DTO 对象,向前端应用完成数据转换和传输。
视图对象 VO(View Object)
用于封装展示层指定页面或组件的数据。
前端应用
前端应用主要是 VO 对象。展现层使用 VO 进行界面展示,通过用户接口层与应用层采用
DTO 对象进行数据交互。
DTO 对象进行数据交互。
微前端
旧有前端-单体前端的困境
传统企业在完成中台转型后,虽然后台的业务完成了微服务架构的升级,但前端仍然是单体
模式,由一个团队创建并维护一个前端应用。随着时间推移和业务发展,前端会变得越来越
臃肿,越来越难维护。而随着 5G 和移动互联技术的应用,企业业务活动将会进一步移动化
和线上化。过去很多企业的做法是为不同的业务开发出独立的 APP。但很显然用户并不想
装那么多的 APP!
模式,由一个团队创建并维护一个前端应用。随着时间推移和业务发展,前端会变得越来越
臃肿,越来越难维护。而随着 5G 和移动互联技术的应用,企业业务活动将会进一步移动化
和线上化。过去很多企业的做法是为不同的业务开发出独立的 APP。但很显然用户并不想
装那么多的 APP!
为了提高用户体验,实现统一运营,很多企业开始缩减和整合 APP,将企业内所有的业务
能力都尽量集中到一个 APP 中。试想如果仍然沿用单体前端的设计模式。前端项目团队将
面对多个中台微服务团队,需要集成成千上万的 API 服务,这就需要相当高的沟通成本和
技术要求。这绝对会是一场灾难。
能力都尽量集中到一个 APP 中。试想如果仍然沿用单体前端的设计模式。前端项目团队将
面对多个中台微服务团队,需要集成成千上万的 API 服务,这就需要相当高的沟通成本和
技术要求。这绝对会是一场灾难。
新时代-微前端
单一业务单元
一个微前端和一个微服务组成单一业务单元。微前端和微服务分别实现同一个领域模型从前
端到后端的功能。
端到后端的功能。
组合业务单元
一个微前端与多个微服务组成组合业务单元。微前端具有多个微服务的前端功能,完成较复
杂的页面和操作。多个微服务实现各自领域模型的功能,向微前端提供可组合的服务。
杂的页面和操作。多个微服务实现各自领域模型的功能,向微前端提供可组合的服务。
记住一点:微前端不宜与过多的微服务组合,否则容易变成单体前端。
通用共享业务单元
一个微前端与一个或多个通用中台微服务组合为通用共享业务单元。通用共享微前端以共享
页面的方式与其它微前端页面协作,完成业务流程。很多通用中台微服务的微前端是共享
的,比如订单和支付等微服务对应的订单和支付微前端界面。
页面的方式与其它微前端页面协作,完成业务流程。很多通用中台微服务的微前端是共享
的,比如订单和支付等微服务对应的订单和支付微前端界面。
微前端与前端主页面的集成
前端主页面是企业级的前端页面,微前端是业务单元的前端页面。微前端通过主页面的微前
端加载器,利用页面路由和动态加载等技术,将特定业务单元的微前端页面动态加载到前端
主页面,实现前端主页面与微前端页面的“拼图式”集成。
端加载器,利用页面路由和动态加载等技术,将特定业务单元的微前端页面动态加载到前端
主页面,实现前端主页面与微前端页面的“拼图式”集成。
微前端完成开发、集成和部署后,在前端主页面完成微前端注册以及页面路由配置,即可实
现动态加载微前端页面。
现动态加载微前端页面。
微前端与微服务的集成
微前端与微服务独立开发,独立部署。在微前端注册到前端主页面前,微前端需要与微服务
完成集成。它的集成方式与传统前后端分离的集成方式没有差异。微服务将服务发布到 API
网关,微前端调用发布在 API 网关中的服务,即完成业务单元内的前后端集成。
完成集成。它的集成方式与传统前后端分离的集成方式没有差异。微服务将服务发布到 API
网关,微前端调用发布在 API 网关中的服务,即完成业务单元内的前后端集成。
注
DDD与微服务的关系
DDD 主要关注
从业务领域视角划分领域边界,构建通用语言进行高效沟通,通过业务抽象,建立领域模型,维持业务和代码的逻辑一致性。
微服务主要关注
运行时的进程间通信、容错和故障隔离,实现去中心化数据管理和去中心化服务治理,关注微服务的独立开发、测试、构建和部署。
限界上下文和微服务的关系
理论上限界上下文就是微服务的边界。我们将限界上下文内的领域模型映射到微服务,就完成了从问题域到软件的解决方案。
DDD、中台和微服务的关系
中台是抽象出来的业务模型,微服务是业务模型的系统实现,DDD
作为方法论可以同时指导中台业务建模和微服务建设,三者相辅相成,完美结合。
作为方法论可以同时指导中台业务建模和微服务建设,三者相辅相成,完美结合。
仓储
为了解耦应用逻辑和基础资源,在基础层和上层应用逻辑之间会增加一层,这一层就是仓储
层。一个聚合对应一个仓储,仓储实现聚合内数据的持久化。聚合内的应用逻辑通过接口来
访问基础资源,仓储实现在基础层实现。这样应用逻辑和基础资源的实现逻辑是分离的。如
果变更基础资源组件,只需要替换仓储实现就可以了,不会对应用逻辑产生太大的影响,这
样就实现了应用逻辑与基础资源的解耦,也就实现了依赖倒置。
层。一个聚合对应一个仓储,仓储实现聚合内数据的持久化。聚合内的应用逻辑通过接口来
访问基础资源,仓储实现在基础层实现。这样应用逻辑和基础资源的实现逻辑是分离的。如
果变更基础资源组件,只需要替换仓储实现就可以了,不会对应用逻辑产生太大的影响,这
样就实现了应用逻辑与基础资源的解耦,也就实现了依赖倒置。
找不到聚合根时
关于聚合设计过程中的一些原则问题。大部分的业务场景我们都可以通过事件风暴,找到聚
合根,建立聚合,划分限界上下文,建立领域模型。但也有部分场景,比如数据计算、统计
以及批处理业务场景,所有的实体都是独立无关联的,找不到聚合根,也无法建立领域模
型。但是它们之间的业务关系是非常紧密的,在业务上是高内聚的。我们也可以将这类场景
作为一个聚合处理,除了不考虑聚合根的设计方法外,其它诸如 DDD 分层架构相关的设计
方法都是可以采用的。
合根,建立聚合,划分限界上下文,建立领域模型。但也有部分场景,比如数据计算、统计
以及批处理业务场景,所有的实体都是独立无关联的,找不到聚合根,也无法建立领域模
型。但是它们之间的业务关系是非常紧密的,在业务上是高内聚的。我们也可以将这类场景
作为一个聚合处理,除了不考虑聚合根的设计方法外,其它诸如 DDD 分层架构相关的设计
方法都是可以采用的。
领域服务的CRUD是不是都是操作聚合根或整个实体对象,比如我只想根据ID判断记录是
否存在,或者返回个别字段,需要返回整个实体对象吗?
否存在,或者返回个别字段,需要返回整个实体对象吗?
其实查询类业务可以不必经过聚合根和仓储。传统方法也可以了。
如果聚合数据比较多,会有延迟加载影响性能。
聚合根的主要目的是为了保证数据的一致性,这些场景一般在CU的场景。
如果聚合数据比较多,会有延迟加载影响性能。
聚合根的主要目的是为了保证数据的一致性,这些场景一般在CU的场景。
DDD领域建模和传统开发模式的区别?
DDD
事件风暴--产品愿景--场景分析--领域建模--微服务拆分与设计。
DDD领域建模优先,领域建模的时基本不考虑数据模型和数据库实现。在
微服务具体落地的时候才考虑数据实体的设计。
微服务具体落地的时候才考虑数据实体的设计。
传统
产品需求--需求分析--详细设计--ER模型(数据库模型)--UML设计(java类关系)
事务封装在哪一层?
按照业务逻辑来讲,封装到应用层或领域层都是可以的
领域层调用关系?
按照严格分层架构层的依赖关系,如果实体的方法需要暴露给应用层,它需要封装成领域服
务后才可以被应用服务调用。所以如果有的实体方法需要被前端应用调用,我们会将它封装
成领域服务,然后再封装为应用服务。
务后才可以被应用服务调用。所以如果有的实体方法需要被前端应用调用,我们会将它封装
成领域服务,然后再封装为应用服务。
DDD 使用的误区?
所有的领域都用 DDD
很多人在学会 DDD 后,可能会将其用在所有业务域,即全部使用 DDD 来设计。DDD 从
战略设计到战术设计,是一个相对复杂的过程,首先企业内要培养 DDD 的文化,其次对团
队成员的设计和技术能力要求相对比较高。在资源有限的情况下,应聚焦核心域,建议你先
从富领域模型的核心域开始,而不必一下就在全业务域推开。
战略设计到战术设计,是一个相对复杂的过程,首先企业内要培养 DDD 的文化,其次对团
队成员的设计和技术能力要求相对比较高。在资源有限的情况下,应聚焦核心域,建议你先
从富领域模型的核心域开始,而不必一下就在全业务域推开。
重战术设计而轻战略设计
很多 DDD 初学者,学习 DDD 的主要目的,可能是为了开发微服务,因此更看重 DDD 的
战术设计实现。殊不知 DDD 是一种从领域建模到微服务落地的全方位的解决方案。
战术设计实现。殊不知 DDD 是一种从领域建模到微服务落地的全方位的解决方案。
战略设计时构建的领域模型,是微服务设计和开发的输入,它确定了微服务的边界、聚合、
代码对象以及服务等关键领域对象。领域模型边界划分得清不清晰,领域对象定义得明不明
确,会决定微服务的设计和开发质量。没有领域模型的输入,基于 DDD 的微服务的设计和
开发将无从谈起。因此我们不仅要重视战术设计,更要重视战略设计。
代码对象以及服务等关键领域对象。领域模型边界划分得清不清晰,领域对象定义得明不明
确,会决定微服务的设计和开发质量。没有领域模型的输入,基于 DDD 的微服务的设计和
开发将无从谈起。因此我们不仅要重视战术设计,更要重视战略设计。
总结
抓住事物的重点,
从本质上讲,这个世界的任何事情都是简单的,抓住DDD的来源,也就抓住的DDD的一
切,从业务角度来设计拆分系统,纵向解耦业务形成不同的微服务,横向解耦业务形成微
服务内部不同的层
从本质上讲,这个世界的任何事情都是简单的,抓住DDD的来源,也就抓住的DDD的一
切,从业务角度来设计拆分系统,纵向解耦业务形成不同的微服务,横向解耦业务形成微
服务内部不同的层
0 条评论
下一页