DDD落地实践-架构师眼中的餐厅

news2025/6/8 20:31:21

本文以餐厅场景为叙事主线,以领域驱动为核心思想,结合架构设计与功能设计方法论。是从领域分析到落地的全过程案例,内容偏重于落地,因此不乏一些探讨,欢迎指正。

文章较长、全程干货、耐心读完、必有收获。

本文不针对餐厅的实现细节,重在探讨设计思想和方法。

1、领域设计

让我们抛开技术人员的本能技术视角、站在纯业务视角来分析领域问题。

领域设计的核心是分而治之,目的是实现业务领域的自治性。

就像你平时不会将枕头和被子放在厨房或卫生间一样,你的床上不会放着大米白面,否则你想睡觉是一件很复杂的事情,软件系统也是如此,这就是我们要解决的问题。

1.1 宏观流程

假如我要设计一个餐厅,由于分而治之的需要,我会首先从宏观流程去分析,可以帮我们迅速找到重要的区域。

因此会得到几个明确的行为区域,我将餐厅划分为“菜品域”,“订单域”,“厨房域”,“用餐域”,这是业务级别的领域划分,后续应该针对每个区域单独分析。

产出物是:宏观流程和参与角色

1.2 统一语言

语言贯穿于整个开发过程,从需求分析到设计、从设计到编码,因此好的语言非常重要,好的语言体现了清晰的业务概念。

在这个阶段,我们需要通过梳理,找到业务中都有哪些实体与行为,对其做一些归纳。我们的核心问题是:“谁”通过什么“行为”影响了“谁”,其中的三个要素分别是:角色、行为、实体。 我的建议是先找到 “实体”、“角色”、“行为”,并对其归类,我常常关注角色以及具体身份、实体以及实体实例,功能以及包含的重要步骤。

角色:是施事主语、是名词,是主动发起行为的一类实体。

行为:是动词、是做了什么事情,是行为本身。

实体:是名词,是除“角色”之外的其他实体。

推荐使用脑图画出来,我认为归纳后的脑图有助于我们识别根本要素。

产出物是:名词、概念定义、相关脑图。

1.3 用例分析

在这一步、我们不需要进入用例的细节分析,使用相对宏观的分析,掌握角色与行为之间的关系。

产出物:用例图

以做菜为例,如图

1.4 领域划分

我们在分析宏观流程时,划分了几个行为区域,但那是业务级别的。在那基础之上,我们需要拉进某个区域的视角,再结合之前的用例分析,按照“功能相关性”、“角色相关性”进一步划分领域。

功能相关性:任何业务都是由一套用例组成的,业务的某个领域也不例外,所以领域的划分应该以功能相关性为主,例如与做菜相关的用例都应该归属于厨房,所以我们确认了厨房域,这是很自然的事。

角色相关性:其次是角色,常用于划分子域,某个区域涉及多个角色参与,可以按照角色的分工,拆分为多个子域,从而满足不同角色的个性化需要。例如厨房的采购人员负责买菜、刀工负责切菜、大厨负责烹饪。我们就会考虑将厨房划分为“采购域”、“加工域”、“烹饪域”。

通常来说,子域不具备独立的问题空间,不会作为独立的领域存在。

产出物:领域、子域

以厨房域为例,如图

1.5 领域建模

这是大家比较熟知的阶段,重点分析实体与领域之间关系(领域聚合),实体与实体的关系(OO聚合)。

领域模型是实现功能的基石、需要有对功能的本质理解,才能找到最核心的实体,实体之间的OO聚合关系决定了功能的扩展性,OO聚合是最重要的核心点。

组合、聚合

聚合(aggregation):聚合关系是一种弱的关系,整体和部分可以相互独立。

组合(composition):组合关系是一种强的整体和部分的关系,整体和部分具有相同的生命周期。

可以使用如下案例,既能表达领域聚合,又能表达OO聚合的关系。

产出物:聚合、实体、值对象、实体的属性

(领域服务和事件在后续的功能设计中提供)

1.6 领域上下游

领域上下游关系,不是领域的依赖关系,依赖关系指的是能力的依赖,是共用了某些能力,依赖关系是固定的。领域上下游关系,也不是调用关系,调用关系是与用例相关的,并非描述领域处境的。

领域上下游关系指的是影响力的关系,上游影响下游,影响力分为“逻辑影响”和“数据影响”,一般说来我们更应该关注“数据影响”,所以领域上下游关系是一种数据流向的限定,是业务发生的顺序限定,用于规定该领域所使用的数据,是下游领域依赖上游领域“准备就绪”的体现。合理的上下游限定,有助于减少领域之间的不必要依赖,有利于数据的复用并减少重复计算。

领域上下游是与场景相关的,并不是一成不变的,不同的场景存在不同的上下游,各场景应该独立说明。

产出物:各场景的上下游说明

例:在【菜品管理】场景下

如果厨房的某些食材不足了,或者某个厨师休假了,就会影响到菜品的展示,从而影响到客户的订单。

例:在【客户消费】场景下

客户的订单、影响厨房生产的菜,从而影响刀工的行为,也影响到了采购。

请对比下面两个图,用于理解领域的上下游

实际上,厨师不应该依赖采购人员的采购功能,也不依赖刀工的切菜功能,他只是依赖“初加工食材”而已,而“初加工食材”就是被处理好的数据,厨师在做饭时,“初加工食材”就已经被处理好了,上面的图例只是为了说明一个关于领域上下游的问题,这是业务发生顺序以及数据来源的问题。

我们常常使用领域事件串联业务流程,在使用领域事件时,不止要关注点对点的解耦,更应该使业务流程符合领域上下游限定,让各个领域独立运行,减少领域之间的功能依赖,降低领域之间的耦合,减少业务变化带来的影响。

2、架构设计

架构设计是为了解决软件系统复杂度带来的问题,找到系统中的元素并搞清楚他们之间关系。

架构的目标是用于管理复杂性、易变性和不确定性,以确保在长期的系统演化过程中,一部分架构的变化不会对其它部分产生不必要的负面影响。这样做可以确保业务和研发效率的敏捷,让应用的易变部分能够频繁地变化,对应用的其它部分的影响尽可能地小。

架构设计三原则:合适原则、简单原则、演化原则

2.1 分层架构

我们需要按照 接口层、领域层(领域用例层、领域模型层)、依赖层、基础层 构建架构模型。

接口层:为外部提供服务的入口,是适配层的北向网关。不实现任何业务逻辑,也不处理事务,是跨领域的,是流程编排层,是门面服务。

领域用例层:是领域服务层,是领域用例的实现层、隶属于某个领域、是业务逻辑层,是事务层,业务逻辑应该在这层完整体现,不要分散到其他层级。

领域模型层:是领域模型(实体、值对象、聚合)的所在位置,专注于领域模型自身的能力,不包含业务功能,可以处理事务,是原子化的能力,是领域对象的自我实现

依赖层: 是连接外部服务的出口,是适配层的南向网关。包括仓储,端点、RPC等,主要作用是领域和外部解耦,用于保持领域的独立性,是跨领域的。

基础层:与业务无关的,与领域无关的,通用的技术能力,技术组件等。

2.2 架构映射

架构的视角,从大到小依次是:系统->应用(微服务)->模块(包)->子模块 这样的从大到小的层级。

业务领域映射:我们将划分好的领域,按照对应的视角映射为对应的元素,领域模型映射到架构模型时,应该是视角对等的,如果餐厅是系统、那么厨房就是应用,如果餐厅是应用、那么厨房就是模块。也应该层级匹配的,将用例的实现映射到用例层,将领域模型的实现映射到领域模型层。

技术和抽象问题:有时候、业务领域分析不能体现那些共性的技术问题,所以需要适当结合技术视角,可能需要对领域模型微调。同时、我们需要找到共同需要的基础能力,例如“水”、“电”、“煤气”等等,将这些作为额外的考虑因素,要做到业务问题与技术问题解耦,不要将技术问题和业务逻辑揉成一团。

领域设计,类似餐厅设计师,他设计餐厅有几个区域,区域的用途是什么。

架构设计,类似建筑设计师,他设计如何走水电煤气、如何施工等。

产出物:分层架构图

以厨房为视角,其架构如下

以餐厅为视角,其架构如下

分层架构图,体现逻辑上的层级分布,而不是代表组件的具体含义,组件是应用还是模块、需要结合实际情况而定。

2.3 必要的约束

1、分层架构越往下层就越是稳定的:下层是被上层依赖的,下层不可以反向依赖上层(扩展点除外)。因为分层架构的核心原则是将容易变化的逻辑上浮,将共性的、原子化的、通用的逻辑下沉,被依赖的下层应该是稳定的,这要求上层承接更多业务变化。下层离开上层应该是可以独立存在的,例如在接口层定义的DTO不可以在下层被使用,但领域层定义的实体可以被上层使用。

2、在使用充血模型时,应该符合面向对象编程原则:不要随意的将一些能力都充到领域实体模型中。以“菜”为例,重量和规格是“菜”的自身的属性,激发味蕾是“菜”的能力,“菜”可以维护自身的持久化状态。但是、请注意、“菜”不可以“炒菜”,因为“炒菜”的时候,“菜”还没有出现呢,“菜”不是自己的上帝,“菜”需要被做出来,所以“菜”被做出来之前是没有“菜”的,这是个时间上的概念,不要错把“炒菜”的能力放在“菜”的身上。“炒菜”用到的“水+电+气+食材+调料+厨具”不应该是“菜”的属性范围,这些元素都在“厨房”的范围中,不要让领域的模型包含不属于自身的元素,领域的实体模型只是领域的一部分,只用于实现通用的模型能力。

3、接口层和依赖层是与领域无关的:他们是与技术相关的层级,不属于任何领域,领域也不一定要有这两层,领域也可以独立拥有这两层,这两层不能包含业务逻辑。

4、领域层是与环境无关的:无论某个领域是应用还是模块,都应该具备独立的用例层和独立的模型层,即使多个领域在同一个应用当中,也要按照他们是分别独立去看待,无论是领域是应用还是模块,领域对外部的交互,不可以绕过依赖层和接口层。

5、领域应该是最小完备的:把一个领域拆分为子域、子子域、子子子,,,无限拆分,拆分到一定程度之后,某个子域就不完整了,不完整的子域是不可以独立存在的。拆分不不够或者过度拆分,都是不符合低耦合高内聚原则的。子域只是用于区分边界,所以同一个领域的子域之间不必严格解耦,不需要通过依赖层访问本领域的其他子域,他们之间可以直接调用。

6、领域服务层就是领域用例层:他们俩是同一回事儿,都是用于实现领域内的用例的。不要将领域服务与领域用例视为两个独立的层,也不要将领域服务与领域模型视为同一层,否则会导致逻辑的分散(一部分在领域服务层、一部分在领域模型层、还有一部分可能在用例层),也会导致每个层的职责不明确,容易搞乱。如果将业务逻辑写在领域模型中,会导致业务逻辑进一步下沉,业务逻辑的不确定性太大,是不适合下沉的,是违反分层架构原则的。领域模型对应的是实体、领域服务对应的是用例。

7、领域用例层只能承接符合自身领域的用例:我们划分出领域的目的,就是为了区分每个领域的职责所在,因此他们必须严格按照职责办事,我们在之前已明确了用例和领域之间的关系,需要严格遵守。

8、领域模型层遵循最小依赖原则:只可以依赖必要的资源,必要资源指的是领域模型实现自身能力需要的资源,不包括实现业务逻辑包含的资源。例如领域模型需要依赖DB完成持久化,可以依赖数据访问资源,但不应该依赖其他领域资源、不可以依赖RPC资源等。

2.4 微服务划分

服务划分以领域划分为参考,主要看我们要拆分到什么粒度,这 应该符合低耦合高内聚原则,不破坏领域实体的聚合关系。

产出物:微服务

例如餐厅:餐厅是有必要拆分的,餐厅的“菜品域”,“订单域”,“厨房域”有独立的问题空间。

例如厨房:厨房是没有必要拆分的,厨师与刀工的耦合非常高,他们都在做饭,分开之后是不完整的,分开就是没有必要的。

餐厅被拆分为:厨房(Kitchen)、菜品(Category)、订单(Order)三个微服务,当然还有两个非领域的服务:餐厅门面服务、餐厅基础服务

一般情况下,依赖层不会作为单独的服务,会被以组件的形式嵌入到领域服务之中

3、功能设计(用例实现)

如果说领域设计是餐厅的设计师、架构设计是餐厅的建筑师、那么功能设计就是餐厅的厨师或服务员。

任何设计都要落地到功能设计,如果厨师不守规则,偏偏要去洗手间洗菜,最后的结果依然是一团乱,最终会导致设计无法落地。

功能设计是实现 “面向扩展开放、面向修改关闭” 的途径,是指导研发落地必备环节。

3.1 功能的概念

功能迭代时,功能会发生一些变化,所以他的含义是可能变化的,所以我们需要再次审视功能的概念,及时加以调整。

例如、我们实现了一个“做蛋炒饭”的功能,后来又实现了一个“做辣椒炒蛋”的功能,那么我们应该将功能升级为“炒菜”,甚至是“制作菜品”等。

明确功能的概念,是功能设计的前提。

产出物:更新语言库,更新脑图

3.2 用例的位置

我们在领域分析章节,已明确了用例与角色的关系,用例与领域的关系。

然而一个新功能的加入,我们仍然要再次评估,以确保他处于正确的位置。

产出物:更新用例图

3.3 事件风暴

我们需要深入功能的细节,首推的方法是事件风暴,适用于解构复杂功能。

事件风暴的作用并不限于功能分析,只是我觉得很适用于功能分析,事件风暴的一张图包含很多内容,正好是功能设计所需要的。

将功能拆分为多个子功能(步骤)。(在后续使用)

确认参与该步骤的角色和领域。(在后续的3.6章节落地)

确认步骤的串联流程和领域事件。(在后续的3.6章节落地)

确认参与该步骤的领域实体。(在后续的3.7章节落地)

产出物:事件风暴模型

3.4 用例分析

首先、我们需要关注共性和差异问题,以确保功能的扩展性。

确认用例的泛化+差异点,实现功能的扩展。

寻找共同包含的步骤,实现逻辑的复用。

产出物:用例分析图

例:制作菜品(做大拌菜、做铁锅炖、做炒鸡蛋、做蒸米饭、做炒米饭)

3.5 用例实现类(领域服务类)结构图

专注于用例层的类设计,实现“面相修改关闭,面相扩展开放”。

用例的类结构图是用例分析图的一种映射。

出物:用例层的类结构图

3.6 用例流程图

我们更进一步,将事件风暴模型落实到代码层面。

我们将步骤分配到实现类中、步骤就是该类的一个方法,进一步明确由哪个类和方法来实现该步骤,从而就规定了步骤所在的领域。

我们将步骤和领域事件串联起来,规定了业务实现流程。推荐使用泳道图表达上述内容。泳道的纵向组件是用例的实现类。

这是真实业务流程的映射。

产出物:用例流程图

以炒鸡蛋为例,其用例流程图如下

试想一下、把业务逻辑放在领域模型当中(例如聚合),如何实现“面相扩展开放、面相修改关闭”呢?显然是很难的,功能逻辑和领域实体模型不是同一类技术问题。

3.7 活动图(时序图)

我们进一步将事件风暴模型落实到代码层面,我们使用时序图,体现依赖和调用关系,规定了步骤与领域实体模型的关系,进一步说明用例是如何实现的。

这时候,为了简便、我们可以收起领域服务类(用例层)的泳道。

产出物:时序图、活动图


4、编码实现

编码实现...... 我决定还是...... 偷个懒吧...... 哈哈哈。

但是我们回顾一下之前的内容,是否足够了? 不同的研发人员依照设计去编码,是否会写出不一样的代码?


系统名

餐厅系统

相关应用

厨房应用、菜品应用、订单应用,门面应用、基础应用

系统架构图

厨房应用-领域模型

厨房应用-用例层

厨师模块、刀工模块、买菜员模块

厨房应用-用例层-厨师模块(服务类结构)

厨房应用-用例层-厨师模块(类中的方法、方法含义、执行流程)

厨房应用-用例层-厨师模块(方法的依赖、调用关系)

文章转载自:京东云开发者

原文链接:https://www.cnblogs.com/Jcloud/p/17942507

体验地址:引迈 - JNPF快速开发平台_低代码开发平台_零代码开发平台_流程设计器_表单引擎_工作流引擎_软件架构

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

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

相关文章

鸿蒙OpenHarmony技术—消息机制实现

用户态应用发送消息到驱动 用户态主要代码 struct HdfIoService *serv HdfIoServiceBind(SAMPLE_SERVICE_NAME);......ret serv->dispatcher->Dispatch(&serv->object, SAMPLE_WRITE_READ, data, reply); if (ret ! HDF_SUCCESS) {HDF_LOGE("fail to sen…

16|连接数据库:通过链和代理查询鲜花信息

16|连接数据库:通过链和代理查询鲜花信息 新的数据库查询范式 下面这个图,非常清晰地解释了这个以 LLM 为驱动引擎,从自然语言的(模糊)询问,到自然语言的查询结果输出的流程。 这种范式结合了…

史上最强,Python3+Selenium3+PO+Yaml+DDT自动化测试框架...

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

多领域SCI/EI快刊,1个月录用,12天见刊,1个月检索!

一、材料科学类SCI 【期刊概况】IF:3.0-4.0, JCR3区,中科院4区; 【大类学科】材料科学; 【检索情况】SCI在检; 【录用周期】2-3个月左右录用; 【接收领域】低温环境下新型生物降解材料的开发相关研究均可&#xf…

HarmonyOS4 vp单位计算

我们在harmonyOS中设置宽度等单位时 需要在后面写明具体是什么单位 width("100%")这里 我们就写明了是 百分之百 如果不写 直接给数值 width(100)那么 它就会按vp去读 这里就被读为 100vp vp 之前是一种移动端宽度概念 后面鸿蒙重定义了它的概念 计算公式是 px 乘…

雍禾医疗亮相博鳌论坛 雍禾植发让小城市也能治“毛”病

颜值经济时代,伴随着居民消费水平的提高与受脱发困扰群体的逐步扩张,人们对毛发健康与毛发美观的关注度日益增长。需求催生了毛发医疗行业的飞速发展,为脱发群体提供爱美、求美、变美的新思路、新契机。 近期,2023中国企业家博鳌…

免费在线游戏探索平台

免费在线游戏平台 免费在线游戏平台,上百款游戏随便玩 关于POKI 免费在线小游戏 Poki是个性化的免费在线游戏探索平台。我们每天都会为您精心挑选最新颖的游戏,保证您玩得尽兴!在这里,您不会感到无聊,因为我们将根据…

短期爆发or未来趋势?浅谈音视频小程序在教育行业的应用发展

疫情三年,极大改变了人类的生活方式,尤其是一些线下化程度占比很大的行业,被迫进行信息化甚至数字化的转型。 教育场景数字化逐步成为刚需 经历过了2018年以来的,国家对在线教育行业的监管收紧,以及受益于 5G 技术的发…

向日葵远程工具安装Mysql的安装与配置

目录 一、向日葵远程工具安装 1.1 简介 1.2 下载地址 二、Mysql 5.7 安装与配置 2.1 简介 2.2 安装 2.3 初始化mysql服务端 2.4 启动mysql服务 2.5 登录mysql 2.6 修改密码 2.7 设置外部访问 三、思维导图 一、向日葵远程工具安装 1.1 简介 向日葵远程控制是一款用…

Docker无法启动Postgresql容器

目录 问题描述解决问题 问题描述 拉取了一个Postgresql14.2的镜像,在docker run创建并运行容器之后使用docker ps发现容器没有跑起来,再次使用docker start也没跑起来。 docker run -d --name mypg -v psql-data:/var/lib/postgresql/data -e POSTGRES…

20、Finetuning

微调是指调整大型语言模型(LLM)的参数以适应特定任务的过程,用于改进预训练模型的性能。这是通过在与任务相关的数据集上训练模型来完成的。所需的微调量取决于任务的复杂性和数据集的大小。 PEFT(Parameter-Efficient Fine-Tunin…

2019数据结构----单链表真题

思路&#xff1a; (1)找到中间节点,将原链表一分为二 (2)后半段链表原地逆置 (3)合并链表 #include <stdio.h> #include <stdlib.h>//定义节点类型 typedef struct LNode {int data;//数据域struct LNode *next;//指针域 } LNode, *LinkList;void tailList(Link…

工业 4.0 和数字孪生

在线工具推荐&#xff1a;3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 介绍 没有回头路可走。制造过程正变得越来越数字化。随着这一趋势的发展&am…

LV逻辑卷

一、定义 LVM 是 Logical Volume Manager 的简称&#xff0c;译为中文就是逻辑卷管理。 分区缺点&#xff1a; 1. 无法动态扩容 2. 必须使用连续的空间 3. 没有备份 物理扩展&#xff08;PE&#xff09;&#xff1a; 是逻辑卷的最小单位 1. 物理卷 将硬盘 转化成 pe 2. 卷组 将…

No Magic—复杂机电产品系统架构开发套件

产品概述 CATIA Magic&#xff0c;原名MagicDraw&#xff0c;俗称No Magic&#xff0c;被达索收购后融入3DExperience产品协同研发管理平台中&#xff0c;形成更具协同体验的系统工程解决方案。该软件提供对SysML/UML/UAF语言的完整支持&#xff0c;提供独有的MagicGrid方法论&…

ubuntu远程桌面连接之novnc

一、前言 该操作是为了实现vnc桌面连接为url连接方式&#xff0c;且在浏览器中可以对ubuntu进行操作。在使用novnc进行操作前&#xff0c;需要先安装vnc才可。ubuntu下如何安装vnc&#xff0c;可看博主前面写的一篇文&#xff0c;ubuntu远程桌面连接之vnc-CSDN博客&#xff0c;…

pip install 安装模块包位置及设置Anaconda为默认版本python

01问题 pycharm运行代码找不到模块包pip install不知道安装到哪里了jupyter使用不同版本python 02产生原因 安装了多个版本pythonanaconda本身也带有python 03解决办法 (1)查看当前默认python版本 打开运行窗口Winr&#xff1b; 输入cmd回车&#xff1b; 输入python回车…

【LMM 008】Instruction Tuning with GPT-4

论文标题&#xff1a;Instruction Tuning with GPT-4 论文作者&#xff1a;Baolin Peng, Chunyuan Li, Pengcheng He, Michel Galley, Jianfeng Gao 作者单位&#xff1a;Microsoft Research 论文原文&#xff1a;https://arxiv.org/abs/2304.03277 论文出处&#xff1a;– 论文…

c语言:打印随机3球颜色小程序|练习题

一、题目 给出5种颜色&#xff0c;取出3种颜色进行组合&#xff0c;计算组合的个数。 如图&#xff1a; 二、思路分析 1、3层循环&#xff0c;每一层循环5次(有5个球) 2、排除掉三个球具有同种颜色的情况 三、代码截图【带注释】 四、源代码【带注释】 #include <stdio.h&…

2024年度 ROTS - 实时操作系统 Top 15

RTOS&#xff08;实时操作系统&#xff09;。 这里说的 RTOS 并非新星球大战电影中的机器人&#xff0c;而是物联网设备、航空系统、空中交通管制等背后的无声协调者&#xff0c;就在地球上。 RTOS&#xff0c;或称实时操作系统&#xff0c;设计它们是为了更好的管理资源&…