07 领域建模原理:DDD领域建模和传统方法有什么区别?
你好,我是钟敬。
前面几节课,我们一起完成了行为需求和领域建模,重点在于实践。但是,如果仅停留在实践层面,不去了解背后的原理,我们就会知其然而不知其所以然,最终还是不能很好地进行实践。
所以,在对领域建模有了一定的感性认识以后,今天我们上升到理论层面,一起来理解模型驱动设计的本质含义。然后再来深入探讨“统一语言”,以及它和领域建模的关系。
什么是领域模型?
在讨论什么是领域模型之前,咱们先说说什么是模型。
先来看几个例子。比如说你去买房,售楼处都会有一个沙盘模型,这样你就可以看到楼的外观、朝向、周边环境等等。
但是如果要盖这个楼盘,靠沙盘模型就不行了,需要有一套详细的建筑图纸,图纸也是模型。为了对大楼进行设计,还要进行各种计算,计算用的公式也是模型,称为数学模型。另外,小孩玩的玩具车、玩具枪什么的,也是模型。事实上,现代生产和生活中,充满着各种各样的模型。
从这些例子里,咱们可以发现模型的几个共同特点。
首先,模型是以解决特定问题为目的的。例如沙盘模型是为了卖房,而建筑图纸是为了盖楼。没有目的就谈不上模型。
第二,模型都是对现实世界或人们思维中的事物进行的模拟。例如沙盘模型和建筑图纸都是对建筑物的模拟,而玩具车是对真车的模拟。
第三,模型总是提取了被模拟事物中的部分信息,而忽略掉了其他大部分信息。例如,沙盘模型提取了楼盘的外观信息,但是忽略了内部结构和建筑材料信息。而建筑图纸反映了内部结构信息,但忽略了外观信息。到底提取哪些信息,忽略哪些信息,取决于模型的目的。
第四,模型可以有多种表现形式,例如图纸、影像、公式以及电脑中的文件等等。具体采用哪种形式,取决于要解决的问题和当前的技术水平。
最后,模型是一种人造物,大自然本身是不存在模型的。
软件开发是一个建模过程
说到这儿,不知道你发现了没有?其实计算机软件也是一种模型。这是因为,计算机软件也是为了满足业务需求,对现实世界的事物和逻辑进行的模拟。所以,我们开发计算机软件的过程也是一个建模过程。
软件本质上是运行在机器上的一串二进制流,我们姑且称之为“机器模型”。我画了一张图,表示了现实世界和机器模型之间的关系。
我们看到,在机器模型和丰富多彩的现实世界之间存在着巨大的鸿沟,所以,用二进制直接为现实世界建模是非常困难的,这也是软件开发如此困难的原因之一。
那么,如何克服这一障碍呢?打个比方,假如我们想爬到房顶上去,太高了上不去怎么办,那就搬个梯子,一步一步地爬上去。
软件开发的道理是一样的。可以把由现实世界到机器模型的过程分成几步,一步一步地走。传统软件工程中,从现实世界到机器模型的过程,一般是这样的:
第一步是捕获行为需求,研究为了满足业务需求需要有怎样的流程和功能,可以用传统的用例分析来做,也可以用咱们这里的事件风暴。
第二步是分析,在行为需求的基础上,对现实世界中领域知识或者说业务概念进行分析和提炼,形成分析模型。尽管分析模型反映的仍然是业务概念,然而是经过抽象得来的,更加严谨、精练和一致,因此比行为需求更加接近实现。
第三步是设计,在分析模型的基础上,增加技术关注点,进行架构设计、详细设计、数据库设计等,形成设计模型。设计模型介于分析模型和代码之间。
第四步是编写代码。代码经过编译后,就成为了运行在机器上的“机器模型”了。
其实,第二步中的分析,就是对领域知识的抽象和提炼的过程,所以分析模型也可以称为领域模型,这个过程也可以叫做领域建模。
但是,很多伙伴在开发软件时,并没有经过领域建模这一步,而是直接进行设计和编码。如果是简单系统的话还可以,如果是复杂系统,就会出现很多问题了。
DDD领域模型与传统方法的不同之处
看到这儿你可能会问了,既然传统软件工程也有领域模型,那DDD的领域模型与传统的方法又有什么不同呢?
这两者之间有一个重要区别:DDD强调领域模型要兼顾业务和技术两个视角。
在传统软件工程里,建立分析模型强调完全从业务领域出发,不考虑技术视角。然后,才会把分析模型交给技术专家,转化为设计模型。两者的关系如下图:
这种方法虽然在理论上是完备的,但实践中常常会有问题。由于在分析阶段没有从技术视角考虑,那么在转化为设计模型的时候,就可能发现有些分析模型很难实现,需要通过复杂的转换,才能适应软件开发的要求,因此两种模型之间就产生了比较大的差距。
所以,在之后的开发过程中,开发人员往往只是聚焦于设计模型,而将分析模型束之高阁。时间久了,分析模型与系统实现之间的差异越来越大,也就失去了存在的意义。最终,技术实现与业务越来越远,软件系统也就难以真实反映业务需求了。
但是,DDD的领域模型则是业务视角(原来的分析模型)和技术视角(原来的设计模型)的交集。它反映了业务人员和技术人员的共识。
尽管技术人员仍然要为领域模型增加实现细节,形成设计模型,但设计模型必须严格遵循领域模型。对领域模型的修改,必须由业务和技术双方达成一致。这样,就避免了传统软件工程中分析模型和设计模型相互割裂的风险,如下图:
为了表达DDD的侧重点,我们把传统的软件开发过程修改为下面这样:
在这个图中,我们直接用领域建模代替了原来的分析步骤。同时,把原来的设计和编码合并成了模型的实现,这是因为,从敏捷的角度来看,设计和编码常常会融合在一起。
模型驱动设计
围绕领域模型进行开发的方法,在DDD中称为模型驱动设计(Model-Driven Design),是DDD的核心模式之一。这个模式可以概括为两点:
- 领域模型要和业务需求一致;
- 系统实现要和领域模型一致。
领域模型要和业务需求一致
首先我们来看看领域模型和业务需求一致。
DDD非常重视对业务需求中领域知识的消化。虽然我们从事件风暴就开始消化了,但领域建模才是消化知识的核心。在这个过程中,事件风暴里遗留的不清晰的部分会得到解决,并且还会发现新的知识。
事实上,事件风暴和领域建模有一个重要的区别:事件风暴仅仅追求“形似”,也就是说业务是怎样运作的,事件风暴就怎样反映。
而领域模型不仅要和需求“形似”,更要“神似”。也就是说,领域模型不仅要对业务进行直观模拟,更要经过提炼,形成浓缩的知识。
什么意思呢?这里主要是指两点,
第一点,是通过抽象思维得到更“深刻”的模型。比如说,我们从企业、开发中心等概念中抽象出组织和组织类别,从人事人员、销售人员中抽象出岗位等等。这使模型中的知识不再停留在业务的表面,而是深入到业务的本质,有利于开发出更加灵活简洁的系统。
第二点,是通过深入思考得到更“丰富”的模型。比如说,我们通过分析“取员工上级”的操作,识别出了员工和组织之间关于组织负责人的关联。另外,作为领域知识的一部分,我们还补充了更多的业务规则,这些都使模型更加丰富。蕴含丰富知识的领域模型,可以让我们在开发的时候不容易遗漏重要的领域概念和规则。
另外,领域模型和业务相一致,必须通过业务人员和技术人员的协作才能完成。业务人员的参与,能为领域模型带来专业的领域知识,而技术人员可以为领域模型带来更高的抽象性和严谨性。
而且,技术视角的加入还为领域模型的选择提供了参考。前面我们说过,模型是一种人造物。既然是人造的,就会带入主观因素,对于同一业务,可能会构建出不同形式的领域模型,这些模型可能都“对”,关键在于哪一个“更好”。这时候,技术人员从技术视角出发,往往可以发现,有些模型更容易进行技术实现。所以,尽管领域模型中都是业务概念,却可以通过技术视角选出更恰当的模型。
系统实现和领域模型一致
模型驱动设计的第二个要点是系统实现和领域模型一致。
如果修改了领域模型,那么系统实现必然也要修改;反之,如果系统实现发生了变化,也很有可能导致模型的变化。
这背后还隐含了一个推论:领域模型中的每个元素,都应该通过某种方式在系统实现中有所体现。反过来说,如果发现领域模型中的某个元素不需要落实到实现里,那么就应该在领域模型里删除这个元素。这也是技术人员参与到领域建模中的一个原因。
根据领域模型进行系统实现的具体技术,我们在会后面的课程中介绍。
领域模型和业务需求一致、系统实现和领域模型一致,最终结果就是系统实现和业务需求总是一致的,避免了系统实现和业务需求差距越来越大,这个老大难问题。
领域模型与统一语言
除了模型驱动设计以外,DDD中的另一个核心模式是统一语言(Ubiquitous Language)。
统一语言包含了两个层面的含义:一是业务和技术人员之间的语言是统一的,二是开发团队内部各角色之间的语言是统一的。最终结果就是每一行代码都能对应到统一语言,从而与业务保持一致。你可能已经发现了,统一语言和领域模型的目的是一致的。
统一语言的概念其实很容易理解,难点在于怎么真正在实践中贯彻。
要在实践里真正贯彻“统一语言”的理念,我们可以从统一语言的“物质基础”和“实际应用”这两个方面来考虑。领域模型、和词汇表(glossary)和业务规则表等文档性的制品,就是统一语言的“物质基础”。而业务和技术人员在开发过程中的沟通协作,就是统一语言的应用。
这两方面缺一不可。要用好统一语言,首先要建好领域模型、词汇表和业务规则表。没有这些,就无法对语言进行规范化和持久化。
另一方面,在所有的协作过程中,每当我们说到领域知识的词汇,都要看一下在领域模型中是否有所反映、大家对同一概念的理解是否一致、已经废弃的词汇是否还在使用等等。
如果发现语言与模型不一致,就要及时纠正,让两者恢复一致。编写代码的时候,也要使代码中的各种命名与模型和词汇表保持一致。在前面的课程里,咱们在建模中模拟了你我两人的对话过程,就是希望你能够体会到语言在沟通中的应用。
在领域建模的过程中,我们也强调了,实体、关联等元素翻译成自然语言应该怎么说。事实上,好的模型中的任何元素,都应该可以和自然语言进行顺畅地双向转换。
总结
这节课的主要内容就讲完了。我们来总结一下。
今天我们首先介绍了模型的概念,然后说明了软件开发也是一个建模过程。为了跨越现实世界和机器模型之间的鸿沟,人们采用了“分步走”的方式。其中,在传统软件工程中的分析步骤产生的分析模型,也叫做领域模型。
但是,DDD的领域模型与传统软件工程有一个重要的区别,就是,DDD强调领域模型要兼顾业务和技术两个视角,而不像传统方法那样,只关注业务视角。
所以,我们可以说:DDD的领域模型是为了满足业务需求,对领域知识进行提炼和抽象的产物,反映了业务和技术人员的共同视角。一方面,它能够全面和深刻地反映领域知识,另一方面又能方便地转化为技术实现。
DDD的核心模式之一:模型驱动设计就是围绕领域模型展开的。它有两个要点:领域模型和业务需求要保持一致;系统实现和领域模型也要保持一致。最终的结果就是系统实现和业务需求保持一致。
除此之外,DDD还有另一个核心模式:统一语言。要用好统一语言,一方面要建立好领域模型、词汇表等“物质基础”,另一方面要在沟通协作的过程中,不断保持模型、语言和系统实现的一致性。
这节课理论比较多,可能比较抽象,希望你在实践中不断体会。
思考题
1.在你的实际项目中,有没有遇到过业务和技术理解不一致的情况,造成了什么后果?
2.在你的实际项目中,有没有做过类似领域建模的事情,是否能够坚持下来?
好,今天的课程结束了,有什么问题欢迎在评论区留言,下节课,我们开始过渡到模型的实现,讲一下怎样根据领域模型进行数据库设计。
- Jxin 👍(21) 💬(6)
这章的认知和钟老师有挺大差异,我的观点不一定成熟,列出来,和大家共同探讨。 定调: 分析模型: 观察现实世界,记录现实世界的产物。模型产物: 用例分析/事件流。 设计模型: 对现实世界的认知做进一步提炼(抽象)的产物。模型产物: 领域模型图/ 架构设计/ 详设。 实现模型: 通过编码将设计模型中的概念转换成可运行的 代码/软件。 然后 分析->设计->实现 是一个循环关系(两关联一循环),这个循环会不断地增减和提炼知识。而领域建模指的是这个循环的产物,而不是单指分析阶段。也说明领域建模是一个循环渐进的过程,代码也是领域建模的一种模型产物。 为什么领域模型图是设计模型? 首先为什么不是分析模型? 因为领域模型里面的部分概念其实是做了抽象的,相比分析阶段的观察现实世界已经到了设计阶段的提炼和抽象;其次,以钟老师上章的UML图为例, 领域模型图既有领域模型以及模型间的关联关系,也有注释和规则,后面再追加领域服务与实体的行为,已经很完备,完备到可以用来验收和表达实现模型了(编码实现),这个粒度和能力从循环的顺序看,应该是落在中间的 设计模型。 思考题: 1.业务和技术理解不一致的情况很多,后果,可大可小,大部分偏小。毕竟系统都上了,还留有后果很严重的认知差异,这个还是比较少见的。毕竟我们哪怕不用ddd也不会不做风险设计和防患。毕竟一次资损整个团队一年白干。 2.做过,好几年,坚持下来了。不过在一线大厂时其实比较少用,1.团队不懂这块,自己的影响力也没法影响整个团队变更工作模式,所以权衡利弊,随大众。2.中台的系统,没有立场也没有勇气去做变更。(能了解到的信息很有限,基本只够在那加行代码,根本不敢乱来。为什么信息很有限,项目权限申请就直接劝退了)
2022-12-29 - escray 👍(1) 💬(3)
开玩笑的说,我们的传统就是没有方法。 文中对于模型的定义和解释很精彩,特别是说模型以解决特定问题为目的。之前可能更多的把模型当做了可展示的三维模型,类似于沙盘;而对于计算模型,类似于图纸,考虑的比较少。 软件开发是建模过程,特别是业务系统,其实就是在使用技术手段模拟业务过程。之前参与过信息化系统的开发,试图使用技术来引领业务,比如超前开展无纸化办公,结果…… 曾经看到或者听说过得失败项目,大多数从第一步捕获行为需求就走歪了。 即使是传统软件开发,其实也希望能够站在技术和业务的十字路口。领域驱动开发,其实是给出了一种发现需求到分析设计的方法论,能不能用的好,就千人千面了。 领域模型和系统实现一致,并且能够保持同步进化,这个更难。 对于思考题, 1. 业务和技术理解不一致的地方,通常在于业务希望保持原有操作方式,越简单傻瓜不费脑子越好,技术希望能够分布式、微服务…… 2. 以前的项目主要是面向领导开发,所以谈不上领域建模,当然不排除领导本身是业务专家。
2022-12-22 - 胡昌龙 👍(7) 💬(1)
感谢老师的内容,理得很清晰,很有帮助,请教下: 传统模式下,产品关注自己的业务分析模型,研发关注自己的技术设计模型,各自做好自己边界内的迭代维护工作。领域驱动模式下,领域模型,统一语言等也会不断迭代更新: 1) 如何在产品与研发是两个大部门的情况下,产品与研发一起同时维护更新,有没有相关的工具; 2) 另外,产品体系较大,模型和业务知识比较多的话,如何统一管理,快速构建可讨论画面 3) 每次迭代可能只是一个切面的需求,中间可能横跨多个领域,基于事件风暴及领域思路分析需求,会不会比较重,或者怎么做到轻; 感谢老师!!!
2022-12-20 - bighero 👍(9) 💬(2)
我想谈谈我眼中的传统与现在的区别。 传统的时代是所谓的“两张皮”的时代。一面皮其实更倾向于拿过来用户需求就被开发人员按照ER关系割开来,拆解的七零八落的关系时代,代码只求crud的快活感。另一面皮是销售(当时并没有所谓的专职ba po划分)拿着cmm到处宣传讲解,某公司是多么按照国际标准规范来制作软件。 现在软件制作更倾向于mvp。最小实现小步快跑的方式螺旋迭代,利用小迭代来固化领域价值,不断迭代完善。所以才有了用户故事方式或事件风暴。其实我一直认为 事件风暴是一种特殊的用户故事表现形式。它力求从事件的起因 经过 结果,来反向导入who where when 。其实还是用户故事的一种描述方式而已。
2022-12-21 - 6点无痛早起学习的和尚 👍(8) 💬(1)
这里有个疑惑点,其实很多时候,是不是只需要技术完成业务的功能就行了,比如业务你要什么功能,我技术按照我技术的设计(不按照业务的设计)帮你实现这个功能就行了,但是这个问题可能仅限于本次完成这个功能,导致了外表看起来一样,内在完全不一样。 如果后面业务基于这个功能要做新的扩展,技术的设计可能扩展性就不太好了,所以其实这里就是技术没有按照业务的设计去做,双方并没有达成内在设计去实现,最后就导致了这个冲突。 DDD 其实就可以解决掉这个冲突,不知道我理解的对不对。 因为我的工作中,就出现过,产品做了一个模型设计关系(账户模型),但是研发不按照产品的模型来设计,但是最终的功能出来是可以满足产品的。
2022-12-29 - Michael 👍(6) 💬(1)
还是有几个问题想请教老师,您说的DDD里的建模与普通建模的区别在于DDD里的建模需要兼顾业务和技术两种视角,但是在前面的例子里面似乎只专注于业务视角啊? 还有就是为什么在领域建模的时候要关注关系而不是别的东西呢?这个有没有什么说法之类的?
2022-12-21 - aoe 👍(5) 💬(2)
看完之后豁然开朗,不在担心自己建模太烂,《DDD》序中写道“真正强大的领域模型是随时间演进的,即时是最有经验的建模人员也往往发现他们是在系统的初始版本完成之后才有了最好的想法。” 在前几课一直纠结自己面对“企业管理”这个项目无法做到像老师一样的分析,现在的想法是,找一个自己感兴趣的项目开始练习 DDD 就完了。
2022-12-20 - Geek_c33f40 👍(3) 💬(1)
老师您好, 目前团队的开发流程是产品收集需求, 产品和交互输出交互稿, 我们开发按照交互稿的内容去实现就行了. 团队虽然有在落地DDD, 但领域模型还是只是开发去建模, 没有加上产品. 一方面是因为功能并不复杂, 开发通过交互稿就可以理解这个流程, 例如一个简单的包含发帖和回复的论坛. 另一方面产品对这个功能的理解也不深, 例如不清楚未来的规划, 功能拓展点可能在哪里, 都是走一步看一步, 所谓"敏捷", 加上产品也可能收效甚微. 目前问题在于设计领域模型的时候输入太少不太好做决策, 开发团队也尝试从例如竞品分析去获取更多对领域的理解, 但还是觉得不太够. 一个功能迭代次数太少也无法验证领域模型是否合理. 老师请问有没有什么好的建议? 还是说针对这种没有领域专家, 业务也相对简单的场景按现有的模式也是可以接受的, 领域模型应先按简单的方式做设计.
2023-02-10 - mm马 👍(3) 💬(1)
本章内容与徐皓老师的两关联一循环有异曲同工之处,妙哉
2023-02-04 - leesper 👍(2) 💬(2)
有个问题请教下钟老师:贵公司在完成需求分析、领域建模,进入设计和编码阶段时,是从头开始做,以TDD的方式进行演进式设计,一步一步迭代功能,添加一些必要组件(比如流程引擎)呢,还是在一些现成脚手架基础上直接做开发呢?我猜是前者,对吧?因为我对现在一些常用的脚手架其实是持保留意见的……这些所谓的脚手架拿来搞简单的CRUD可以,拿来实现复杂软件其实是处处掣肘,根本不好用的
2022-12-20 - 赵晏龙 👍(2) 💬(3)
1. 绝大多数你在软件开发中的感觉到的不协调,都是模型的差异,其实也包括技术框架的使用。 2. 习惯先建模再设计以后,就回不去了
2022-12-20 - 6点无痛早起学习的和尚 👍(1) 💬(1)
2 刷,回到这一章节,在 1 刷之后在公司实践中遇到一个问题:领域模型要和业务需求一致(这个太难拉齐了) 在实践中,产品经理给的业务需求在某个功能上/模型上就是一句话的内容,写的很粗,当研发看到这句话进行了自己的一些抽象设计模型,然后 PM 就不认可这个抽象模型和他的业务需求模型不一样,但是研发的抽象模型比PM 的业务需求模型更抽象,扩展性也更强,研发的抽象设计模型也能完成满足 PM 当前业务需求和未来扩展的需求场景。 就因为这个点,研发和 PM 撕逼了不少次,研发吐槽 PM 过度干涉技术设计,PM 吐槽研发不按照需求来。 具体🌰就是这样: 背景:我们是做一个海外电子银行的业务,模型就是三户模型,底层是资金账户概念 PM需求:来一个人,我要给这个人开设一个账户,账户类型就是现金户,对应的就是资金账户类型里的余额账户,也就是 type+人==>余额账户 研发设计:把账户类型设计成一个模型叫产品账户概念,1 个人可以有多类产品账户,1 个产品账户有多个资金账户,抽象原则就是:分离开业务层和资金层,业务层可以多变,资金层永远是不变的。 就因为这个设计,互相撕逼不认可。其实现在来看,研发是把产品诉求里的类型抽象了一个模型,而产品就理解为一个字段。
2023-04-27 - 江凌 👍(0) 💬(1)
模型是一种以解决特定问题为目的,对现实世界或人们思维中的事物提取部分信息忽略其他大部分信息进行模拟,具备多种表现形式的人造物
2024-05-16 - aoe 👍(0) 💬(1)
从「知识管理」的角度来看,DDD 的核心是「知识」 DDD 中的核心模式:统一语言、模型驱动设计 建立领域模型是 DDD 的核心,主要有两个目的: 将知识可视化,准确、深刻地反映领域知识,并且在业务和技术人员之间达成一致; 指导系统的设计和编码,也就是说,领域模型应该能够比较容易地转化成数据库模式和代码实现。 请根据 彼得·德鲁克的《管理》一书,分析一下「知识在 DDD 中的作用」 AI 总结: 领域模型本质上是对领域知识的抽象和表达 知识是决策的基础 知识创造价值 知识的共享与沟通 持续学习与知识的迭代 知识的管理与领导 使知识具体化并可操作 知识在 DDD 实践中的体现:事件风暴、领域建模 知识管理的内容来自 《徐昊 · AI 时代的软件工程》课程 详见 https://wyyl1.com/post/23/09/
2024-04-16 - Geek4329 👍(0) 💬(1)
在对应的捕获行为需求和需求分析阶段,我们这架构师对技术人员的要求是不能用技术视角看业务问题,必须用业务视角和产品、业务同学进行沟通,只有在设计阶段才能考虑技术的问题,但是在我们架构师看来技术问题都是小问题。所以想咨询一下老师,领域驱动设计兼容了业务和技术的视角,这个是官方的还是老师的个人理解?有没有更强有力的佐证?
2023-10-17