DDD(3)-领域驱动设计之如何建模

前言

上一篇:从领域驱动到模型驱动中我们讨论到,领域驱动设计的核心思想是保持业务-模型-代码的一致性,模型作为沟通业务和代码的工具,至关重要,今天这篇文章就来讨论DDD中建模的一些思考和方法。

什么是建模

虽然看到这篇文章的读者都是IT从业人员,大家都知道建模是怎么回事,但我还是想先对建模这件事讨论几句,我理解的建模,是对业务中数据流的合适描述。业务是公司的经营活动,但是在软件工程范畴中,当业务人员找到开发说要开发个系统来管理业务的时候,其本质是需要一个能管理业务中数据的系统。因为软件系统唯一能处理的只有数据,它不可能做到把货物从A运到B类似的事情,但它可以通过把“货物从A运到B”这件事情通过数据的方式传递给合适人去完成。因此,我们构建软件系统时唯一关注的是如何处理业务中的数据。业务中的数据具有历史性,即其会随着业务的流转而变化,衍生出新的数据。将业务全周期中的所有数据视为一个集合,不同的业务阶段、业务操作、业务视角都是关注集合中部分数据并筛选出来形成一个子集。例如电商场景中,一个完整的订单流程包含用户浏览商品、下单、付款、物流等阶段,包含商品名称、用户地址、付款渠道、物流明细等数据。但在不同的业务阶段,不同的业务角色只关注部分数据,但因为各参与方都使用同一套系统(同一套数据),因此系统还要关注模型间数据的流转路径。将数据集合进行划分,并描述其变化路径,这就是建模。

什么算好的建模

模型包含数据和行为。模型本质上是一个集合,是为了最大限度满足使用方信息完备要求并且使得系统管理代价最小的平衡结果。这里说得系统管理代价,实际上是指数据规模、信息密度超出人脑处理信息上下文的容量后带来的复杂度急剧上升,从而无法做出有效、正确决策,使得系统和业务的一致性越来越低,使软件系统在错误的道路上越走越远。因此建模的评判标准有三个:1、和业务保持一致;2、信息完备;3、管理代价最小。
“和业务保持一致”:
这里就是DDD中提倡的“共同语言”,创建的模型应该能和业务中的概念术语一一对应,不能自己创造、篡改、臆想出一个模型,应该是业务流程中确实存在、需要的数据子集。数据的流转应该符合业务实际中的数据变化实际,而不能为了技术、性能、方便等理由而强行创建出一条数据流。
“信息完备”是指应该从业务流程出发,将上下文需要的数据都在模型中体现。如果某个数据在节点3处使用,而它是在节点1出产生的,那么它就应该沿着节点1-节点2-节点3的路径流转,而不是在节点3处再去节点1中获取。
“管理代价最小”主要指的是系统复杂度要最小,复杂度的度量有两个指标:模型数量和模型关系,且模型关系对复杂度的影响远大于数量。这里说得复杂度仍然是描述开发人员对系统的理解、掌握、改造时要处理的信息大小。为什么说关系对复杂度的影响远大于数量呢?
一本新华字典的体量远大于一本红楼梦小说,但理解红楼梦的复杂度远大于新华字典。因为字典中收录的汉字都是独立的,前后并无强烈关联。但红楼梦中包含的人物、故事纷纭复杂,想要读懂甚至修改红楼梦需要大师级的文学素养。因此建模时我们应该着力避免模型间的关系,必要时可以用模型的数量来规避关系。

建模方法

由于DDD追求建模和业务的一致性,且愿意使用模型的数量来置换关系以追求系统的复杂度降低,DDD中常采用的建模方法是CQRS(Command Query Responsibility Segregation,命令查询职责分离)和命令-事件模型,。CQRS将系统的功能分为两类:写操作和读查询,每个写操作视为一个命令,是真正的业务流程,只针对写操作建模。而读请求不会对系统造成更改,可以直接从数据层取数据组装返回。大部分系统属于写少读多,运用CQRS的方式会大大降低建模难度。
命令-事件模型将系统中的写操作分类两部分:命令、事件,命令由外部触发,其携带了上下文数据,命令通过执行对系统的状态(数据)产生了变更,由此产生了事件,该事件携带了一些数据,可能被系统中某些部分关注,从而做出反应,这些反应通常也会使用执行命令的方式完成,由此循环往复,把系统中的所有写操作使用命令-事件模型描述清楚。
例如,用户选择商品后点击下单,对于系统来说,用户触发了一个命令,该命令包含了用户和商品等上下文数据,系统需要执行该命令。通过某个命令执行器,将“创建订单”命令执行完毕后,系统中将会保存一份订单数据,还需要广播一个事件“订单已创建”,其将包含已创建订单的关键信息。用户积分管理业务关注“是否有订单创建”这件事,通过合适的方式监听到“订单已创建”事件,将自己要进行的业务操作,也封装成一个命令,通过专有的命令执行器处理自己的业务。
CQRS

为何命令-事件模型适合DDD?

命令-事件模型只是一种建模方法,其可以脱离DDD使用,但因为其具有的几个特点,使得其非常适合应用在DDD中。
1、命令-事件模型只针对写操作建模,符合CQRS思想。
2、命令-事件的万能句式是:xxx操作触发了yyy事件,发生yyy事件时做zzz操作。使用这样的句式能将业务流程、内里变化描述得非常清晰,而且只需要命令、事件两类模型即可完成建模,意味着模型和业务保持一致非常容易。
3、由于建模结果容易理解,且具有很强的业务表达能力,意味着使用代码描述模型将会非常容易,因此更能保证代码和模型的一致性。
4、命令-事件天然具有对应关系,而事件到命令可通过命令总线方式隔离、解耦,使得系统中模型间关系减少,大大降低了系统复杂度。

总结

本篇主要分析DDD中对建模的一些要求,建模首先要保证和业务的一致性,齐次通过减少关系来降低结果复杂度。CQRS+命令-事件模型是目前DDD中的操作性强、适应范围广的,符合DDD核心要求的可落地建模方法。这里推荐一个B站视频:Java8 到 .NET8 - 掌握这个模型你就能设计一切,详细介绍了如何使用命令-事件模型进行建模的细节。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于SSM的高考志愿选择辅助系统

基于SSM的高考志愿选择辅助系统的设计与实现~ 开发语言:Java数据库:MySQL技术:SpringSpringMVCMyBatis工具:IDEA/Ecilpse、Navicat、Maven 系统展示 前台 前台首页 院校展示 后台 后台首页 学校管理 摘要 随着高考制度的不断完…

【Drone】drone编译web端 防墙策略 | 如何在被墙的状态drone顺利编译npm

一、drone编译防墙版本 1、web端drone kind: pipeline type: docker name: ui steps:- name: build_projectimage: node:20-slim depends_on: [clone]volumes:- name: node_modulespath: /drone/src/node_modulescommands:- pwd- du -sh *- npm config set registry https://…

前端使用 Konva 实现可视化设计器(18)- 素材嵌套 - 加载阶段

本章主要实现素材的嵌套(加载阶段)这意味着可以拖入画布的对象,不只是图片素材,还可以是嵌套的图片和图形。 请大家动动小手,给我一个免费的 Star 吧~ 大家如果发现了 Bug,欢迎来提 Issue 哟~ github源码 g…

测试——Selenium

内容大纲: 什么是自动化测试 什么是Selenium Selenium工作原理 Selenium环境搭建 Selenium API 目录 1. 什么是自动化测试 2. 什么是Selenium 3. Selenium工作原理 4. Selenium环境搭建(java) 5. Selenium API 5.1 定位元素 5.1.1 CSS选择器定位元素 5.1.2 XPath定位元…

PHP进阶:前后端交互、cookie验证、sql与php

单词:construct 构造 destruct 摧毁 empty 空的 trim 修剪 strip 清除 slash 斜线 special 特殊 char 字符 query 询问 构造方法(魔术方法) 构造方法是一种特殊的函数&#xff0…

QT 4.8版本的Ubuntu2004编译错误的解决方案

arm-linux-gnueabihf-gcc 5.2编译qt4.8.5_error: ‘class ui::qprintpropertieswidget’ has no m-CSDN博客

k8s中部署nacos

1 部署nfs # 在k8s的主节点上执行 mkdir -p /appdata/download cd /appdata/download git clone https://github.com/nacos-group/nacos-k8s.git 将nacos部署到middleware的命名空间中 kubectl create namespace middleware cd /appdata/download/nacos-k8s # 创建角色 kub…

VScode连接虚拟机运行Python文件的方法

声明:本文使用Linux发行版本为rocky_9.4 目录 1. 在rocky_9.4最小安装的系统中,默认是没有tar工具的,因此,要先下载tar工具 2. 在安装好的vscode中下载ssh远程插件工具 3. 然后连接虚拟机 4. 查看python是否已经安装 5. 下载…

linux代填密码切换用户

一、背景 linux用户账户密码复杂,在不考虑安全的情况下,想要使用命令自动切换用户 二、操作 通过 expect 工具来实现自动输入密码的效果 yum install expect创建switchRoot.exp文件,内容参考下面的 #!/usr/bin/expect set username root…

【状态估计】偏差,匹配和外点

我们都知道:对于状态的估计可能是有偏差的,特别是在运动模型或观测模型是非线性的情况下。在简单的立体相机的例子中,我们看到MAP方法相比于全贝叶斯方法来说是有偏差的。同时,我们也看到批量ML方法对于真实值来说也是有偏差的&am…

openEuler操作系统下Oracle 19c 从19.3补丁更新到19.17

Oracle 19c 从补丁19.3更新到19.17的过程涉及到多个步骤,包括备份、下载补丁、替换OPatch、验证清单信息、冲突检测、空间检测、应用补丁等。以下是一个概括性的流程,但请注意,具体步骤可能会根据实际的Oracle环境、补丁内容和Oracle的官方指…

【接口自动化_07课_Pytest+Excel+Allure完整框架集成_下】

目标:优化框架场景 1. 生成对应的接口关联【重点】 2. 优化URL基础路径封装【理解】 3. 利用PySQL操作数据库应用【理解】--- 怎么用python连接数据库、mysql 4. 通过数据库进行数据库断言【重点】 5. 通过数据库进行关联操作【重点】 一、接口关联&#xff1a…

【数据中心】数据中心的IP封堵防护:构建网络防火墙的基石

数据中心的IP封堵防护:构建网络防火墙的基石 引言一、理解IP封堵二、IP封堵的功能模块及其核心技术三、实施IP封堵的关键策略四、结论 引言 在当今高度互联的世界里,数据中心成为信息流动和存储的神经中枢,承载着企业和组织的大量关键业务。…

【QAC】分布式部署下其他机器如何连接RLM

1、 文档目标 解决分布式部署下其他机器如何连接RLMLicense管理器。 2、 问题场景 分布式部署下QAC要在其他机器上单独运行扫描,必须先连接RLMLicense管理器,如何连接? 3、软硬件环境 1、软件版本:HelixQAC23.04 2、机器环境…

【算法/训练】:前缀和差分

🚀 前言: 前面我们已经通过 【算法/学习】前缀和&&差分-CSDN博客 学习了前缀和&&差分的效相关知识,现在我们开始进行相关题目的练习吧 1. 校门外的树 思路:给[0, n]的数组都标记为1,然后输出m行范围…

基于 PyTorch 的模型瘦身三部曲:量化、剪枝和蒸馏,让模型更短小精悍!

基于 PyTorch 的模型量化、剪枝和蒸馏 1. 模型量化1.1 原理介绍1.2 PyTorch 实现 2. 模型剪枝2.1 原理介绍2.2 PyTorch 实现 3. 模型蒸馏3.1 原理介绍3.2 PyTorch 实现 参考文献 1. 模型量化 1.1 原理介绍 模型量化是将模型参数从高精度(通常是 float32&#xff0…

2024年自动驾驶规划控制面试及答案

自动驾驶行业随着发展越来越卷,在面试前有更多的准备对求职者来说是很有必要的。在即将秋招来临之前给大家整理出了一些新的 自动驾驶规划控制面试题,希望在大家找工作的过程中提供帮助。 持续更新中…… 刷更多的面试题有助于求职者展示自己与公司需求的…

Elasticsearch:Retrievers 介绍 - Python Jupyter notebook

在今天的文章里,我是继上一篇文章 “Elasticsearch:介绍 retrievers - 搜索一切事物” 来使用一个可以在本地设置的 Elasticsearch 集群来展示 Retrievers 的使用。在本篇文章中,你将学到如下的内容: 从 Kaggle 下载 IMDB 数据集…

Linux云计算 |【第一阶段】SERVICES-DAY5

主要内容: 源码编译安装、rsync同步操作、inotify实时同步、数据库服务基础 实操前骤:(所需tools.tar.gz与users.sql) 1.两台主机设置SELinnx和关闭防火墙 setenforce 0 systemctl stop firewalld.service //停止防火墙 sy…

C#类型基础Part2-对象判等

C#类型基础Part2-对象判等 参考资料引用类型判等简单值类型判等复杂值类型判等 参考资料 《.NET之美-.NET关键技术深入解析》 引用类型判等 先定义两个类型,它们代表直线上的一个点,一个是引用类型class,一个是值类型struct public class…