【DDD】学习笔记-理解领域模型

Eric Evans 的领域驱动设计是对软件设计领域的一次重新审视,是在面向对象语言大行其道时对数据建模的“拨乱反正”。Eric 强调了模型的重要性,例如他在书中总结了模型在领域驱动设计中的作用包括:

  • 模型和设计的核心互相影响
  • 模型是团队所有成员使用的统一语言的中枢
  • 模型是浓缩的知识

显然,模型在领域驱动设计中是设计的起点和关键。但是,该如何才能得到我们心目中能够准确表达业务需求的模型呢?

我们需要认识到模型和领域模型是两个不同层次的概念。如前所述,模型还可以是数据模型或服务模型,这取决于我们观察现实世界业务需求的视角。因此,领域模型是以“领域”为关注核心的模型,是对领域知识严格的组织且有选择的抽象。

领域模型的特征与分类

即便有了这个定义,却没有清晰地说明领域模型到底长什么样子。领域模型究竟是什么呢?是使用建模工具绘制出来的 UML 图?是通过编程语言实现的代码?或者干脆就是一个完整的书面设计文档?

我认为,UML 图、代码与文档仅仅是表达领域模型的一种载体而已,如果绘制出来的 UML 图或者编写的代码与文档并没有传递领域知识,那就不是领域模型。

因此,领域模型应该具备以下特征:

  • 运用了统一语言来表达领域中的概念
  • 蕴含了业务活动和规则等领域知识
  • 对领域知识进行了适度的提炼和抽象
  • 它的建立是一个迭代的演进的过程
  • 能够有助于业务人员与技术人员的交流

既然如此,不管领域模型的表现形式,只要它正确地传递了领域知识,并有助于业务人员与技术人员的交流,就可以说是领域模型。这是一个更不容易犯错误的定义。它其实体现的是一种建模原则。很可惜,这样高屋建瓴的原则并不能指导开发团队运用领域驱动设计。就好似软件设计有个核心原则是“高内聚低耦合”,然而知道这个原则并不能保证你设计出高内聚低耦合的方案。故而诸如这样打太极似的原则与模糊定义,并不能让开发团队满意,他们还是会执着地追问:领域模型到底是什么?

Eric 并没有就此作出正面地解答,但是他在模型驱动设计中提到了模型与程序设计之间的关系:

“模型驱动设计不再将分析模型和程序设计分离开,而是寻求一种能够满足这两方面需求的单一模型。”

这句话说明分析模型和程序设计应该一起被放入到同一个模型中。这个单一模型就是“领域模型”。他反复强调程序设计与程序实现应该忠实地反映领域模型,他写道:

“软件系统各个部分的设计应该忠实地反映领域模型,以便体现出这二者之间的明确对应关系。”

同时,他还要求:

“从模型中获取用于程序设计和基本职责分配的术语。让程序代码成为模型的表达。”

在我看来,设计对领域模型的反映,就是“领域设计模型”;代码对领域模型的表达,就是“领域实现模型”。领域分析模型、领域设计模型与领域实现模型在领域视角下,成为了领域模型中相互引用和参考的不可或缺的组成部分,它们分别是分析建模活动、设计建模活动与实现建模活动的产物。

模型驱动设计非常强调模型的一致性,Eric Evans 甚至认为:

“将分析、建模、设计和编程工作过度分离会对模型驱动设计产生不良影响。”

这正是我将分析、设计和实现都统一到模型驱动设计中的原因。因此,倘若我们围绕着“领域”为核心进行设计,采用的就是领域模型驱动设计,整个领域模型就应该包含领域分析模型、领域设计模型和领域实现模型:

51525288.png

如何表现领域模型

因为交流的目标对象不同,不同的领域模型会有不同的表现形式。文档描述、UML 图与实现代码是最为常见的模型表现形式。但是,这些表现形式仅仅是对领域建模结果的一种呈现。领域模型的目的在于交流,因此更好的方式是引入直观而又具备协作能力的可视化手段,引导领域专家和开发团队参与到领域建模的整个活动中来,而不是由专职的分析师或设计师使用冷冰冰的建模工具绘制 UML 图。通过使用各种颜色的便利贴、马克笔与白板纸等可视化工具,让彩色的领域模型成为一种沟通交流的视觉工具。领域模型中的领域概念、协作关系皆生动形象地活跃在彩色图形上,使得团队协作成为可能,让领域模型更加直观,从而避免沟通上的误差与分歧,使得团队能够迅速就领域模型达成一致。

例如,在运用用例图分析业务逻辑时,就可以用黄色便利贴代表参与者,蓝色便利贴代表主用例,绿色便利贴代表包含用例与扩展用例。便利贴可以在白板纸上自由移动,便于团队的协作和交流:

76339225.png

事件风暴更是将这种可视化手段用到了极致,沿着一条时间线,通过对事件、命令、读模型(Read Model)、流程、策略(Policy)的不断识别,领域专家与开发团队一起探寻业务的真相,绘制出表现业务流程与领域模型的设计画布:

73688849.png

职责驱动设计使用时序图来体现对象之间的协作关系。同样,我们可以用即时贴表达参与协作的对象,在白板上绘制出协作的时序图。如下图所示,我使用不同的颜色表达远程服务、应用服务、领域服务、资源库和聚合:

48761851.png

图中的红色五角星表达一个业务场景只需一个对外公开的接口。多数情况下,这个对外公开的接口就是远程服务。在时序图上,对象之间以箭头表达消息的传递。红色箭头指向的对象,会履行该消息代表的职责,例如 exists() 职责就由该红色箭头指向的 TrainingRepository 对象承担。一个对象如有太多红色箭头指向它,就说明该对象可能承担了太多职责,属于设计的坏味道。同时,我们也需要注意发起消息箭头的对象,它通常代表某个方法的调用者。如果发出了太多消息,说明调用逻辑变得过于复杂,缺少必要的封装层次,同样属于设计的坏味道。图中绘制的蓝色圆圈代表了应用服务发出的调用消息。由于领域驱动设计不允许将业务逻辑封装到应用服务,因此,在一个时序图中应该只能有一个蓝色圆圈。

时序图自身的可视化特征,可以直观地体现职责分配是否平衡。例如,针对一个业务场景绘制的时序图如果过宽,则说明对象的粒度可能太细,增加了不必要的抽象与间接导致协作复杂度增加;如果时序图过窄而高,又可能说明对象的粒度可能太粗,协作仅在有限的几个对象之间完成,没有做到职责的分治。因此,这些可视化特征都能够传递信号,直观地呈现“设计坏味道”,以便于我们对其进行修改和调整。

领域建模的结果固然比过程重要,但如果缺乏高效沟通的建模手段,或许我们根本无法获得正确的领域模型。显然,可视化的表现形式与工作坊的沟通方式可以帮助我们在沟通交流时走出“盲人摸象”的窘境,在团队中传递知识,进而对整个业务系统的领域逻辑达成共识,最终形成领域分析模型与领域设计模型。

至于领域实现模型,则可以通过协作编写测试开始。测试用例体现了具体的业务场景,测试方法的命名更加接近自然语言,Given-When-Then 模式与业务场景的描述非常契合,这就使得领域专家与开发人员结对编程成为了可能。如上一课给出的转账业务场景的测试方法,完全可以是这种协作的产物。在针对业务场景进行测试驱动开发时,可以让开发人员将注意力完全放在业务逻辑的实现上。由于代码仅仅是业务逻辑的表达,领域专家就有能力参与进来,帮助开发人员打磨代码,使得代码的编写满足统一语言的要求。代码即模型,这是领域模型最理想的表现形式,也是领域建模最终的模型产物。

领域模型与统一语言的关系

领域模型之所以被划分为三个模型,源于不同活动中的交流对象与交流重心各不相同。在分析建模活动中,开发团队与领域专家一起工作,通过建立更加准确而简洁的分析模型,直观地传递着不同角色对业务知识的理解。在设计建模活动中,必须基于领域分析模型对模型中的对象做出设计改进,考虑职责的合理分配与良好的协作,建立具有指导意义的设计模型。在实现建模活动中,代码必须是领域设计模型的忠实表现,意味着它其实也忠实表现了领域分析模型蕴含的领域知识。一言以蔽之,让领域分析模型服务于开发团队与领域专家,领域设计模型服务于软件设计人员,领域代码模型服务于程序员。三个模型各司其职,各取所需,它们又都属于领域模型。

在建模过程中,我们需要不断地从“统一语言”中汲取建模的营养,并通过“统一语言”来维护模型的一致性。当开发团队根据领域分析模型建立领域设计模型时,如果发现领域分析模型中的概念未能准确表达领域知识,又或者缺少了隐式概念,就需要调整领域分析模型,使得领域设计模型与领域分析模型保持一致。领域实现模型亦当如此。显然,统一语言为领域模型驱动设计提供了一致的领域概念,使得领域模型在整个软件开发阶段保持了同步:

81361973.png

迭代建模

分析、设计与实现不是割裂开的三个阶段,而是一个迭代建模(Iteration Modeling)过程中的三个建模活动。在战略设计阶段,我们可以通过业务场景识别系统的限界上下文。无论是采用用例场景分析还是事件风暴对限界上下文展开识别,都可以认为是一个自底向上的建模过程。在获得限界上下文的同时,我们也获得了相对细化的用例(或主故事)与初步的领域分析模型。为了避免分析瘫痪(Analysis Paralysis),应将这个过程控制在两周到一个月左右的先启(Inception)阶段完成。

先启阶段结束后,就应该进入针对限界上下文开展领域模型驱动设计的迭代开发。在迭代开发过程中,我们可以根据用户故事结合分析模式与四色建模等手段,进一步细化领域分析模型,然后结合设计模式与设计要素,引入职责驱动设计获得领域设计模型,最后,结合业务场景与设计模型,推进测试驱动开发实践进行编码开发,以小步快速的“红—绿—重构”反馈环不断地改进代码质量和增量开发,快速交付高价值的可运行的功能:

82473387.png

说明:迭代建模与本图参考了 Scott W. Ambler 敏捷建模的思想,参见链接:

http://agilemodeling.com/essays/iterationModeling.htm

迭代建模与迭代的增量开发一脉相承。它避免了在建模过程尤其是分析建模活动中的分析瘫痪,也避免了在设计建模活动中的过度设计,同时还能通过增量快速地开发出新功能来及时获得反馈。获得的领域模型也随着增量开发而不断演化,并始终指导着设计与开发。迭代建模使得建模活动成为迭代开发中不可缺少的一个重要环节,但整个活动却是轻量的,有效地促进了团队成员的交流,符合 Kent Beck 提出的核心价值观——沟通、简单和灵活。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于微信小程序的校园二手交易平台

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

Linux下代码的运行

在Windows环境下,我们代码都是在集成开发环境下运行,也就是说代码的编辑、编译、调试、运行都在一个软件上,而在Linux环境下这些都是分开执行的。 Linux编辑器-vim vim是一款多模式编辑器,vim有很多模式,最常用的三个…

idea: 无法创建Java Class文件(SpringBoot)已解决

第一:点击file-->project Sructure... 第二步:点击Moudules 选择自己需要创建java的文件夹(我这里选择的是main)右键点击Sources,然后点击OK即可 然后就可以创建java类了

【漏洞复现】EasyCVR智能边缘网关用户信息泄漏漏洞

Nx01 产品简介 EasyCVR智能边缘网关是一种基于边缘计算和人工智能技术的设备,旨在提供高效的视频监控和智能分析解决方案。它结合了视频监控摄像头、计算能力和网络连接,能够在现场进行视频数据处理和分析,减轻对中心服务器的依赖。 Nx02 漏…

【深度学习】pytorch 与 PyG 安装(pip安装)

【深度学习】pytorch 与 PyG 安装(pip安装) 一、PyTorch安装和配置(一)、安装 CUDA(二)、安装torch、torchvision、torchaudio三个组件(1)下载镜像文件(2)创建…

智慧自助餐饮系统(SpringBoot+MP+Vue+微信小程序+JNI+ncnn+YOLOX-Nano)

一、项目简介 本项目是配合智慧自助餐厅下的一套综合系统,该系统分为安卓端、微信小程序用户端以及后台管理系统。安卓端利用图像识别技术进行识别多种不同菜品,识别成功后安卓端显示该订单菜品以及价格并且生成进入小程序的二维码,用户扫描…

【芯片设计- RTL 数字逻辑设计入门 7 -- 同步复位与异步复位详细介绍】

文章目录 复位的类型和划分同步复位综合后电路优缺点 异步复位优缺点 异步复位的时序分析(recovery time/removal time)异步复位,同步释放综合后电路优缺点 转自:https://blog.csdn.net/qq_40281783/article/details/128969188 复…

使用Python语言生成区块链地址

# 单次运行 import binascii import sha3 from ecdsa import SigningKey, SECP256k1priv SigningKey.generate(curveSECP256k1) # 生成私钥 pub priv.get_verifying_key() # 生成公钥keccak sha3.keccak_256() keccak.update(pub.to_string()) # keccak_256哈希运算 addr…

计算机视觉讲座PPT分享

最近在电子工业出版社做的《计算机视觉入门路线图》讲座的部分PPT。 主要介绍了计算机视觉的学习基本路线。

github拉取项目,pycharm配置远程服务器环境

拉取项目 从github上拉取项目到pycharmpycharm右下角选择远程服务器上的环境 2.1. 如图 2.2. 输入远程服务器的host,port,username,password连接 2.3. 选择服务器上的环境 链接第3点 注:如果服务器上环境不存在,先创建…

【CV论文精读】EarlyBird: Early-Fusion for Multi-View Tracking in the Bird’s Eye View

【CV论文精读】EarlyBird: Early-Fusion for Multi-View Tracking in the Bird’s Eye View 0.论文摘要 多视图聚合有望克服多目标检测和跟踪中的遮挡和漏检挑战。多视图检测和3D对象检测中的最新方法通过将所有视图投影到地平面并在鸟瞰视图(BEV)中执…

django admin 自定义界面时丢失左侧导航 nav_sidebar

只显示了自定义模板的内容,左侧导航没有显示出来。 原因:context 漏掉了,要补上。 # 错误写法(左侧导航不显示)def changelist_view(self, request, extra_contextNone):form CsvImportForm()payload {"form&qu…

Gitlab和Jenkins集成 实现CI (二)

配置Gitlab api token 配置 Gitlab 进入gitlab #mermaid-svg-QQWExcx5fpZ59Sk7 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#000000;}#mermaid-svg-QQWExcx5fpZ59Sk7 .error-icon{fill:#552222;}#mermaid-svg-QQWExcx5fpZ59Sk7 .e…

ubuntu22.04@laptop OpenCV Get Started: 005_rotate_and_translate_image

ubuntu22.04laptop OpenCV Get Started: 005_rotate_and_translate_image 1. 源由2. translate/rotate应用Demo3 translate_image3.1 C应用Demo3.2 Python应用Demo3.3 平移图像过程 4. rotate_image4.1 C应用Demo4.2 Python应用Demo4.3 旋转图像过程 5. 总结6. 参考资料 1. 源由…

【开源】SpringBoot框架开发校园电商物流云平台

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 商品数据模块2.3 快递公司模块2.4 物流订单模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 商品表3.2.2 快递公司表3.2.3 物流订单表 四、系统展示五、核心代码5.1 查询商品5.2 查询快递公司5.3 查…

【龙年大礼】| 2023中国开源年度报告!

【中国开源年度报告】由开源社从 2015 年发起,是国内首个结合多个开源社区、高校、媒体、风投、企业与个人,以纯志愿、非营利的理念和开源社区协作的模式,携手共创完成的开源研究报告。后来由于一些因素暂停,在 2018 年重启了这个…

JavaScript实现轮播图方法

效果图 先来看下效果图,嫌麻烦就不用具体图片来实现了,主要是理清思路。(自动轮播,左右按钮切换图片,小圆点切换图片,鼠标移入暂停轮播,鼠标移出继续轮播) HTML 首先是html内容&am…

从0开始学Docker ---Docker安装教程

Docker安装教程 本安装教程参考Docker官方文档,地址如下: https://docs.docker.com/engine/install/centos/ 1.卸载旧版 首先如果系统中已经存在旧的Docker,则先卸载: yum remove docker \docker-client \docker-client-latest…

Springboot拦截器中跨域失效的问题、同一个接口传入参数不同,一个成功,一个有跨域问题、拦截器和@CrossOrigin和@Controller

Springboot拦截器中跨域失效的问题 一、概述 1、具体场景 起因: 同一个接口,传入不同参数进行值的修改时,一个成功,另一个竟然失败,而且是跨域问题拦截器内的request参数调用getHeader方法时,获取不到前端…

[CUDA手搓]从零开始用C++ CUDA搭建一个卷积神经网络(LeNet),了解神经网络各个层背后算法原理

文章目录 前言一、所需环境二、实现思路2.1. 定义了LeNet网络模型结构,并训练了20次2.2 以txt格式导出训练结果(模型的各个层权重偏置等参数)2.3 (可选)以pth格式导出训练结果,以方便后期调试2.4 C CUDA要做的事 三、C CUDA具体实现3.1 新建.cu文件并填好…
最新文章