DDD领域驱动

news2024/11/26 13:36:45

为什么需要DDD?

我们经常讲技术为业务服务,架构设计需要对业务充分理解,在面向复杂的业务场景时,会面临诸多问题:

  • 复杂系统设计:业务系统多、业务类型多、业务相互耦合,有没有合适的方法来指导模块的边界开发?
  • 多团队协同:业务系统边界划分不清,系统间依赖复杂,往往一个边界的理解就要扯半天,有没有统一的语言来进行建模,让业务同学和技术同学都看得懂并理解一致?
  • 设计和实现耦合:缺少设计文档,业务及功能性代码混杂,有时业务代码可能不到10%,有没有什么方法可以讲业务需求准确转换为软件设计,有些代码进行有效的聚合,达到业务和技术的平衡?
  • 缺乏灵活扩展:针对频繁变化的业务,有没有什么方法可以有效支持模型和服务如何支持场景的灵活扩展?特别是商业环境、商业流程和规则多变,同时变化不可预测,对架构带来很大挑战
  • 微服务拆分:怎么确定服务的业务边界和应用边界?微服务的拆分粒度应该多大,怎么拆分设计才算合理?
  • 中台规划:如何能够清晰的识别和发现业务模型中的共享和联通部分,定义出哪些共享能力中心?

DDD的价值

  • 统一语言:团队成员会在有界的上下文中有意识的形成统一语言,便于沟通,减少分歧
  • 业务领域知识沉淀:业务通过核心稳定的领域模型,领域知识进行传递,业务相应能力提升
  • 边界清晰的设计方法:用领域模型划分出的边界,来界定那些需求是合理的,哪些需求应该在什么地方实现,不断拉齐团队内成员对需求的认知,让设计更加清晰和规范,分而治之,控制规模
  • 关注点分离:领域模型与数据模型分离,业务复杂度与技术复杂度分离,保持结构清晰,应对不可预测性挑战

DDD核心切入点

DDD中比较关键的几个切入点是通用语言、领域、限界上下文

通用语言 Ubiquitous Language

通用语言解决在业务人员和技术人员协作过程中非常重要的问题,即团队所有人怎么讲同一种语言?通用语言是提炼领域知识的产出物,获得统一语言就是需求分析的过程,也是理解领域知识的过程。团队中各个角色就系统目标、范围与具体功能达成一致的过程。在实际过程中,可能由团队所有相关角色参加,比如领域专家、产品经理、业务架构师、技术架构师、开发人员。

通用语言可以定义公共术语,减少概念混淆,消除歧义和理解偏差,提升需求和知识消化的效率;达到概念和代码的统一语言,连接概念和实现。通用语言也需要行业参考,如果有一些领域模型有通用知识参考,则可简化通用语言的过程。

领域 Domain

领域是来确定范围和边界的,DDD将业务上的问题将其限定归属在特定的边界内,而这划分出来的一个个边界就可以叫做领域。为了降低业务理解和系统实现的复杂度,DDD会将领域进一步划分成更小力度的小问题,也就是子域,子域根据自身重要性和功能属性又可以划分为三类子域:

核心域:决定产品和系统核心竞争力的子域是核心域,它是影响产品和业务成功的主要因素,比如电商系统中关注的会员、商品、订单、交易、库存、营销等
通用域:没有太多个性化的诉求,同时被多个子域使用的通用功能子域是通用域,比如统一的认证和权限管理系统
支撑域:不包含决定产品和公司核心竞争力的功能,也不包含通用功能的子域,但该功能子域又是产品所必须的,它就是支撑域。比如某个特定领域的数据字典。

限界上下文 Bounded Context

我们在平时沟通中为了避免同样的词语产生歧义,我们会把这个词语带入到语言上下文中去理解其语义。比如谈到“苹果”,有人可能想到平时吃的水果,有人也可能想到苹果手机。

限界上下文是一个显式的概念性边界,领域模型都存在于这个边界之内,出了这个边界就不能确保这个含义。而上面提到的通用语言必须限制在这个限界上下文之中。在微服务设计中,一般一个限界上下文理论上就可以设计为一个微服务。

那么有了边界后,我们如何做到领域之间的交互呢?我们通过上下文映射的方式,一般方法有通过合作关系(一荣俱荣,一损俱损)、防腐层(通过一些适配和转换)、共享内核(依赖部分共享的模型)、依赖关系(有组织的上下游依赖)等,其中需要特别关注防腐层,强调单独一层完成上下游的交互,隔离业务逻辑,在实际过程中会比较实用,比如在商品和采购子域提供防腐层,将商品的变更进行收口,隔离后端业务实现。

DDD核心结构概念

实体 Entities

实体是一个具有唯一身份标识的对象,并且可以在相当长的一段时间内持续地变化。我们可以对实体做多次修改,一个实体对象可能和它先前的对象大不相同,但拥有相同的身份标识(identity),依然是同一个实体。对这些对象而言,重要的不是其属性,而是其延续性和标识,我们把这样的对象称为实体。

另外,实体具有可变性,这里需要引出两个概念,贫血模型还是充血模型。贫血模型类似我们熟悉的Bean或者DO对象,一般只有getter和setter方法,只作为保存状态或者传递状态,但并不包含业务逻辑,这种只有数据没有行为的对象不是真正的领域对象, DDD中的实体属于充血模型,会封装包含这个实体相关的所有业务逻辑,它不仅是多个业务属性的载体,也是操作或行为的载体。

值对象 Value Object

值对象用来描述领域的特定方面,并且是一个没有标识符的对象。值对象本质上就是一个集合,这个集合中包含若干个用于描述目的、具有整体概念和不可修改的属性。它可以避免属性零碎,让属性归类更加地清晰,从概念理解上也更加完整。

值对象与实体的区别在于:值对象一般依附于实体而存在, 是实体属性的一部分,而非独立存在。值对象没有唯一标识,当任何属性发生变化时, 都意味着新的值对象产生。值对象功能单一,一般是贫血模型。

聚合 Aggregates

聚合是可以被视为⼀一组单个领域对象的集合,聚合由根实体,值对象和实体组成,作为一个整体被外界访问,。比如一个包含多条记录的订单,每条记录都是单独的对象,但订单(连同所有记录)一起视为单个聚合是有用的(封装业务规则)。

聚合通过定义清晰的所属关系和边界,并避免错综复杂的对象关系⽹网来实现模型的内聚。在聚合边界内,对象之间可以相互引用。聚合之间,聚合根是聚合中唯一允许被外部引用的元素,比如订单ID。

领域服务 Services

领域中的一些概念不太适合建模为对象,即归类到实体对象或值对象,因为它们本质上就是一些操作,一些动作。它们代表了领域中的一个重要的行为,所以不能忽略它们或者简单地把它们合并到某个实体或者值对象中。这些操作或动作往往会涉及到多个领域对象,并且需要协调这些领域对象共同完成这个操作或动作。领域服务还有一个很重要的功能就是可以避免领域逻辑泄露到应用层。因为如果没有领域服务,那么应用层会直接调用领域对象完成本该是属于领域服务该做的操作。

识别领域服务,主要看它是否满足如下特点:服务执行的操作代表了一个领域概念,这个领域概念无法自然地隶属于一个实体或者值对象;被执行的操作涉及领域中的其他对象;操作是无状态的。

领域建模常用方法

todo 实际项目分析补充

用例分析法

用例分析是比较通用的领域建模方法,可以在比较传统需求调研过程中再结合领域模型的设计思路进行,核心是通过通过需求、场景、规则、流程等梳理用例,进而规划领域模型。

首先,用例分析的基础是做好需求调研,大致的步骤如下:

  1. 梳理领域概念:梳理出领域内我们关注的概念、用力的关系,并统一交流词汇,形成统一语言;
  2. 梳理业务规则:梳理出领域内我们关注的各种业务规则,DDD中叫不变性(invariants),比如唯一性规则、促销互斥叠加等;
  3. 梳理业务场景:梳理出领域内的核心业务场景,比如电商领域的订单寻源、库存锁定、商品价格计算等、优惠券核销等业务场景;
  4. 梳理业务流程:梳理出领域内的关键业务流程,比如订单处理流程,分单拆单逻辑,逆向退款逻辑等

用例整理好后,可以根据语义来整理用例,进而整理领域模型,大概步骤如下:

  1. 收集用例:从领域、规则、场景、流程中进行提取,收集相应的名词、动词、形容词
  2. 提取实体:从名词中定位出主要实体,比如商品、SKU、品类等
  3. 提取属性:从形容词中添加实体属性,比如颜色、价格等
  4. 添加关联:动词添加实体和实体之间的关联,比如商品“包含”SKU,卖家“开设”店铺等
  5. 完善模型:识别出初步模型,验证并迭代模型,同时补充用例验证模型、业务流程验证模型

四色建模法

四色建模在实际中也比较常用,有几个核心概念:

时间(Moment-Interval):具有可追溯性的记录运营或管理数据的时刻或时段对象,用粉红色表示
人货场(Party-Place-Thing Archetype):也叫PPT,代表参与到流程中的参与方/地点/物,用绿色表示
角色(Role):在时标型对象与 PPT 对象(通常是参与方)之间参与的角色,用黄色表示
描述(Description):对 PPT 对象的一种补充描述,用蓝色表示

简单说,四色法关注的是,某个人(Party)的角色(PartyRole)在某个地点(Place)的角色(PlaceRole)用某个东西(Thing)的角色(ThingRole)做了某件事情(MomentInterval)

事件风暴法

事件风暴也称为事件建模,类似头脑风暴,可以快速分析复杂业务领域,完成领域建模的目标。关注如下元素:

事件 -> 某个动作的结果
属性-> 事件的输入、输出
命令-> 某个动作
实体-> 命令的触发者

简单理解就是谁(实体)在何时(时间)基于什么(输入)做了什么(命令、动作)产生了什么(输出)影响了什么(事件)。

事件风暴强调正确的人(业务⼈员,领域专家,技术⼈员,架构师,测试⼈员等关键⻆色都要参与其中),开放空间(有足够的空间可以将事件流可视化,让⼈们可以交互讨论),即时贴(至少三种颜色),关联的人充分讨论,集体决策,从价值角度来审视业务流程的合理性,领域事件容易创建业务人员和非业务人员的共识。

DDD分层架构

在这里插入图片描述

展现层:它负责向前台显示信息和解释用户命令,完成前端界面逻辑。展示层的组件实现用户与应用交互的功能。一般建议用MVC,MVP或者MVVM模式来分隔这些组件为子层。
应用层:它是很薄的一层,负责展现层与领域层之间的协调,也是与其它系统应用层进行交互的必要渠道,例如事务、执行单位操作、调用应用程序的任务。应用层要尽量简单,不包含业务规则或者知识,不保留业务对象的状态,只保留有应用任务的进度状态,更注重流程性的东西。它只为领域层中的领域对象协调任务,分配工作,使它们互相协作。类似于Façade模式,调用领域层和基础设施层来完成应用的用例。
领域层:它是业务软件的核心所在,包含了前面提到的核心概念,如领域对象(实体、值对象)、领域服务以及它们之间的关系,负责表达业务概念、业务状态信息以及业务规则,具体表现形式就是领域模型。领域驱动设计提倡充血模型,即尽量将业务逻辑归属到领域对象上。
基础设施层:它向其他层提供通用的技术能力,为应用层传递消息(API 网关等),为领域层提供持久化机制(如数据库资源、中间件交互、缓存、MQ消息)等,屏蔽技术底座能力(如底层服务的健康度检查、配置参数等)。

DDD与传统设计方式不同

DDD给我们带来的是设计模式的改变。DDD的设计模式与传统的面向数据驱动的开发模式有显出区别,这一点特别需要技术同学在具体操作时关注。数据驱动是从数据出发,先梳理ER图,设计数据库表,编写DAO,然后进行业务实现。而领域驱动设计从领域出发,分析领域内模型及其关系,并进行领域建模,设计核心业务逻辑,进而再进行技术细节实现。其核心思想是通过领域驱动设计方法定义领域模型,从而确定业务和应用边界,保证业务模型与代码模型的一致性。在DDD中,领域模型和数据模型是解耦的,有时也不是一一对应,因此,如果一开始应用DDD进行设计时,一定要跳出数据模型优先的束缚,不要让领域模型被数据模型绑架,先设计出合理的领域模型是首要任务。

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

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

相关文章

深度分析高性能计算工程师和传统互联网开发有何不同?

数字化时代来袭,各类开发工程师层出不穷。在移动互联网时代,互联网开发享用了10年的行业红利;在即将到来的超算互联网时代、数字化浪潮汹涌而来的时代,高性能计算工程师这个原本在科研院所熠熠生辉的工程师群体也从技术的神坛走下…

刁钻面试问题?超全接口测试面试题总结+答案,面试看这篇就够了

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 面试题&#xff1…

通过Xshell连接远程服务器搞懂SSH非对称加密的实际应用

最近阿里云服务器即将到期,正好618入手了腾讯云很便宜的轻量级服务器,之前阿里云服务器远程控制都是用Xshell密码登录,这次腾讯云试了试SSH免密登录,还是很好用的,正好借这个机会研究了下SSH原理 SSH是“非对称加密”…

在做性能测试时会遇到的瓶颈

针对网络瓶颈,现在冒似很少,不过也不是没有,首先想一下如果有网络的阻塞,断网,带宽被其他资源占用,限速等情况,应用程序或系统会是什么情况,针对WEB,无非是超时&#xff…

【ros2】ros2环境安装与基础入门

😏★,:.☆( ̄▽ ̄)/$:.★ 😏 这篇文章主要介绍ros2环境安装与基础入门。 学其所用,用其所学。——梁启超 欢迎来到我的博客,一起学习,共同进步。 喜欢的朋友可以关注一下,下次更新不迷…

【RF-SSA-LSTM】随机森林-麻雀优化算法优化时间序列预测研究(Python代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

红帽认证考试难倒你?这些知识点可以帮你一臂之力

话不多说直接上干货,本篇文章适用于备考Linux红帽认证的同学。 常用的RPM软件包命令 常用的Yum命令 systemd与system V init的区别以及作用 如果想要将系统默认的运行目标修改为“多用户的文本界面”模式,可直接用ln命令把多用户模式目标文件链接到/e…

Pytest教程__用例分组(6)

用例分组 pytest进行分组测试的方法是使用装饰器 pytest.mark.标记名称,被标记为相同名称的用例可以看做为同一个组。 分组用例的运行方式是在执行命令中追加 -m "标记名称"的参数。 执行结果如下: 从结果可以看出,未被标记的用例…

aPaaS平台和低代码开发平台是一回事吗?哪个更好?

零代码、低代码、APaaS系统应从哪些指标考察选型?低代码、零代码、APaaS哪一个更好? 零代码、低代码、APaaS的概念在行业内已经流行了很长一段时间。那这3个概念分别指的是什么?企业如果要用该如何选?又有哪些好用的低代码平台推…

Oracle集群管理 -CRSD层进程启动过程与故障分析

1 CRSD启动过程 整体以及依赖关系如图展示: crsd.bin从OCR中获取所需要的资源列表。 crsd.bin启动对应的代理进程。代理进程oraagent_root启动集群的公网资源之后集群的VIP和scan vip资源也被启动。代理进程oraagent_grid启动进而vip对应的listener资源,…

unity制作愤怒的小鸟

文章目录 一、 介绍SpringJoint2D 、line renderer制作发射绳基类bird脚本的基础功能给bird添加飞行拖尾效果pig类游戏胜利的小星星烟花界面摄像机跟随移动游戏失败的界面多种小鸟的制作:黄鸟、绿鸟、黑鸟地图选择关卡选择数据保存制作多个关卡场景异步加载游戏全局…

Unity基础4——LineRenderer

一、参数面板 二、参数介绍 Loop:是否首尾相连 Positions:线段的点 Width:线段宽度曲线的调整 Color:颜色变化 需要搭配材质才有效果 Corner Vertices:角顶点、圆角 此属性指,在一条线中绘制角时使用了…

模块化互联产品 --青翼自研 模拟采集FMC子卡产品资料

FMC121是一款基于FMC标准规范,实现2路14-bit、1GSPS ADC同步采集,2路16-bit 2.5GSPS DAC同步回放功能子卡模块。该模块遵循VITA57.1标准,可直接与FPGA载卡配合使用,板卡ADC器件采用ADI的AD9680芯片,该芯片具有两个模拟…

软件进行验收测试的必要性体现在哪些方面?

在软件开发的过程中,验收测试是一个非常重要的环节。为确认软件是否符合预期需求而进行的一种测试工作。目的是验证软件是否满足其预期功能、性能以及质量等要求。通过对软件进行全面、系统的测试,可以发现和解决软件开发过程中存在的问题和缺陷&#xf…

第19章:索引的创建与设计原则

一、索引的声明与使用 1.1索引的分类 功能逻辑:普通索引,主键索引,唯一索引,全文索引 物理实现方式:聚簇索引和非聚簇索引 作用字段个数:单列索引和联合索引 1.普通索引 对表中的任何字段都可以创建&…

MT6853 (天玑 720)核心板,5G核心板

天玑720是一款中端移动设备的5G入门级体验,采用了7纳米制程,并集成了低功耗的5G调制解调器。它配备了一个八核CPU,其中包括两个主频为2GHz的Arm Cortex-A76大核和6个2GHz的Cortex-A55小核。此外,它还搭载了Mali-G57 MC3的GPU&…

django REST框架- Django-ninja

Django 是我学习的最早的web框架,大概在2014年,当时选他原因也很简单就是网上资料比较丰富,自然是遇到问题更容易找答案,直到 2018年真正开始拿django做项目,才对他有了更全面的了解。他是一个入门有门槛,学…

教程示例:嵌入式软件移植 printf

在嵌入式中printf 这种功能强大的函数可谓是c语言库函数的中的一股清流!也就是太好用了吧!今天分享的例程有 stm32f4ZG 和 cc2530f256,这个两款芯片的移植例程和移植教程!相信你看完后也可以移植到别的芯片去! 使用的…

YouTubeDNN

这个youTubeDNN主要是工程导向,对于推荐方向的业界人士真的是必须读的一篇文章。它从召回到排序整个流程都做了描述,真正是在工业界应用的经典介绍。 作者首先说了在工业上YouTube视频推荐系统主要面临的三大挑战: 1.Scale(规模)&#xff1…

微软ChatGPT技术的底层支撑——GPU

我是荔园微风,作为一名在IT界整整25年的老兵,今天我们来看一看微软ChatGPT技术的底层支撑——GPU。 想要了解GPU,你必须要清楚CPU、GPU、TPU三者的关系。 微软的chatgpt是基于复杂的人工神经网络和强化学习的技术,这是如何运算的…