searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

DDD领域驱动设计的理论解读

2023-06-12 07:42:03
62
0

DDD是什么

DDD领域驱动设计(Domain Driven Design)是一种架构设计方法论,DDD围绕业务概念构建领域模型来控制业务的复杂性,通过领域模型将物理世界的真实业务同构映射成虚拟世界的代码实现,从而构建更易维护的系统。DDD通过边界划分将复杂业务领域简单化,帮我们设计出清晰的领域和应用边界,可以很容易地实现架构演进。
DDD 包括战略设计和战术设计两部分,战略设计主要从业务视角出发,建立业务领域模型,划分领域边界,建立通用语言的限界上下文。战术设计则从技术视角出发,侧重于领域模型的技术实现,完成软件开发和落地,包括:聚合根、实体、值对象、领域服务、应用服务和资源库等代码逻辑的设计和实现。

软件架构的演进

在解读DDD领域驱动设计的具体思想之前,我们先来回顾下软件架构模式的演进:
第一阶段:单机架构
采用面向过程的设计方法,系统包括客户端 UI 层和数据库两层,采用 C/S 架构模式,整个系统围绕数据库驱动设计和开发,并且总是从设计数据库和字段开始。
第二阶段:集中式架构
采用面向对象的设计方法,系统包括业务接入层、业务逻辑层和数据库层,采用经典的三层架构,也有部分应用采用传统的 SOA 架构。这种架构容易使系统变得臃肿,可扩展性和弹性伸缩性差。
第三阶段:分布式微服务架构
随着微服务架构理念的提出,集中式架构正向分布式微服务架构演进。微服务架构可以很好地实现应用之间的解耦,解决单体应用扩展性和弹性伸缩能力不足的问题。
在单机和集中式架构时代,系统分析设计和开发往往是独立、分阶段割裂进行的。比如,在系统建设过程中,我们经常会看到这样的情形:A 负责提出需求,B 负责需求分析,C 负责系统设计,D 负责代码实现,这样的流程很长,经手的人也很多,很容易导致信息丢失。最后,就很容易导致需求、设计与代码实现的不一致,往往到了软件上线后,我们才发现很多功能并不是自己想要的,或者做出来的功能跟自己提出的需求偏差太大。而且在单机和集中式架构这两种模式下,软件无法快速响应需求和业务的迅速变化。也是正在这些背景下,微服务架构和敏捷开发的模式逐步流行起来。
 

同构映射与领域划分

进入微服务架构时代以后,微服务架构解决了原来采用集中式架构的单体应用的很多问题,比如扩展性、弹性伸缩能力、小规模团队的敏捷开发等等。
但在看到这些好处的同时,微服务实践过程中也产生了不少的争论和疑惑:微服务的粒度应该多大?微服务到底应该如何拆分和设计?微服务的边界应该在哪里?
那如何确定,是否有相关理论或知识体系支持呢?
在回答这些问题之前,我们先来了解一下领域驱动设计与微服务的前世今生。2004 年埃里克·埃文斯(Eric Evans)发表了《领域驱动设计》(Domain-Driven Design –Tackling Complexity in the Heart of Software)这本书,从此领域驱动设计(Domain Driven Design,简称 DDD)诞生。DDD 核心思想是通过领域驱动设计方法定义领域模型,从而确定业务和应用边界,保证业务模型与代码模型的一致性,业务模型和代码模型的同构映射能够保证在业务变更的时候只需要在代码层面做小范围可控的变更。
但 DDD 提出后在软件开发领域一直都是“雷声大,雨点小”!直到微服务架构流行起来后,DDD 才真正迎来了自己的时代。有些熟悉 DDD 设计方法的软件工程师在进行微服务设计时,发现可以利用 DDD 设计方法来建立领域模型,划分领域边界,再根据这些领域边界从业务视角来划分微服务边界。而按照 DDD 方法设计出的微服务的业务和应用边界都非常合理,可以很好地实现微服务内部和外部的“高内聚、低耦合”。于是越来越多的人开始把 DDD 作为微服务设计的指导思想。现在,很多大型互联网企业已经将 DDD 设计方法作为微服务的主流设计方法了。DDD 也从过去“雷声大,雨点小”,开始真正火爆起来。
 

关键概念

代码模型

按照 DDD 分层架构模型设计出来的微服务代码模型到底长什么样子呢?其实,DDD 并没有给出标准的代码模型,不同的人可能会有不同理解。
相关代码结构可以参考:《解构领域驱动设计》作者张逸的示例工程https://github.com/agiledon/eas-ddd
这里对其中的几个关键概念补充一些说明
Aggregate(聚合):它是聚合软件包的根目录,可以根据实际项目的聚合名称命名,比如权限聚合。在聚合内定义聚合根、实体和值对象以及领域服务之间的关系和边界。聚合内实现高内聚的业务逻辑,它的代码可以独立拆分为微服务。以聚合为单位的代码放在一个包里的主要目的是为了业务内聚,而更大的目的是为了以后微服务之间聚合的重组。聚合之间清晰的代码边界,可以让你轻松地实现以聚合为单位的微服务重组,在微服务架构演进中有着很重要的作用。聚合的方式也使得在微服务工程内部也有明确的边界,如果继续采用MVC的方式实现微服务那往往会让微服务后期陷入维护扩展困难的局面。
Entity(实体):它存放聚合根、实体、值对象以及工厂模式(Factory)相关代码。实体类采用充血模型,同一实体相关的业务逻辑都在实体类代码中实现。跨实体的业务逻辑代码在领域服务中实现。
Service(领域服务):它存放领域服务代码。一个领域服务是多个实体组合出来的一段业务逻辑。你可以将聚合内所有领域服务都放在一个领域服务类中,你也可以把每一个领域服务设计为一个类。如果领域服务内的业务逻辑相对复杂,我建议你将一个领域服务设计为一个领域服务类,避免由于所有领域服务代码都放在一个领域服务类中,而出现代码臃肿的问题。领域服务封装多个实体或方法后向上层提供应用服务调用。
Repository(仓储):它存放所在聚合的查询或持久化领域对象的代码,通常包括仓储接口和仓储实现方法。为了方便聚合的拆分和组合,一般遵循一个聚合对应一个仓储的原则。
0条评论
0 / 1000
刘****海
6文章数
0粉丝数
刘****海
6 文章 | 0 粉丝