作者简介:张刚,软件工程博士,阿里云云效资深技术专家,ALPD方法学核心成员。
引言
领域模型是重要的概念。但是,真正了解并能熟练运用它的人并不多。这实在是殊为可惜的一件事情。
软件开发中的许多问题,例如需求难于沟通,软件难以演化,都和领域模型紧密相关。更关键的是,掌握这个概念并不难。通过练习,一个团队只需要一两个小时,就可以习惯领域模型的建模思路,并且开始从中受益。
那么,什么是领域模型?如何理解领域模型的本质?为什么领域模型能给软件开发带来巨大帮助?如何表达它,如何应用它?本文将依次展开这些概念。
什么是领域模型?
首先我们来看什么是领域模型。
领域模型定义了领域内的关键的概念以及这些概念之间的关系。
为什么要强调“领域内”?是因为模型(或者说概念)只在它所处问题空间中才有意义。这分为两种情况:
1)一个概念只在某个特定领域有意义。例如,“应收账款”,就只是在财务领域,更严格的说是会计领域才有意义。
2)一个概念必须通过领域限定,才有具体的意义。例如,“轨道”这个概念,它可能是天文学领域的行星运动轨道,也可能是铁路领域的火车轨道,必须得先限定领域,这个概念才有真正的价值。
关键信息1:领域模型最重要的是概念,领域模型也被称为概念模型。
虽然有人说“领域模型是领域内的概念的可视化表示”,但是, “可视化”并不本质,虽然它也重要。相比较而言,“概念”才是根本。
关键信息2:“语言的边界就是思想的边界”—— 一个好的领域模型,必然承载了有用的知识。
对一个不熟悉特定领域的人来说,理解概念,往往是进入一个领域最快的方式。例如,小时候的儿歌:太阳大,地球小,地球绕着太阳跑。地球大,月亮小,月亮绕着地球跑。它就可以认为是一种概念模型的表达。在这个模型中,包括了3个概念实体:太阳,地球和月亮。而太阳和地球的关系是地球绕着太阳运动,地球和月亮的关系是月亮绕着地球运动。用一张图画下来就是:
这张图其实是UML的对象图,当然即使你不熟悉UML,就是作为线框图,也能很容易理解。
同样,在各种业务领域,都有自己的关键概念。这些概念的表达也不一定是图。例如,刚才所讲的会计领域,我们可以使用一张表来表达下列的几个关键概念:
会计主体(本方)->对方 |
|
应收账款 |
货物已经发给对方,但是尚未收到货款 |
应付账款 |
已经收到对方货物,但是尚未支付货款 |
预收账款 |
已经收到对方货款,但是尚未发货 |
预付账款 |
已经支付对方货款,但是尚未收到货物 |
通过这样一张表格,相信即使对会计领域不甚了解对小伙伴,也能快速掌握相关的知识。如果我们更进一步,能够理解到,应收和预付,本质上是本方的债权,而预收和应付,本质上是本方的债务。用一张图表示就是:
在这里我们使用了UML类图来表示。对于不熟悉UML的小伙伴,可能需要解释一下三角形箭头的意思,它代表“是一种”,例如,应收账款是一种债权。
更严格的,如果一笔应收账款的帐期已经很长,例如5年,那么这种账款有很大概率已经收不回来了,所以需要计提坏账。有一些通用的坏账计提策略,例如:一年以内5%,一到二年20%,二到三年50%,三年以上100%等。所以,面向刚才的应收账款,我们可以用下面的图来表达这样的概念:
图是一种视图,它不需要面面俱到。例如,本图中,并没有显示一切和会计科目相关的信息,而只是集中于坏账的计提。其中,我们在应付账款和坏账之间引入了一个新的符号,认识UML的小伙伴知道我们表达的是”应收账款中包括坏账“。图中的帐期、金额等,我们成为“属性”,用于详细的说明应收账款、坏账这些概念还包括哪些内容。
由于领域模型本质上传递的是概念,是知识性的信息,所以,对于软件开发的场景来说,把这些知识显式化,能快速对齐不同角色、不同参与方之间的概念,加速沟通,避免误解。
领域模型是重要的业务资产
领域概念沉淀业务知识,而且非常稳定。
一家在某个领域深耕多年的企业,和一个新入行的企业,差别是什么?差距可能是多方面的,但是最大的差距应该是“认知”。——所以我们常常会看到,新入行的企业追赶深耕多年的企业的办法,常常是去成熟的的企业高薪“挖角”。按道理说,挖来的这些人既不能把原公司的客户带来,也不可能把原公司的系统带来,那么本质上他们给新企业带来了什么呢?他们对新公司最大的帮助,是对特定领域的认知。在业务领域,认知非常值钱,而且非常稳定。我们也会看到,一些在某个领域建立了优势的企业,特别是咨询类企业,单靠业务领域的咨询,就能给企业带来客观的收入。如果有良好维护的领域模型,那么领域模型就是这些认知沉淀的最佳位置所在。
更重要的是,尽管业务常新,但是领域模型却相当稳定。我们以商品交易为例。我们知道买家、买家、商品、交易这些概念,都是商品交易领域的核心概念。这些概念并不会随着业务的演进发生剧烈的变化,无论是B2C业务,C2C业务,C2M业务,拼团业务还是秒杀业务。不同的业务,体现的只是对这些业务概念的不同组织方式。当然,真正的领域模型要远远比上述概念复杂的多。我们这里只是举一个简单的例子,说明领域概念的稳定性。
领域模型的跃迁和生长
当然,我们说领域模型稳定,并不是说它一成不变。优秀的领域模型都一定会持续生长,甚至有时候会发生本质的跃迁。
一旦一个模型被推翻,我们会认为,我们对某个领域的认知,一定发生了非常本质的跃迁。例如,前述的儿歌“太阳大,地球小,地球绕着太阳跑。地球大,月亮小,月亮绕着地球跑。”并不是一开始就是这样认知的。无论中外,在几百年前,我们都曾经认为,地球是宇宙的中心,太阳、月亮都是绕着地球运行的。那么,这个模型画出来就是下面这个样子:
地心说对象图
地心说到日心说,是我们宇宙认知到巨大进步,以为日心说模型彻底否定了地心说模型。在软件领域也是这样。我曾经经历过几次领域模型跃迁的场景,每次都伴随这业务认知的巨大进步。
当然,在现实生活中,跃迁并不多见。更多的时候都是在原有的模型上稳定发展,逐步增入各种新的概念和各种细节。模型的生长过程,本质上也是业务能力积累的过程。
稳定的领域模型带来软件的适应性
需求是不稳定性的,而领域模型是稳定的,这启发我们,如果以领域模型为中心去构造软件,那么我们就会构造出很多稳定的积木块。新的需求,就可能通过这些稳定的积木块,通过不同的搭建方式,形成丰富多彩的应用。在这种情况下,我们的软件对于变化的适应力最强,开发成本最低。
领域模型存在于哪里
用类图表示领域模型
UML类图是表达领域模型的非常好的工具,虽然并不存在如何表达领域模型的标准。因为在UML中,“类”并不简单是软件设计中的“类”,它代表的其实是“概念”,所以,把类图用在领域模型的表达上,是非常恰切的。而且,UML已经约定了概念和概念之间的关系,例如:类、属性、关联、关联的多重性、泛化、聚合、组合、依赖等等。
对于不熟悉UML的人来说,使用UML也完全没必要有什么心理负担。UML是一个高度灵活的结构,它具有渐近的能力。你没有必要掌握所有复杂的概念才开始工作,根据我的经验,只要一开始能把类(代表概念)、类的属性和它们的关系描述出来,最多再知道多重性怎么表示,就足以应付大多数的场景。
有些小伙伴有面向对象的经验,在这里会纠结于要不要对“方法/操作”进行建模。在“领域模型”是一种“业务概念”这个上下文中,方法是完全多余的东西,暂时不需要在这个阶段进行建模。我认为在实现阶段补足它们更合适。
在交流和文档中使用领域模型
领域模型写在纸上并不是最关键的。作为概念模型,它反映了这个领域的最重要的概念,也构成了表达业务概念的词汇。所以:
最好的领域模型,应该时刻存在于团队成员的心中,存在于日常的交流活动中。
为了做到这一点,我对自己的团队和辅导过的团队,都有一个要求,这个要求也被成为交流活动中的“统一语言”:
任何在需求描述中出现的概念,都必须出现在领域模型中。如果需求描述中存在概念之间的关系,领域模型中也必须有这个关系
这个要求看似简单,实际做到会比较困难。特别在刚开始的时候,团队成员可能并不适应这种做法,常常就忘记了这个准则,需要经常纠正。但是一旦习惯,大家会发现,在日常交流活动中,因为所有的概念都已经显式化,误解大大减少,共识更容易达成,导致的后果就是最后团队成员,都会非常自觉的维护“统一语言”的做法。
出于同样的原因,编写文档时,使用领域模型作为统一语言也成了一个非常自然的结果。
在代码中使用领域模型
由于领域模型已经被显式化,所以如果能够在代码中使用领域模型,那么代码就会获得更好的易读性。由于领域模型和代码对应的更加一致,那么在领域模型发生演进时,代码就会变得更容易演进。在这方面,领域驱动设计给出了一组完备的模式,可以帮助架构师和开发人员自然地把领域模型转化为代码。本文中我们并不准备展开这些模式。在此,暂时先请读者们记住下面的结论,后面会有更深入的讨论:
代码和问题域之间的表示差距应该尽量缩小,领域模型是连接现实世界和数字世界的最佳桥梁。使用领域模型作为代码中的业务概念的基本表达元素,可以大幅提升代码的易读性,也可以更好的支持业务的演进。
领域模型来自哪里
领域模型反映了关键的业务认知,但是认知并不会凭空建立。能够一上来就洞悉一切本质的,要么是这个人是天才,要么说明这个领域已经是一个非常成熟的领域,已经无需探索和发现。
大多数时候,认知都来自于业务场景的启发。所以,领域模型建立的过程,往往是伴随着需求分析同步产生的。
我画了下面这张图,来说明领域模型和业务场景之间的关系:
也就是说,领域模型是在业务场景的激励下逐渐完善的。而且,反过来因为对领域的认知更加深刻,领域模型还有助于新的业务场景的发现。
探索和发现最好不要一个人独自进行。更多地时候,应该尽量进行集体建模。集体建模不仅仅利于探索和发现,而且它也有助于达成对于关键业务概念的共识。
集体建模的最好工具并不是UML的电子化工具,使用白板,在开放空间中的讨论,往往能够收到最好的效果。
由于领域模型表达的是概念,所以对于概念及时地分解和抽象,是领域建模的基本功。当然,现实中受过严格的分解和抽象训练的人并不多,特别是很多业务人员往往都缺乏这方面的能力。我在实际工作中,观察到具有面向对象经验的开发人员,经过一定时间的练习,可以很快掌握这方面的技能。所以,如果有一些具有经验的开发人员参与建模,往往可以获得质量更高的模型。
常见误区
领域模型的概念产生于90年代的面向对象社区。在那个时候,业务变化还不像今天这样频繁,迭代的思想也还没有完全成熟,业务人员和技术人员也没有像今天这样密集的交流,所以,无论是从参考书上,还是实践上,领域模型的概念都难免留下早年做法的影响。其中,有若干误区,在实践中是应该尽量避免的:
误区1: 从开发视角进行领域模型的建模
常常有技术人员问:“领域模型和ER图有什么关系?” 对这个问题最直接的回答就是:“没有关系”。固然,我肯定知道在有了领域模型之后,设计ER图会更简单,或者对于一个还缺乏领域模型的遗留系统,研究数据库结构可以带来有效的输入,但是它们的立足点是完全不一样的。
领域模型一定要从业务视角去看,因为领域模型反映的是业务认知。一旦在领域模型中掺杂了技术的概念,不仅仅是因为它不够纯粹,更重要的是它已经堵死了从业务视角对领域模型进行演进和纠正的机会。因为没有软件背景的业务人员,是不可能去看一个充斥着技术概念的模型的。统一语言无法建立,领域模型带来的价值就已经损失了一大部分。此外,从开发视角进行建模,往往还会忽视业务人员的参与。而实践一再表明,资深的业务人员在领域建模时,往往能提出深入的洞察。所以,从开发视角对领域模型进行建模绝对不可取。
误区2: 建立庞大的领域模型
当我们说“领域”的时候,并没有限定一个“领域”应该有多大。究竟是“航空”作为一个领域,还是“航空”中的“订票”是一个领域?
当你考虑到“领域的核心是认知”,这个答案就变得非常清楚了。领域越大,越不利于建立认知和共识。我们应该这问题域,把大的领域划分为小的领域,然后逐个建立这些小的领域的领域模型。那种整整一面墙的领域模型,往往都是不可取的。
误区3: 重文档,轻交流和共识
领域模型的核心在于建立共同的共识,所以,如果只是把领域模型作为一种“制品”,作为某个阶段的“输出”,这是非常不合适的。领域模型需要作为交流工具。“统一语言”是避免该误区的重要方法。
误区4: 不把领域模型显式化
很多人认为自己是有“认知”的,甚至是有“领域模型”的,但是,如果你问他们模型在哪里,这些要么就是在某个项目曾经有过一些讨论,但是现在已经不知所踪,要么就是虽然文档还在,但是团队的概念表达依旧混乱。没有显式化,没有把领域模型写下来,没有形成团队口口相传的知识,那么这种模型,并不真正存在。除了“统一语言”,我们还有一个非常简便的检验方法,就是看这个团队如何给新人介绍自己的系统。因为领域模型反映了基本的业务概念,是一个非常好的新人培养工具,但凡真正有“领域模型”的组织,是不可能不把领域模型拿出来做介绍的。
总结
本文我们主要介绍了领域模型的基本概念及重要度,领域模型对于“统一语言”的价值以及领域模型应用的常见误区。
总结一下要点:
- 领域模型的本质是概念和认知,它定义了领域内的关键概念以及这些概念之间的关系
- 相对于业务的多变,领域模型相对稳定,优质的领域模型可以低成本的支持业务,领域模型也是统一语言的基础,能有效提升沟通效率
- 领域模型来自于业务滋养,领域模型生长的过程,也是业务认知建立的过程,协作建模是更有效的建模方法
原文链接
本文为阿里云原创内容,未经允许不得转载。