【DDD】学习笔记-统一语言与领域分析模型

news2024/11/24 1:36:29

无论你采用什么样的软件开发过程,对于一个复杂的软件系统,都必然需要通过分析阶段对问题域展开分析,如此才能有的放矢地针对该软件系统的需求寻找设计上的解决方案。在领域驱动设计中,分析阶段完全围绕着“领域”为中心展开,最终获得的领域模型即领域分析模型。开发团队应该与领域专家一起分析系统的用户需求,然后建立初步的领域分析模型。在进行分析建模时,一个重要参考是整个系统的统一语言(Ubiquitous Language)。

统一语言与领域分析模型

回顾领域驱动的战略设计阶段,我们引入了敏捷开发的先启(Inception)实践促进团队与领域专家以及客户的充分交流。先启阶段的如下活动与提炼领域知识直接相关:

img

通过先启阶段,团队对整个系统的范围、目标与愿景达成了一致,并通过展开识别核心领域(Core Domain)子领域(Sub Domain)对问题域进行了合理的分解。问题域的识别与分解在一定程度上降低了系统的业务复杂度。针对核心领域,结合识别出来的史诗级故事与主故事,我们利用领域场景分析来提炼领域知识,获得整个系统的统一语言

在领域驱动设计中,怎么强调统一语言都不为过!无论是在战略阶段还是战术阶段,我们都能看到统一语言的身影。它是战略设计阶段的重要模式,可以帮助我们梳理业务知识,以此来识别问题域。在识别限界上下文时,是统一语言提出了概念边界,才给了我们判断限界上下文边界的标准。领域模型所要表达的业务概念更是要遵守统一语言,保证分析模型、设计模型与实现模型的一致性。统一语言是领域模型的核心参考!

因此,当我们想要获得领域分析模型时,首先需要参考的就是统一语言,它可以有效地帮助我们识别出整个模型中最核心也是最基本的显式领域概念。

那么统一语言到底出现在哪里?它似乎无处不在,然而正因为此,又似乎缺乏足够明确的规范。就我个人理解,所谓“统一语言”,并非某一种固定格式的交付物,而是领域驱动设计过程中无形的最高设计准绳。为了保证分析与设计的质量,我们需要不停地追问:

  • 我们设计的模型符合统一语言吗?
  • 限界上下文的领域概念遵循统一语言吗?
  • 类名与方法名满足统一语言的规范吗?

这就好比你开车到一个陌生的城市。统一语言就是地图导航,不停地发出声音提醒你行进的方向,当你驶入错误的地方时,它也会及时地修正路线,然后给予你正确的提示。

我在为一家物流公司提供领域驱动咨询时,发现他们对运输的定义未曾形成统一语言。他们认为运输是一个单段运输,整体的一个多式联运则被认为是一项委托。表面看来,委托是客户提出的需求订单,然而经过我和他们一起分析领域概念,发现承运人在确认委托时,需要对整个运输过程制定计划。这个运输可能是从 A 到 B 的铁路运输,也可能是 B 到 C 的公路运输。从 A 到 C 的运输被视为一个多式联运的委托,其中 B 为铁路堆场,C 为货站。由于没有确定统一语言,团队对运输和委托的领域概念混淆不清。

经过分析,我们一致认为应该将运输(Shipment)理解为从起点到终点的整个运输过程,整个运输过程可能会经过多个站点(Station),站点包括堆场和货站,两个站点之间的运输则被称为运输段(Segment)。运输上下文包括运输计划与路径线的管理。堆场和货站是两个完全不同的概念,堆场针对的资源是集装箱,货站针对的资源是件散货。用于装卸货的工作区域和用于存储货物的仓库组成一个独立的货站限界上下文。堆场限界上下文则包含堆场区域信息管理与掏箱、转场和修箱。在运输上下文,堆场和货站被抽象为站点,并不牵涉到站点内部的管理。这就使得运输与站点之间的逻辑互不干扰。

img

在建立了运输上下文的领域模型之后,我们发现铁路运输和公路运输可以合并到同一个运输领域模型中,体现为运输的两种方式。开发团队在日常交流和讨论中提及的委托、规划与计划,其实是同一个概念,定义其统一语言为运输规划

如果希望将统一语言固化到某一个实践中,使之成为我们领域建模的参考,那就是领域场景分析的产物。我在《领域驱动战略设计实践》课程中给出了三种不同的领域场景分析方法:用例、用户故事和测试驱动开发,它们恰好对应了分析、设计与实现三个阶段。因此,对于领域分析模型而言,我们可以参考遵循统一语言的用例。这也正是我为何反复强调用例表达的领域概念必须精准的主要原因。

在战略部分的领域场景分析中,我写道:

在为每个用例进行命名时,我们都应该采纳统一语言中的概念,然后以言简意赅的动宾短语描述用例,并提供英文表达。很多时候,在团队内部已经形成了中文概念的固有印象,一旦翻译成英文,就可能呈现百花齐放的面貌,这就破坏了“统一语言”。为保证用例描述的精准性,可以考虑引入“局外人”对用例提问。局外人不了解业务,任何领域概念对他而言可能都是陌生的。通过不断对用例表达的概念进行提问,团队成员就会在不断的阐释中形成更加清晰的术语定义,对领域行为的认识也会更加精确。

在针对一款供应链产品进行领域分析建模时,资金团队识别出来的部分用例如下所示:

img

:这里绘制的用例图并未采用 UML 的标准用例图形式,各种颜色的便利贴分别代表了参与者、主用例和子用例。我希望通过这种形式再次说明利用可视化工具进行领域建模的重要性。

用例描述要求言简意赅,但并不意味着我们不追求用例描述的精确。图中的付现汇和付票据主用例都包含了“提交银行”子用例。这个用例的描述语焉不详,甚至会被认为是同一个重用的子用例。经过不断交流,才发现这里遗漏了重要的领域概念。付现汇主用例中的“提交银行”子用例其实是“提交收款指令”,而付票据主用例的“提交银行”子用例则是“提交电票指令”。因此,类似用例这样的领域场景分析方法,是领域分析模型的重要源头,若源头被“污染”了,就会影响到领域分析模型的质量。对领域场景的分析,必须字斟句酌,比作家对待写作还要精确与严谨。

无论是用例,还是用例图,只要遵照了这样的分析要求,我们就可以利用“名词动词法”来初步梳理该问题域的领域概念,并获得这些领域概念之间的关系。这种方法由 Russell Abbott 提出,在他 1983 年发表的论文 Program Design by Informal English Description 中,他建议写下问题的英语描述,然后划出名词和动词。名词代表了候选对象,动词代表了这些对象上的候选操作。倘若采用用例分析,则一个用例就是一句英语描述。例如电商系统下订单的用例图如下所示:

59800642.png

用例描述中的名词对应于领域分析模型中的类型或类型的属性。注意,即使是属性,如果该属性表达了一个领域概念,同样应该定义为类型,如“calculate shipping fee”用例中的名词为 Shipping Fee,它是订单(Order)的属性,但它同样体现了“运费”这一个重要的领域概念。用例中的参与者在领域分析模型中同样应该被定义为类型,它与构成主用例宾语的领域概念之间存在关联关系。

比起用例,用例图要更加精炼。若在领域场景分析过程中,以获得用例图为目标,就可以降低领域分析建模阶段的成本。然而,凡事有利就有弊,这种精炼的形式也可能会漏掉一些必要的业务概念。这些业务概念往往是领域模型中主要领域概念的附属概念,如订单(Order)与订单项(OrderItem)、购物车(ShoppingCart)与购物车选项(CartItem)。

在分析用例时,也要注意用例描述可能带来的分析陷阱或隐藏的概念。例如“validate inventory”用例中,宾语为库存(Inventory),但在下订单领域场景中,检查的其实是商品的库存量。当然,这也可能反过来说明在绘制用例图时,我们对用例的描述欠妥当。“notify buyer”用例较为特殊,表面上它表达的领域行为就是“通知买家”,但实际上这里隐藏了一个“通知(Notification)”的名词概念。

综上分析,利用名词动词法自然就能获得如下的分析模型:

img

在这个模型中,我定义了 OrderPlacedNotification 而非 Notification,这是希望清晰地表达下订单场景的通知行为。粗略一看,OrderPlacedNotification 需要包含买家的联系信息和订单内容,似乎足以证明这三者之间存在关联关系。仔细分析,却发现在创建 OrderPlacedNotification 时,确实需要买家和订单的信息,然而一旦创建,它就成了自给自足的通知对象,与模型中的 Buyer 和 Order 再也无关。在领域模型中,没有关系也是一种关系,只要表达了真实的领域逻辑,就是合理的。

在建立领域分析模型时,必须慎重确定类型之间的关系。由于分析活动并未深入太多业务细节,在分析建模过程中,应只考虑显而易见且明确无误的关联关系,如 Order 与 OrderItem、ShoppingCart 与 CartItem,以及在用例图中表达出来的 Buyer 与 Order 之间的关系。除了没有关系这种特殊关系外,模型概念之间的关系不外乎一对一、一对多和多对多。在建立领域分析模型时,最好也能确定具体的关系类型。但是,由于“名词动词法”这种分析建模方法稍显简陋,只适用于领域分析建模的早期。在这个阶段,识别主要的领域概念才是建模的重心,至于关系类型的确定,可以留待领域分析模型的精炼阶段。

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

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

相关文章

RabbitMQ(保姆级教程)

RabbitMQ学习 基础 1. 同步通信和异步通信 同步调用 下一步动作必须依赖上一步 异步调用 通知到位就行,不对消费者做强制要求,只要求最终一致性就行 2. MQ技术选项 消息先进先出,RabbitMQ默认有序 Erlang 是面向并发&#xff0c…

STM32 + ESP8266,连接阿里云 上报/订阅数据

(文章正在编辑中,一点点地截图操作过程,估计要拖拉两三天) 一、烧录MQTT固件 ESP8266出厂时,默认是AT固件。连接阿里云,需要使用MQTT固件。 1、独立EPS8266模块的烧录方法 2、魔女开发板,板载…

备战蓝桥杯---组合数学基础1

让我们来几道高中的组合题吧: 1.我们一定有n个向下,为 2.我们挑最大的两个,条件是他们奇偶性相同,为2*A10,2; 3.用捆绑法即可。 4.我们用隔板法,为 5.问题等价于23个相同的球放到3个盒子里,每个盒子至少…

【北邮鲁鹏老师计算机视觉课程笔记】04 fitting 拟合

【北邮鲁鹏老师计算机视觉课程笔记】04 fitting 拟合 1 拟合的任务 如何从边缘找出真正的线? 存在问题 ①噪声 ②外点、离群点 ③缺失数据 2 最小二乘 存在的问题 3 全最小二乘 度量的是点到直线的距离而不是点在y方向到直线的距离 提示:点到直线的…

ChatGPT偷懒、变慢的罪魁祸首竟然是它?!系统提示词塞满垃圾!

大家好,我是木易,一个持续关注AI领域的互联网技术产品经理,国内Top2本科,美国Top10 CS研究生,MBA。我坚信AI是普通人变强的“外挂”,所以创建了“AI信息Gap”这个公众号,专注于分享AI全维度知识…

【Java程序设计】【C00263】基于Springboot的分布式架构网上商城(有论文)

基于Springboot的分布式架构网上商城(有论文) 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的网上商城 本系统分为管理员功能模块以及系统功能模块。 系统功能模块:在系统首页可以查看首首页、商品信息、购物…

【Git】移除Git中的文件

有的时候需要移除或者更新 Git 中的文件,我们无法直接在远程仓库中移除,移除或者更新操作需要在本地端实现。 1、移除被跟踪文件 当某个文件被添加到暂存区或者本地仓库,此时会被标记为“跟踪状态”,此时 Git 就会代为管理这个文…

肿瘤微环境异质性对治疗反应的影响(综述)

Influence of tumour micro-environment heterogeneity on therapeutic response | Nature 肿瘤的形成涉及肿瘤细胞与细胞外基质、肿瘤血管和免疫细胞的共同进化。肿瘤的成功生长和最终转移并不完全取决于肿瘤细胞的基因改变,还取决于这种突变在特定环境中带来的适…

通过QT制作一个模仿微信主界面的界面(不要求实现具体通信功能)

main.cpp #include "widget.h" #include "second.h"#include <QApplication>int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();//实例化第二个界面Second s;QObject::connect(&w, &Widget::my_jump, &…

STM32F1 引脚重映射功能

STM32 端口引脚重映射 文章目录 STM32 端口引脚重映射前言1、查阅芯片数据手册1.1 串口引脚重映射描述 2、代码部分2.1 核心代码部分 3、实验现象4、总结 前言 在写程序时遇到想要的端口功能&#xff0c;而这个引脚又被其它的功能占用了无法删除掉或直接使用&#xff0c;这种情…

Netty应用(三) 之 NIO开发使用 网络编程 多路复用

目录 重要&#xff1a;logback日志的引入以及整合步骤 5.NIO的开发使用 5.1 文件操作 5.1.1 读取文件内容 5.1.2 写入文件内容 5.1.3 文件的复制 5.2 网络编程 5.2.1 accept&#xff0c;read阻塞的NIO编程 5.2.2 把accept&#xff0c;read设置成非阻塞的NIO编程 5.2.3…

基础IO[一]

文件文件内容属性 文件在硬盘上放着&#xff0c;我们的流程->写代码->编译->运行->访问文件。那么本质上是谁在访问&#xff1f; 是进程在访问。进程访问文件是需要通过接口来访问。 文件在磁盘上放着&#xff0c;要向硬件写入文件&#xff0c;谁有权限呢?必须…

腾讯云4核8G服务器多少钱?2024精准报价

腾讯云4核8G服务器S5和轻量应用服务器优惠价格表&#xff0c;轻量应用服务器和CVM云服务器均有活动&#xff0c;云服务器CVM标准型S5实例4核8G配置价格15个月1437.3元&#xff0c;5年6490.44元&#xff0c;标准型SA2服务器1444.8元一年&#xff0c;轻量应用服务器4核8G12M带宽一…

MySQL-----DCL基础操作

▶ DCL简介 DCL英文全称是Data ControlLanguage(数据控制语言)&#xff0c;用来管理数据库用户、控制数据库的访问权限。 DCL--管理用户 ▶ 查询用户 use mysql; select * from user; ▶ 创建用户 ▶ 语法 create user 用户名主机名 identified by 密码 设置为在任意主机上访问…

在虚拟机上完成Centos安装

Linux学习和使用 前言如何安装Centos初始化操作 使用VMware备份操作系统快照克隆 内容总结参考链接 本人介绍:2023年全国大学生数学建模竞赛国家二等奖,2022年蓝桥杯省二等奖,这里是一个和你一起不断努力,不断前进的程序猿一枚 前言 简单介绍一下本片文章将会讲到的内容:本章节…

通过容器化释放云的力量

NCSC (英国国家网络安全中心) 经常被问到的一个问题是是否在云中使用容器。这是一个简单的问题&#xff0c;但答案非常微妙&#xff0c;因为容器化的使用方式有很多种&#xff0c;其中一些方法比其他方法效果更好。 今天&#xff0c;我们发布了有关使用容器化的安全指南&#…

寒假作业

手写盗版微信登入界面 #include "mainwindow.h" #include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this);this->resize(421,575);this->setFixedSize(421,575);th…

线性表的链式存储结构

顺序存储结构不足的解决方法 顺序存储结构有缺点&#xff0c;最大的缺点是插入删除时需要移动大量元素&#xff0c;会导致时间效率下降。 线性表链式存储结构的定义 线性表的链式存储结构的特点是用一组任意的存储单元存储线性表的数据元素&#xff0c;这些存储单元可以是连…

Impala-架构与设计

架构与设计 一、背景和起源二、框架概述1.设计特点2.框架优点3.框架限制 三、架构图1.Impala Daemon2.Statestore3.Catalog 四、Impala查询流程1.发起查询2.生成执行计划3.分配任务4.交换中间数据5.汇集结果6.返回结果 总结参考链接 一、背景和起源 现有的大数据查询分析工具H…

volatile的实现

字节码层面 ACC_VOLATILE JVM volatile内存区的读写都加了内存屏障 OS和硬件层面 windows lock 指令实现