DDD 领域驱动设计·学习应用·一
责任申明
本文部分资料来源《极客时间的领域驱动设计课程》,目前是一门讲 DDD 的课程,大家可以去购买!我这里通过自己的理解进行下笔记整理和如何应用我们的业务系统场景。
另外资料来源领域驱动设计书和 B 站上的 DDD 领域驱动设计分享。地址传送门:https://www.bilibili.com/video/BV1pf4y1Y75t
背景
之前根据领域驱动设计写过一篇领域驱动设计,但是依旧没有掌握如何去应用到实践工作中!
前一阵正好群里沟通了下发现大家虽然都知道,但是依然是很难落地,或者落地的话也是比较照猫画虎没有一个好的方案。那么今天我也不知道会不会有彩蛋,因为本身 DDD 是一种设计思想。因为思想在实现过程中每个人获得的输入和经历业务场景不同,那么实现方式也会有差距。但是我们是为了去追寻真理,不断的去逼近真相。所以一起看看吧。
一、DDD 体系下架构师要做的事情
1.1、DDD 与微服务设计
1.1.1、熟悉的逻辑架构图
1.1.2、熟悉的接口依赖
1.1.3、熟悉的 DDD 设计
1.1.4、熟悉的 DDD 设计
1.2、DDD 与分层模型设计
1.2.1、六边形架构
图片来源:https://www.jdon.com/ddd/jivejdon/1.html
1.2.2、洋葱架构(简洁架构)
图片来源:https://www.jdon.com/53095
1.2.4、CQRS 架构
CQRS 是命令和查询分离,命令主要实现写入功能,例如新增、修改、删除。
图片来源:https://www.jdon.com/ddd/jivejdon/1.html
1.3、DDD 与业务的理解
1.4、小结
上面的资料是不是看起来很熟悉,或者说我们感觉很高大上,讲了一些东西,但是好像似乎又没吃饱的样子。其实大部分人现在都是,就很多高级架构师目前也都是有着每个人不同的理解。所以我们本篇文章也是结合我学习的东西和理解写,可能之后还需要修正。
二、DDD 名词解析
2.0、知识图谱
2.1、前提知识
题外话:所有的架构书籍以及架构知识都喜欢讲演进架构过程,如果你不知道为啥?其实我这里说下每个架构师都喜欢说的一句话是好的架构是根据业务场景演化出来的,不是一上来就是完美的架构,但是为啥会有这么多的架构设计原则,设计模式,架构思想,那是因为总结了很多业务场景以后的经验,所以很多东西不是一下子就 OK 的,需要有个过程。
这里的架构还可以再借用下 dubbo 官网的架构
在阿里的官网中描述:当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。此时,用于提高机器利用率的资源调度和治理中心(SOA)是关键。这里有个名字叫做流动计算架构,资料来自https://dubbo.apache.org/zh/docsv2.7/user/preface/background/
2.1.1、DDD 的关联
那么问题产生的背景是微服务架构是如何和 DDD 关联起来的呢?我们发现服务好拆,往往通过一个单体服务直接就拆了好几个服务。那么按照我们之前的拆分方式会有比如商城系统,我们会进行根据业务功能拆分,可能拆分结果如下:举例阿里的架构吧。
上面你会发现有很多业务事业部,或者业务单元 XX 中心,那么这些拆分是从业务上来拆分的,没有任何问题。所以我们会诞生很多系统,但是随着时间推移,我们又会在交易中心延伸出非常多的业务需求导致系统臃肿,我们又要如何处理呢?这个时候 DDD 就是来解决这个问题的。因为我们在前几年设计系统的时候基本上的思想都是 Spring 体系下的 MVC 架构思想。但是随着业务 service 层越来越庞大,我们抽离了很多其他层模块,但是每个团队和公司又没有很好的统一,导致系统框架都会多多少少有些黑话,另外在微服务化盛行,和服务治理大行其道的环境中。我们的 DDD 仿佛成了救星一样。
DDD 主要关注:从业务领域视角划分领域边界,构建通用语言进行高效沟通,通过业务抽象,建立领域模型,维持业务和代码的逻辑一致性。
微服务主要关注:运行时的进程间通信、容错和故障隔离,实现去中心化数据管理和去中心化服务治理,关注微服务的独立开发、测试、构建和部署
2.1.2、DDD 不是架构而是一种思想
DDD 是一种处理高度复杂领域的设计思想,它试图分离技术实现的复杂性,并围绕业务概念构建领域模型来控制业务的复杂性,以解决软件难以理解,难以演进的问题。DDD 不是架构,而是一种架构设计方法论,它通过边界划分将复杂业务领域简单化,帮我们设计出清晰的领域和应用边界,可以很容易地实现架构演进。
我们再来回顾下这个 DDD 架构师的工作
DDD 包括战略设计和战术设计两部分。
战略设计主要从业务视角出发,建立业务领域模型,划分领域边界,建立通用语言的限界上下文,限界上下文可以作为微服务设计的参考边界。
战术设计则从技术视角出发,侧重于领域模型的技术实现,完成软件开发和落地,包括:聚合根、实体、值对象、领域服务、应用服务和资源库等代码逻辑的设计和实现。
2.1.3、DDD 与项目管理
2.2、如何实施划分领域模型
三步来划定领域模型和微服务的边界
第一步:在事件风暴中梳理业务过程中的用户操作、事件以及外部依赖关系等,根据这些要素梳理出领域实体等领域对象。
第二步:根据领域实体之间的业务关联性,将业务紧密相关的实体进行组合形成聚合,同时确定聚合中的聚合根、值对象和实体。在这个图里,聚合之间的边界是第一层边界,它们在同一个微服务实例中运行,这个边界是逻辑边界,所以用虚线表示。
第三步:根据业务及语义边界等因素,将一个或者多个聚合划定在一个限界上下文内,形成领域模型。在这个图里,限界上下文之间的边界是第二层边界,这一层边界可能就是未来微服务的边界,不同限界上下文内的领域逻辑被隔离在不同的微服务实例中运行,物理上相互隔离,所以是物理边界,边界之间用实线来表示。
那么根据上面的知识点我进行了提炼:DDD 的核心知识体系,具体包括如下:
领域(多个子域(核心域、通用域、支撑域))
领域(多个限界上下文)
领域(多个聚合(聚合根、值对象、实体等概念))
领域的核心思想就是将问题域逐级细分,来降低业务理解和系统实现的复杂度。通过领域细分,逐步缩小微服务需要解决的问题域,构建合适的领域模型,而领域模型映射成系统就是微服务了。
核心域、支撑域和通用域的主要目标是:通过领域划分,区分不同子域在公司内的不同功能属性和重要性,从而公司可对不同子域采取不同的资源投入和建设策略,其关注度也会不一样。
核心域:决定产品和公司核心竞争力的子域是核心域,它是业务成功的主要因素和公司的核心竞争力
通用域:没有太多个性化的诉求,同时被多个子域使用的通用功能子域是通用域
支撑域:功能子域是必需的,但既不包含决定产品和公司核心竞争力的功能,也不包含通用功能的子域,它就是支撑域。
2.3、如何定义领域内容
DDD 分析和设计过程中的每一个环节都需要保证限界上下文内术语的统一,在代码模型设计的时侯就要建立领域对象和代码对象的一一映射,从而保证业务模型和代码模型的一致,实现业务语言与代码语言的统一
上面的这个图我觉得不太好,目前先挂这里吧,之后添加下我的理解图。
理论上限界上下文就是微服务的边界。我们将限界上下文内的领域模型映射到微服务,就完成了从问题域到软件的解决方案。
举个案例,因为我做过互联网保险比较能理解作者的意图和保险行业领域的业务词汇。我们在保险的流程实际上是主要是四步骤:核保->支付->承保->理赔。保单管理就是承保,核保就是投保。
2.4、如何定义实体
1. 实体的业务形态
在 DDD 不同的设计过程中,实体的形态是不同的。在战略设计时,实体是领域模型的一个重要对象。领域模型中的实体是多个属性、操作或行为的载体。在事件风暴中,我们可以根据命令、操作或者事件,找出产生这些行为的业务实体对象,进而按照一定的业务规则将依存度高和业务关联紧密的多个实体对象和值对象进行聚类,形成聚合。你可以这么理解,实体和值对象是组成领域模型的基础单元。
2. 实体的代码形态
在代码模型中,实体的表现形式是实体类,这个类包含了实体的属性和方法,通过这些方法实现实体自身的业务逻辑。在 DDD 里,这些实体类通常采用充血模型,与这个实体相关的所有业务逻辑都在实体类的方法中实现,跨多个实体的领域逻辑则在领域服务中实现。
3. 实体的运行形态
实体以 DO(领域对象)的形式存在,每个实体对象都有唯一的 ID。我们可以对一个实体对象进行多次修改,修改后的数据和原来的数据可能会大不相同。但是,由于它们拥有相同的 ID,它们依然是同一个实体。比如商品是商品上下文的一个实体,通过唯一的商品 ID 来标识,不管这个商品的数据如何变化,商品的 ID 一直保持不变,它始终是同一个商品。
4. 实体的数据库形态
实体的数据库形态可能和领域建模的实体稍微有出入。
2.5、如何定义值
《实现领域驱动设计》一书中对值对象的定义:通过对象属性值来识别的对象,它将多个相关属性组合为一个概念整体。在 DDD 中用来描述领域的特定方面,并且是一个没有标识符的对象,叫作值对象。
2.5.1、 值对象的业务形态
值对象是 DDD 领域模型中的一个基础对象,它跟实体一样都来源于事件风暴所构建的领域模型,都包含了若干个属性,它与实体一起构成聚合
2.5.2、值对象的代码形态
2.5.3、值的运行形态
2.5.4、数据库形态
在领域建模时,我们可以将部分对象设计为值对象,保留对象的业务涵义,同时又减少了实体的数量;在数据建模时,我们可以将值对象嵌入实体,减少实体表的数量,简化数据库设计。
2.6、如何定义聚合
聚合在 DDD 分层架构里属于领域层,领域层包含了多个聚合,共同实现核心业务逻辑。聚合内实体以充血模型实现个体业务能力,以及业务逻辑的高内聚。
2.7、如何定义聚合根
聚合根主要目的是为了避免由于复杂数据模型缺少统一的业务规则控制,而导致聚合、实体之间数据不一致的问题。
外部对象不能直接访问聚合和实体状态。
版权声明: 本文为 InfoQ 作者【小诚信驿站】的原创文章。
原文链接:【http://xie.infoq.cn/article/4151c8696f1958cd449fd856c】。文章转载请联系作者。
评论