DDD领域设计基础

1概述

作为架构师,我们在业务建模的时候不能完全凭经验、感觉,还得有一套方法论,DDD领域驱动设计恰巧可以作为业务建模的方法论来使用。

2 为什么要使用DDD

2.1 为什么需要DDD

  • 复杂系统设计:系统多,业务逻辑复杂,概念不清晰,有什么合适的方法帮助我们理清楚边界,逻辑和概念?
  • 多团队协调:边界不清晰,系统依赖复杂,语言不统一导致沟通和理解困难。有没有一种方式把业务和技术概念统一,大家用一种语言沟通。例如:航程是大家所理解的航程吗?
  • 设计与实现一致性:PRD,详细设计和代码实现天差万别。有什么方法可以把业务需求快速转换为设计,同时还要保持设计与代码的一致性?
  • 架构统一(可复用和扩展):当前取决于开发的同学具备很好的抽象能力和高编程的技能。有什么好的方法指导我们做抽象和实现。

2.2 DDD的价值

  • 边界清晰的设计方法:通过领域划分,识别哪些需求应该在哪些领域,不断拉齐团队对需求的认知,分而治之,控制规模。
  • 统一语言:团队在有边界的上下文中有意识的形成对事务进行统一的描述,形成统一的概念(模型)。
  • 业务领域的知识沉淀:通过反复论证和提炼模型,使得模型必须与业务的真实世界保持一致。促使知识(模型)可以很好的传递和维护。
  • 面向业务建模:领域模型与数据模型分离,业务复杂度和技术复杂度分离。

3 DDD架构

3.1 分层架构

在这里插入图片描述

  • 用户接口层:对外提供接口,调用应用层完成具体用户请求。包含:controller,远程调用服务等。
  • 应用层APP:尽量简单,不包含业务规则,而只是为了下一层中的领域对象做协调任务,分配工作,重点对象层做编排完成复杂业务场景。包含:AppService,消息处理等。
  • 领域层Domain:负责表达业务概念和业务逻辑,领域层是系统的核心。包含:模型(业务模块),值对象,域服务,事件。
  • 基础层:对所有上层提供技术能力,包括:数据操作,发送消息,消费消息,缓存等。
  • 调用关系:用户接口层-》应用层-》领域层-》基础层
  • 依赖关系:用户接口层-》应用层-》领域层-》基础层

3.2 六边形架构

在这里插入图片描述

  • 六边形架构:系统通过适配器的方式与外部交互,将应用服务和领域服务封装在系统内部。
  • 分层架构:依然是分层架构,核心是改变依赖关系。
  • 领域层依赖导致:领域层依赖基层倒置成基础层依赖领域层,这个简单的变化使得领域层不依赖任何层,其他层都依赖领域层,使得领域层只表达业务逻辑且稳定。

3.3 调用链路

在这里插入图片描述

4 DDD的基本概念

在这里插入图片描述

4.1 领域模型

  • 领域(战略):整体的业务范围,范围就是边界,比如电商业务就是一个电商领域问题。
  • 子领域:领域可大可小,我们将一个领域进行拆解形成子领域,子领域还可以进行拆解。就是一个复杂问题拆解成小的简单的问题的过程。
  • 模型(战术):基于某个业务领域识别出这个业务领域的聚合,聚合根,限界上下文,实体,值对象。

4.1.1 核心域

决定产品和公司核心竞争力的子域就是核心域,它是业务成功的主要因素和公司的核心竞争力。直接对业务产生价值。

4.1.2 通用域

没有太多个性化的诉求,同时被多个子域使用的通用功能子域。例如,权限,登录等等。间接对业务产生价值。

4.1.3 支撑域

支撑其他领域业务,具有企业特性,但不具有通用性,间接对业务产生价值。

4.1.4 为什么要划分核心域、通用域和支撑域

一个业务一定有他最重要的部分,在日常做业务判断和需求优先级判断的时候可以基于这个划分来做决策。例如:一个交易相关的需求和一个配置相关的需求排优先级,很明显交易是核心域,规则是支持域。同样我们认为是支撑域或者通用域的在其他公司可能是核心域,例如权限对于我们来说是通用域,但是对于专业做权限系统的公司,这个是核心域。

4.2 限界上下文(战略)

业务的边界的划分,这个边界可以是一个领域或者多个领域的集合。复杂业务需要多个域编排完成一个复杂业务流程。限界上下文可以作为微服务系统的划分方法。如何进行划分,我的方法是一个界限上下文必须支持一个完整的业务流程,保证这个流程所涉及到的子域都在一个限界上下文中,子域之间可以通过RPC调用。
我们可以把限界上下文看做一个微服务模块的组合,可以把一个或多个限界上下文比作一个微服务系统。

4.3 实体(ENTITY)

  • 定义:实体有唯一的标识,有生命周期且具有延续性。例如一个交易订单,从创建订单我们会给他一个订单编号并且是唯一的这就是实体唯一标识。同时订单实体会从创建,支付,发货等过程最终走到终态这就是实体的生命周期。订单实体在这个过程中属性发生了变化,但订单还是那个订单,不会因为属性的变化而变化,这就是实体的延续性。
  • 实体的业务形态:实体能够反映业务的真实形态,实体是从用例提前出来的。领域模型中的实体是多个属性、行为的载体。
  • 实体的代码形态:我们要保证实体代码形态与业务形态的一致性,那么实体的代码应该有属性和行为,也就是我们说的充血模型。通常的三层架构我们使用的是贫血模型,贫血模型的优点是简洁,但是缺点是业务逻辑分散,更新数据库模型,不符合面向对象的设计原则,高内聚,自己的事情有自己负责。充血模型能够反映业务,但过早依赖数据库操作,而且复杂场景下需要编排领域服务,会导致事务过长影响性能。所以我们使用的充血模型并不是100%的充血模型,而是模型的行为中只涉及业务的逻辑内存操作,数据库操作交给Infrastructure层处理。
  • 实体的运行形态:实体有唯一ID,当我们在流程中对实体属性进行修改,但DI不会变,实体还是那个实体。
  • 实体的数据库形态:实体在映射数据库模型时,一般是一对一,也有一对多的情况。

4.4 值对象(ValueObject)

  • 定义:通过对象属性值来识别的对象,他将多个相关属性组合为一个概念整体。在 DDD 中用来描述领域的特定方面,并且是一个没有标识符的对象,叫作值对象。值对象没有唯一标识,没有生命周期,不可修改,当值对象发生改变时只能替换(例如String的实现)。
  • 值对象的业务形态:值对象是描述实体的特征,多数情况下一个实体有很多属性,这些数据进行分类和聚合后能够表达一个业务含义,方便沟通而不关注细节。
  • 值对象的代码形态:实体的单一属性是值对象,例如:字符串,整型,枚举。多个属性的集合也是值对象,这个时候我们把这个集合设计为一个CLASS,但没有ID。例如商品实体下的航段就是一个值对象。航段是描述商品的特征,航段不需要ID,可以直接整体替换。商品为什么是一个实体,而不是描述订单特征,因为需要表达谁买了什么商品,所以我们需要知道哪一个商品,因此需要ID来标识唯一性。我们看一下下面这段代码,person实体中包含若干个单一属性的值对象,比如Id、name等属性;同时它也包含了复合属性的值对象,比如地址address。
    在这里插入图片描述
  • 值对象的运行形态:值对象创建后就不允许修改了,只能用另外一个值对象来整体替换。当我们修改地址时,从页面传入一个新的地址对象替换调用person对象的地址即可。如果我们把address设计成实体,必然存在ID,那么我们需要从页面传入的地址对象的ID与person里面的地址对像的ID进行比较,如果相同就更新,如果不同先删除数据再在新增数据。
  • 值对象的数据库形态:分为两种方式:嵌入式、序列化大对象。
    1、嵌入式方式:单一值对象以属性嵌入的方式形成人员实体对象,复合地址值对象也直接以属性嵌入的方式放入人员实体中。当我们只有一个地址时使用嵌入式方式比较好,也支持搜索。
    在这里插入图片描述2、序列化大对象方式:序列化大对象的方式形成的人员实体对象,地址值对象被序列化成大对象Json串后,嵌入人员实体中。
    在这里插入图片描述
    支持多个地址存储,不支持搜索。
    值对象的优势和局限
    1)简化数据库设计,提升数据库操作的性能;
    2)虽然简化数据库设计,但是领域模型还是可以表达业务;
    3)序列化的方式会使搜索实现困难(通过搜索引擎可以解决);

4.5 聚合

聚合:有多个实体、值对象逻辑组合在一起的叫做聚合,就一个高内聚的小业务我们可以把他划分成一个聚合。这个聚合里面一定有一个实体是聚合根,聚合根负责聚合内部的管理和聚合外部的对接。聚合和领域的关系:聚合也是范围的划分,领域也是范围的划分;领域与聚合可以是一对一,也可以是一对多的关系。为了保证聚合内部的实体一致性,对外只能通过聚合根进行操作。

4.6 聚合根

聚合根是实体,拥有实体的业务属性和行为,同时也是聚合的管理者,负责协调聚合内的实体和值对象,按照固定的业务规则,完成业务逻辑。
聚合根是聚合对外唯一的接口人,聚合之间以聚合根ID关联的方式接受聚合的外部任务和请求,聚合外不能通过对象引用的方式访问聚合内的对象。需要将关联的聚合根ID作为入参,先访问聚合根,再通过聚合根导航到聚合内部实体

如果聚合根被删除了,他引用的实体和值对象就不会存在了
聚合根所在层的领域服务都可以组合多个实体完成领域逻辑,但为了DDD分层架构的职责单一,聚合根最好只承担聚合管理职能,只实现聚合内实体和聚合根本身相关的业务逻辑,而跨多个实体的复杂领域逻辑统一放到领域服务中实现。
领域建模中,可能存在一些独立的找不到聚合根的实体,但可以根据高度依赖的业务逻辑,把这些实体集合也作为聚合处理。

4.7 领域,限界上下文,子域,聚合,实体,值对象的关系

领域包含限界上下文,限界上下文包含子域,子域包含聚合,聚合包含实体和值对象。
领域-》限界上下文-》子域-》聚合-》实体+值对象

4.8 事件风暴

参与者除了领域专家,事件风暴的其他参与者可以是DDD专家、架构师、产品经理、项目经理、开发人员和测试人员等项目团队成员。
通过业务场景的梳理,找出实体,命令,事件。
领域建模领域建模时,我们会根据场景分析过程中产生的领域对象,比如命令、事件等之间关系,找出产生命令的实体,分析实体之间的依赖关系组成聚合,为聚合划定限界上下文,建立领域模型以及模型之间的依赖。领域模型利用限界上下文向上可以指导微服务设计,通过聚合向下可以指导聚合根、实体和值对象的设计。

5 建模

6 结语

  • 好的模型,可以沉淀组织资产,不好的模型逐渐成为负债。
  • 功能是表象,模型才是内在。
  • 建模的过程是不断猜想和反驳的过程。
  • 演化观点是建模过程的基本心智模式,先完成再完美。

参考

迄今为止最完整的DDD实践

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/558080.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

四信遥测终端入选河南省水利先进实用技术推广目录

近期,河南省水利科技推广中心发布通知,四信自主研发的“遥测终端机RTU”,列入河南省水利先进实用技术推广目录,认定为水利先进实用技术。 四信遥测终端 F9164系列 ●一体化设计 ●工业级设计 ●接口丰富、标准易用 ●大容量储存空…

python爬虫 - 爬取微博热搜数据

文章目录 python爬虫 -爬取微博热搜数据1. 第一步:安装requests库和BeautifulSoup库2. 第二步:获取爬虫所需的header和cookie3. 第三步:获取网页4. 第四步:解析网页5. 第五步:分析得到的信息,简化地址6. 第…

代码随想录阅读笔记-回溯【全排列 II】

题目 给定一个可包含重复数字的序列 nums ,按任意顺序 返回所有不重复的全排列。 示例 1: 输入:nums [1,1,2]输出: [[1,1,2], [1,2,1], [2,1,1]] 示例 2: 输入:nums [1,2,3]输出:[[1,2,3],[1,…

JVM 性能调优命令(jps,jinfo,jstat,jstack,jmap)

常用命令:jps、jinfo、jstat、jstack、jmap jps jps查看java进程及相关信息 jps -l 输出jar包路径,类全名 jps -m 输出main参数 jps -v 输出JVM参数jps命令示例 显示本机的Java虚拟机进程: # jps 15729 jar 92153 Jps 90267 Jstat显示主类…

c 多文件编程

1.结构目录 声明类:用于声明方法,方便方法管理和调用; 实现类:用于实现声明的方法; 应用层:调用方法使用 写过java代码的兄弟们可以这么理解: 声明类 为service层 实现类 为serviceimpl层 应用层 为conlloter层 2.Dome 把函数声明放在头文件xxx.h中&…

外包干了7个月,技术退步明显。。。。。

先说一下自己的情况,本科生,19年通过校招进入广州某软件公司,干了接近4年的功能测试,今年年初,感觉自己不能够在这样下去了,长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…

Spark01

Spark01 一. Spark概述二. Spark环境部署 - Local三. Spark环境部署 - Standalone1. Standalone集群概述2. Standalone环境部署3. 测试环境 四. Spark环境部署 - Standalone-HA1. 安装部署Zookeeper1. 下载2. zookeeper安装3. 配置StandAlone-HA集群 五. Spark On YARN -- 重点…

CSS 实现视差滚动效果

一、是什么 视差滚动(Parallax Scrolling)是指多层背景以不同的速度移动,形成立体的运动效果,带来非常出色的视觉体验 我们可以把网页解刨成:背景层、内容层、悬浮层 当滚动鼠标滑轮的时候,各个图层以不…

Nuclei 减少漏报的使用小技巧

在最近工作的渗透测试项目中发现Nuclei存在一个问题,就是相同的网站连续扫描多次会出现漏报的情况,此前没有注意过这个情况,所以写篇文章记录一下。 在此之前我的常用命令都是一把梭,有就有没有就继续其他测试 $ nuclei -u htt…

锂电池寿命预测 | Matlab基于GRU门控循环单元的锂电池寿命预测

目录 预测效果基本介绍程序设计参考资料 预测效果 基本介绍 锂电池寿命预测 | Matlab基于GRU门控循环单元的锂电池寿命预测 Matlab基于GRU的锂电池剩余寿命预测 基于GRU的锂电池剩余寿命预测(单变量) 运行环境Matlab2020及以上 锂电池的剩余寿命预测是…

【简单介绍下K-means聚类算法】

🌈个人主页: 程序员不想敲代码啊 🏆CSDN优质创作者,CSDN实力新星,CSDN博客专家 👍点赞⭐评论⭐收藏 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共…

​面试经典150题——从前序与中序遍历序列构造二叉树

​ 1. 题目描述 2. 题目分析与解析 二叉树的前序、中序和后序遍历 二叉树的前序、中序和后序遍历是树的三种基本遍历方式,它们是通过不同的顺序来访问树中的节点的。 前序遍历(Pre-order traversal): 访问根节点 前序遍历左子树…

Linux-Stunnel介绍

1、定义 Stunnel是一个自由的跨平台软件,用于提供全局的TLS/SSL服务。针对本身无法进行TLS或SSL通信的客户端及服务器,Stunnel可提供安全的加密连接。该软件可在许多操作系统下运行,包括Unix-like系统,以及Windows。Stunnel依赖于…

15、ESP32 BLE

低功耗蓝牙: 低功耗蓝牙,简称 BLE,是蓝牙的省电版本。BLE 的主要应用是短距离传输少量数据(低带宽)。与经典蓝牙不同,BLE 始终保持睡眠模式,除非启动连接,这使得它消耗的功率非常低。…

智能设备订购如何使药品供应链受益

自从 Covid-19 大流行扰乱全球供应链以来,制药行业对增强弹性的需求变得比以往任何时候都更加重要。药品供应链已经开始数字化转型,采用新技术有助于确保药品和关键物资按时到达目的地并支持长期业务战略。其中一种解决方案是在移动设备上进行智能设备订…

在 Ubuntu 12.10 安装 wxPython

安装 wxPython 可以使用 pip 工具,但在 Ubuntu 12.10 上需要首先安装 wxPython 的依赖项。请注意,Ubuntu 12.10 已于2013年终止支持,建议升级到更高版本的 Ubuntu。以下是在 Ubuntu 12.10 上安装 wxPython 的一般步骤: 一、问题背…

HTML学习笔记:(二)框架实例

2、 框架实例 注意&#xff1a;frameset不能和body标签共存 <frameset>元素是用于创建框架页面的&#xff0c;它允许在一个浏览器窗口中显示多个HTML页面。然而&#xff0c;<frameset>是一种较旧的方式来构建网页&#xff0c;它不符合现代Web标准&#xff08;比如…

【VTKExamples::Meshes】第 十四期 ExtractEdges

很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ:870202403 公众号:VTK忠粉 前言 本文分享VTK样例ExtractEdges,并解析接口vtkExtractEdges,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步! 你的点赞就是我的动力(^U^)ノ~…

深入理解JAVA垃圾收集器CMS,G1工作流程原理 GC流程图 什么社会触发Minor GC?触发MinorGC过程。Full GC 过程。

java CMS&#xff0c;G1垃圾收集器工作流程原理浅析 JVM内存空间基础知识点&#xff08;基于JDk1.8&#xff09; 1.方法区&#xff1a;逻辑概念&#xff0c;元空间&#xff0c;方法区主要用于存储类的信息、常量池、方法数据、方法代码等。方法区逻辑上属于堆的一部分&#xf…

Github 2024-04-15 开源项目日报Top10

根据Github Trendings的统计,今日(2024-04-15统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目4TypeScript项目2HTML项目1JavaScript项目1C++项目1Rust项目1Mojo项目1Fooocus: 图像生成软件 创建周期:188 天开发语言:Python协议…