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

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

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

相关文章

从信息隐藏到功能隐藏

本文主要记录复旦大学张新鹏教授于2022年12月在第三届CSIG中国媒体取证与安全大会上的汇报

微信小程序 民宿预订租赁系统uniApp

通过山青水磨APP办理租房相关业务,线上解决预定、退订的业务,旅客在使用时更加灵活,实现了快速找房,在线沟通、便捷租赁等操作,除此以外,还能帮助旅客获取周边资讯、当地特色活动服务,提升旅客的…

1-3 mininet中使用python API直接拓扑定义以及启动方式对比

作为SDN网络中搭建拓扑非常重要的仿真平台,我们可以使用mininet默认的库内拓扑文件,也可以使用python语言进行自定义拓扑。使用python进行拓扑定义时,不同的定义方式将导致其启动的方式由所不同。 一、采用最原始的命令启动方式: …

Python 视频转场特效处理笔记

本文参考Python-OpenCV 实现美图秀秀视频剪辑效果【特效】_opencv 多张图片 视频 特效-CSDN博客 最近研究了点python处理视频相关的东西,本文展示特效包括,竖向开幕/横向开幕,渐隐/渐显,推近/拉远,方形开幕&#xff0…

yolo层数连接

head [-1,6]连接的是第六层 [-1,4连接的是第四层

在虚拟机上完成Centos安装

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

大模型训练所需的硬件配置

1. 引入 训练一个大模型,到底需要投入多少块GPU,需要多少数据,训练多长时间能达到一个不错的效果? 本文引用靠谱的数据,来回答这些问题。 2. 全流程训练 大模型的训练,简单来说,分为Pretrain…

Peter算法小课堂—单调队列

祝大家新年快乐! 今天这一次有点简单。 单调队列有两个要点,一个是单调,另一个就是我们的队列。 听到队列,我相信大家一定会想到它的好朋友BFS吧。但是……今天……可……没……那么……简单哦。 西佳佳偶像天团1 题目描述 …

第74讲Breadcrumb 面包屑实现

Breadcrumb 面包屑实现 为了实现二级路由,我们搞成搞个子路由,对于二级菜单 const routes [{path: /,name: 首页,component: () > import(../views/layout),redirect:/home,children:[{path: /home,name: 首页,component: () > import(../views…

vtkActor 设置特定图层 显示及置顶显示

问题,有时我们需要显示某个 Actor 在相机最前面,可以遮盖后面的物体;显示在顶层有点不准确;因为这个还相机位置也有关系; 这里讲三种情况: 1. 设置 Mapper 顶层,尝试了一下,可以用于某些场景&…

对话模型Demo解读(使用代码解读原理)

文章目录 前言一、数据加工二、模型搭建三、模型训练1、构建模型2、优化器与损失函数定义3、模型训练 四、模型推理五、所有Demo源码 前言 对话模型是一种人工智能技术,旨在使计算机能够像人类一样进行对话和交流。这种模型通常基于深度学习和自然语言处理技术&…

七、热身仪式(Warm-Up Rituals)

5.Warm Up Rituals 五、热身仪式 A warm up ritual is your per flight checklist you go through before you start focusing for a big session.It may be checking that you have water, that you don’t need to use the bathroom, that your phone is turned off or you’…

基于微信小程序的校园故障维修管理系统的研究与实现

博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…

Sodinokibi(REvil)勒索病毒黑客组织攻击姿势全解

前言 2021年6月 11日,国外媒体 threatpost 发布文章宣称美国能源部 (DOE) 的分包商同时也是美国国家核安全局 (NNSA) 核武器开发合作商的 Sol Oriens 公司遭受到网络攻击,并且 Sol Oriens 公司人员已证实该公司于上月发现被勒索病毒攻击,而国…

Java图形化界面编程——组件绘图原理 笔记

2.8 绘图 ​ 很多程序如各种小游戏都需要在窗口中绘制各种图形,除此之外,即使在开发JavaEE项目时, 有 时候也必须"动态"地向客户 端生成各种图形、图表,比如 图形验证码、统计图等,这都需要利用AWT的绘图功…

深入理解Netty及核心组件使用—下

目录 ChannelHandler ChannelHandler 接口 ChannelInboundHandler 接口 ChannelHandler 的适配器 Handler 的共享和并发安全性 资源管理和 SimpleChannelInboundHandler Bootstrap ChannelInitializer ChannelOption ChannelHandler ChannelHandler 接口 从开发人员的…

重构利器:如何用 Immer 优雅地管理应用状态

1. immer immer 是一个 JavaScript 库,用于处理不可变数据的状态更新。不可变数据意味着一旦创建,数据结构就不能被修改。在编写复杂的应用程序时,不可变性可以带来一系列好处,比如更容易追踪数据的改变、更容易实现撤销/重做功能以及更简单的状态管理。 然而,处理不可变…

更新win11后无法上网

问题描述 系统提示可以更新win11了,然后我就想着更新一下试试。等了好久终于下载完了准备更新,结果提示更新失败,再次更新时下载到一半就停了,然后就发现连不上网了(真服了,win11没更新成功,还…

MATLAB环境下一维时间序列信号的同步压缩小波包变换

时频分析相较于目前的时域、频域信号处理方法在分析时变信号方面,其主要优势在于可以同时提供时域和频域等多域信号信息,并清晰的刻画了频率随时间的变化规律,已被广泛用于医学工程、地震、雷达、生物及机械等领域。 线性时频分析方法是将信…

「C++ 类和对象篇 10」初始化列表

目录 一、什么是初始化列表? 二、为什么需要初始化列表? 三、初始化列表怎么使用? 3.1 在构造函数中使用初始化列表 3.2 注意 3.3 结论 3.4 应用场景 四、初始化列表的初始化顺序 五、另一种初始化成员变量的方法 【总结】 一、什么是初始化…