DDD领域驱动设计实战-分层架构

本文涉及的产品
应用实时监控服务-可观测链路OpenTelemetry版,每月50GB免费额度
Serverless 应用引擎免费试用套餐包,4320000 CU,有效期3个月
可观测可视化 Grafana 版,10个用户账号 1个月
简介: DDD分层架构通过明确各层职责及交互规则,有效降低了层间依赖。其基本原则是每层仅与下方层耦合,分为严格和松散两种形式。架构演进包括传统四层架构与改良版四层架构,后者采用依赖反转设计原则优化基础设施层位置。各层职责分明:用户接口层处理显示与请求;应用层负责服务编排与组合;领域层实现业务逻辑;基础层提供技术基础服务。通过合理设计聚合与依赖关系,DDD支持微服务架构灵活演进,提升系统适应性和可维护性。

1 DDD分层架构

1.1 分层架构的基本原则

每层只与位于其下方的层发生耦合。

1.2 分层架构的分类

  • 严格分层架构(Strict Layers Architecture)
    某层只能与其直接下层耦合,即我的奴隶的奴隶,不是我的奴隶。
  • 松散分层架构(Relaxed Layers Architecture)
    允许任意上层与任意下层耦合。由于用户接口层和应用服务通常需要与基础设施打交道,许多系统都是该架构。

较低层有时也可与较高层耦合,但只限于采用观察者 (Observer)模式或者调停者(Mediator)模式场景。
较低层绝不能直接访问较高层。例如,在使用调停者模式时,较高层可能实现了较低层的接口,然后将实现对象作为参数传递到较低层。当较低层调用该实现时, 它并不知道实现出自何处。

1.3 分层架构演进

1.3.1 传统四层架构

将领域模型和业务逻辑分离出来,并减少对基础设施、用户界面甚至应用层逻辑的依赖,因为它们不属业务逻辑。将一个夏杂的系统分为不同的层,每层都应该具有良好的内聚性,并且只依赖于比其自身更低的层。

传统分层架构的基础设施层位于底层,持久化和消息机制便位于该层。
这里的消息包含

  • MQ消息
  • SMTP
  • 文本消息(SMS)

可将基础设施层中所有组件看作应用程序的低层服务,较高层与该层发生耦合以复用技术基础设施。即便如此,依然应避免核心的领域模型对象与基础设施层直接耦合

1.3.2 改良版四层架构

传统架构的缺陷

DDD初创开发团队发现,将基础设施层放在最底层存在缺点,比如此时领域层中的一些技术实现就很困难:

  • 违背分层架构的基本原则
  • 难以编写测试用例

何解?
使用依赖反转设计原则:低层服务(如基础设施层)应依赖高层组件(比如用户界面层、应用层和领域层)所提供的接口。

应用依赖反转原则

  • 依赖反转原则后的分层方式:基础设施层在最上方,可实现所有其他层中定义的接口

依赖反转原则真的可以支持所有层吗?
有人认为依赖反转原则中只存在两层:最上方和最下方,上层实现下层定义的抽象接口。因此上图的基础设施层将位于最上方,而用户接口层、应用层和领域层应作同层且都位于下方。对此大家可保留自己意见。

2 各层职责

2.1 用户接口层

一般包括用户接口、Web 服务等。

只处理用户显示和用户请求,不应包含领域或业务逻辑。
有人认为,既然用户接口需验证用户输入,就无可避免应该包含业务逻辑。事实上,用户接口所进行的验证和对领域模型的验证不同:对那些粗制滥造且只面向领域模型的验证行为,应该予以限制。

如果用户接口使用了领域模型中的对象,那么此时领域对象仅限于数据渲染展现。在采用这种方式时,可使用展现模型对用户接口与领域对象进行解耦。
由于用户可能是人,也可能是其他系统,有时用户接口层将采用开放主机服务的方式向外提供API。
用户接口层是应用层的直接用户。
用户接口层在于前后端调用的适配。若你的微服务要提供服务给很多外部应用,而对每个外部应用的入参出参都不同,你不可能开发一堆一对一的应用服务,这时Facade接口就起到了很好的作用,包括DO和DTO对象的组装和转换。

2.2 应用层

主要包含应用服务,理论上不应有业务规则或逻辑,而主要是面向用例和流程相关的操作。

  • 应用层位于领域层之上,因为领域层包含多个聚合,所以它可协调多个聚合服务和领域对象完成服务编排和组合,协作完成业务。
  • 应用层也是微服务间的交互通道,它可调用其它微服务,完成微服务间的服务组合和编排

开发设计时,不要将本该放在领域层的业务逻辑放到应用层。因为庞大的应用层会使领域模型失焦,时间一长,微服务就会退化为MVC架构,导致业务逻辑混乱

应用服务是在应用层,负责

  • 服务的组合、编排、转发、转换和传递,处理业务用例的执行顺序以及结果的拼装,以粗粒度服务通过API网关发布到前端
  • 安全认证
  • 权限校验
  • 事务控制
  • 发送或订阅领域事件

2.3 领域层

主要包含聚合根、实体、值对象、领域服务等领域模型中的领域对象。

实现核心业务逻辑,通过各种校验保证业务正确性。领域层主要体现领域模型的业务能力,它用来表达业务概念、业务状态和业务规则。

领域模型的业务逻辑主要由实体和领域服务实现:

  • 实体采用充血模型 实现所有与之相关的业务功能。

实体和领域服务在实现业务逻辑上不是同级,当领域中的某些功能,单一实体或值对象无法实现,就会用到领域服务,它可组合聚合内的多个实体或值对象,实现复杂业务逻辑。

2.4 基础层

为其它各层提供通用技术基础服务:

  • 三方工具
  • 驱动
  • MQ
  • API网关
  • 文件
  • 缓存
  • DB
    最常用的

基础层包含基础服务,它采用依赖反转,封装基础资源服务,实现应用层、领域层与基础层解耦。

MVC架构由于上层应用对DB强耦合,很多公司在架构演进最怕换DB,一旦更换,可能需重写一堆代码。
但采用依赖反转,应用层即可通过解耦保持独立核心业务逻辑。当DB变更,只需更换DB基础服务。

3 微服务架构演进

领域模型中对象的层次从内到外依次是:值对象、实体、聚合和限界上下文。

实体或值对象的简单变更,一般不会让领域模型和微服务发生大变。但聚合的重组或拆分却可以。因为聚合内业务功能内聚,能独立完成特定业务。那聚合的重组或拆分,势必引起业务模块和系统功能变化。

可以聚合为基础单元,完成领域模型和微服务架构的演进。
聚合可作为整体,在不同领域模型间重组或拆分,或直接将一个聚合独立为微服务。

微服务架构的演进案例

现有
微服务 1:包含聚合 a、b、c
微服务2:
微服务3:包含聚合 d、e、f

  • 当发现微服务1中聚合a的功能经常被高频访问,以致拖累了整个微服务1的性能,可把聚合a,从微服务1中剥离,独立为微服务2以应对高性能场景
  • 随业务发展,发现微服务3的领域模型变化,聚合d会更适合放到微服务1的领域模型。即可将聚合d整体迁移到微服务1。注意定义好聚合间的代码边界
  • 架构演进后,微服务1从最初包含聚合a、b、c,演进为包含聚合b、c、d的新领域模型和微服务

可见,好的聚合和代码模型的边界设计,可让你快速应对业务变化,轻松实现领域模型和微服务架构演进。

微服务内服务的演进

在微服务内部,实体的方法被领域服务组合和封装,领域服务又被应用服务组合和封装。在服务逐层组合和封装的过程中,你会发现这样一个有趣的现象。

服务设计时,你并不一定能完整预测有哪些下层服务会被多少个上层服务组装,因此领域层通常只提供一些原子服务,比如领域服务a、b、c。但随系统功能增强和外部接入越来越多,应用服务不断丰富。终有一日,你会发现领域服务b和c同时多次被多个应用服务调用了,执行顺序也基本一致。这时你可以考虑将b和c合并,再将应用服务中b、c的功能下沉到领域层,演进为新的领域服务(b+c)。这样既减少了服务的数量,也减轻了上层服务组合和编排的复杂度。

这就是服务演进,领域模型会越来越能适应需求快速变化。

从MVC跨越到DDD

由于层间松耦合,可专注本层设计,而不必关心其它层,也不必担心自己的设计会影响其它层。即DDD成功降低层与层之间的依赖。

分层架构使得程序结构更清晰,升级和维护更容易。修改某层代码时,只要本层接口参数不变,其它层不必修改。即使本层接口发生变化,也只影响相邻的上层,修改工作量小且可控。

传统企业应用大多是单体架构,而单体架构则大多是三层架构。三层架构解决了程序内代码间调用复杂、代码职责不清的问题,但这种分层是逻辑概念,在物理上它是中心化的集中式架构,并不适合分布式微服务架构。

DDD分层要类似三层架构,只是在DDD中,这些要素被重新划分了层,确定了层与层之间的交互规则和职责边界。


DDD分层架构相比MVC(只有API)在用户接口层新增了DTO,给前端提供了更多的可使用数据和更高的展示灵活性。

DDD分层架构对三层架构的业务逻辑层进行了更清晰的划分,改善了三层架构核心业务逻辑混乱,代码改动相互影响大的情况。

MVC架构向DDD分层架构演进,主要发生在业务逻辑层和数据访问层。
DDD分层架构将业务逻辑层的服务拆分到了应用层和领域层:

  • 应用层快速响应前端的变化
  • 领域层实现领域模型的能力

数据访问层和基础层之间:

  • 三层架构数据访问采用DAO方式
  • DDD分层架构的数据库等基础资源访问,采用了仓储(Repository)设计模式,通过依赖倒置实现各层对基础资源的解耦。

仓储本身属基础层,但考虑到一个聚合对应一个仓储,为了以后聚合代码整体迁移方便,在微服务代码目录设计时,在聚合目录下增加一个Repository的仓储目录,跟仓储相关的代码都在这个目录下。
这个目录下的代码与聚合的其它业务代码是分开的。如果未来换数据库,只需将Repository目录下的代码替换。而如果聚合需要整体迁移到其它微服务中去,仓储的代码也会一并迁移。

仓储又分为两部分:仓储接口和仓储实现。仓储接口放在领域层中,仓储实现放在基础层。原来三层架构通用的第三方工具包、驱动、Common、Utility、Config等通用的公共的资源类统一放到了基础层。

MVC 到 DDD 具体操作如下:

抽象数据存储层

一般将Data Access层做抽象,降低系统对DB的直接依赖。
举个例子:

  • 新建Account实体对象:一个实体(Entity)是拥有ID的域对象,除了拥有数据之外,同时拥有行为。Entity和数据库储存格式无关。

对象储存接口类AccountRepository:Repository只负责Entity对象的存储和读取,而Repository的实现类完成数据库存储的细节。通过加入Repository接口,底层数据库连接可以通过不同的实现类而替换

参考

相关文章
|
1月前
|
运维 监控 负载均衡
动态服务管理平台:驱动微服务架构的高效引擎
动态服务管理平台:驱动微服务架构的高效引擎
27 0
|
7天前
|
弹性计算 Java 数据库
Web应用上云经典架构实战
本课程详细介绍了Web应用上云的经典架构实战,涵盖前期准备、配置ALB、创建服务器组和监听、验证ECS公网能力、环境配置(JDK、Maven、Node、Git)、下载并运行若依框架、操作第二台ECS以及验证高可用性。通过具体步骤和命令,帮助学员快速掌握云上部署的全流程。
|
1月前
|
消息中间件 Java Kafka
实时数仓Kappa架构:从入门到实战
【11月更文挑战第24天】随着大数据技术的不断发展,企业对实时数据处理和分析的需求日益增长。实时数仓(Real-Time Data Warehouse, RTDW)应运而生,其中Kappa架构作为一种简化的数据处理架构,通过统一的流处理框架,解决了传统Lambda架构中批处理和实时处理的复杂性。本文将深入探讨Kappa架构的历史背景、业务场景、功能点、优缺点、解决的问题以及底层原理,并详细介绍如何使用Java语言快速搭建一套实时数仓。
173 4
|
1月前
|
运维 NoSQL Java
后端架构演进:微服务架构的优缺点与实战案例分析
【10月更文挑战第28天】本文探讨了微服务架构与单体架构的优缺点,并通过实战案例分析了微服务架构在实际应用中的表现。微服务架构具有高内聚、低耦合、独立部署等优势,但也面临分布式系统的复杂性和较高的运维成本。通过某电商平台的实际案例,展示了微服务架构在提升系统性能和团队协作效率方面的显著效果,同时也指出了其带来的挑战。
85 4
|
1月前
|
前端开发 测试技术 数据库
DDD架构中assembler和converter的区别
在 DDD 四层架构模式中,assembler 和 converter 常用于对象转换,但两者在实际项目中的使用较为随意。本文从英文释义、语义区分和模型层区分三个方面探讨了两者的区别,建议按模型层区分,即 Interface 和 Application 层使用 assembler,Infrastructure 层使用 converter,以避免混淆和随意使用。此外,将转换代码抽离为独立方法有助于保持代码整洁和可测试性。
106 1
|
21天前
|
弹性计算 API 持续交付
后端服务架构的微服务化转型
本文旨在探讨后端服务从单体架构向微服务架构转型的过程,分析微服务架构的优势和面临的挑战。文章首先介绍单体架构的局限性,然后详细阐述微服务架构的核心概念及其在现代软件开发中的应用。通过对比两种架构,指出微服务化转型的必要性和实施策略。最后,讨论了微服务架构实施过程中可能遇到的问题及解决方案。
|
1月前
|
Cloud Native Devops 云计算
云计算的未来:云原生架构与微服务的革命####
【10月更文挑战第21天】 随着企业数字化转型的加速,云原生技术正迅速成为IT行业的新宠。本文深入探讨了云原生架构的核心理念、关键技术如容器化和微服务的优势,以及如何通过这些技术实现高效、灵活且可扩展的现代应用开发。我们将揭示云原生如何重塑软件开发流程,提升业务敏捷性,并探索其对企业IT架构的深远影响。 ####
43 3
|
1月前
|
Cloud Native 安全 数据安全/隐私保护
云原生架构下的微服务治理与挑战####
随着云计算技术的飞速发展,云原生架构以其高效、灵活、可扩展的特性成为现代企业IT架构的首选。本文聚焦于云原生环境下的微服务治理问题,探讨其在促进业务敏捷性的同时所面临的挑战及应对策略。通过分析微服务拆分、服务间通信、故障隔离与恢复等关键环节,本文旨在为读者提供一个关于如何在云原生环境中有效实施微服务治理的全面视角,助力企业在数字化转型的道路上稳健前行。 ####
|
20天前
|
Java 开发者 微服务
从单体到微服务:如何借助 Spring Cloud 实现架构转型
**Spring Cloud** 是一套基于 Spring 框架的**微服务架构解决方案**,它提供了一系列的工具和组件,帮助开发者快速构建分布式系统,尤其是微服务架构。
141 68
从单体到微服务:如何借助 Spring Cloud 实现架构转型
|
22天前
|
设计模式 负载均衡 监控
探索微服务架构下的API网关设计
在微服务的大潮中,API网关如同一座桥梁,连接着服务的提供者与消费者。本文将深入探讨API网关的核心功能、设计原则及实现策略,旨在为读者揭示如何构建一个高效、可靠的API网关。通过分析API网关在微服务架构中的作用和挑战,我们将了解到,一个优秀的API网关不仅要处理服务路由、负载均衡、认证授权等基础问题,还需考虑如何提升系统的可扩展性、安全性和可维护性。文章最后将提供实用的代码示例,帮助读者更好地理解和应用API网关的设计概念。
51 8