Skip to content

领域和子域:有效分解问题域

在DDD知识体系里有很多概念,比如领域、子域、核心子域、通用子域、支撑子域、限界上下文、聚合、聚合根、实体、值对象、领域服务和应用服务等,它们在DDD理论和知识体系里都是非常重要的概念。虽然有些名词和概念可能在微服务设计和开发过程中并不一定都用得上,但它可以帮你理解DDD的核心设计思想和理念。而这些设计思想和理念,在IT战略设计、中台领域建模和微服务设计中都是很有价值的。

领域的基本概念

我们先看一下汉语词典中对领域(Domain)的解释:“领域是从事一种专门活动或事业的范围、部类或部门。”

我们再来看一下百度百科对领域的解释:“领域具体指一种特定的范围或区域。”

这两个解释都有一个共同的词:“范围”。

对了!领域就是用来确定范围的,范围即边界。这也是为什么DDD在设计过程中不断强调边界的原因。

在研究和解决业务问题时,DDD会按照一定的规则对业务领域进行细分,当领域细分到一定的程度后,DDD会将问题范围限定在特定的边界内,在这个边界内建立领域模型,进而用代码实现该领域模型,解决相应的业务问题。

简言之,DDD的领域就是这个边界内要解决的业务问题域。

既然领域是用来限定业务边界和范围的,那么就会有大小之分,领域越大,业务边界的范围就越大,反之则相反。领域可以进一步划分为子领域。我们把划分出来的多个子领域称为子域,每个子域对应一个更小的问题域或更小的业务范围。

领域的分解过程

我们知道,DDD是一种处理高度复杂领域的设计思想,它采用分而治之的策略,从而降低业务领域和技术实现的复杂度。那么面对错综复杂的业务领域,DDD是如何使业务领域从复杂变得更简单,更容易让人理解,技术更容易实现呢?

其实很好理解,DDD的研究方法与自然科学的研究方法类似,那就是分治策略。当人们在自然科学研究中遇到复杂问题时,通常的做法就是将问题一步一步细分,再针对细分出来的问题域,逐个深入研究,探索和建立所有子域的知识体系。当所有问题子域完成研究时,我们就建立了全部领域的完整知识体系了。

下面用图所示的这个例子来讲解如何给桃树建立一个完整的生物学知识体系。其实初中的生物课早就已经告诉我们研究方法了,它的研究过程是这样的。

第一步,确定研究对象,即研究领域,在这里我们的研究领域是一棵桃树。

第二步,对研究对象进行细分,将桃树细分为器官,器官又细分为营养器官和生殖器官两种。其中营养器官包括根、茎和叶,生殖器官包括花、果实和种子。桃树的知识体系就是我们已经确定要研究的问题域,对应DDD的领域。根、茎、叶、花、果实和种子等器官则是细分后的问题子域。从桃树到器官的划分过程就是DDD将领域细分为多个子域的过程。

第三步,对器官进行细分,将器官细分为组织。比如,叶子这个器官可细分为保护组织、营养组织和输导组织等。从器官到组织的划分过程就是DDD再次将子域进一步细分为多个子域的过程。

第四步,对组织进行细分,将组织细分为细胞。细分到这一级,细胞就成为我们研究的最小单元。细胞之间的细胞壁确定了最小单元的边界,也就确定了研究的最小边界。

我们知道细胞核、线粒体、细胞膜等物质共同构成细胞,这些物质共同协作让细胞具有这类细胞特定的生物功能。在这里你可以把细胞理解为DDD领域模型中的聚合,细胞内的这些物质就可以理解为聚合里面的聚合根、实体和值对象等领域对象。在聚合内这些领域对象共同协作,完成这个特定边界内的生物功能。这个过程类似DDD战术设计时确定微服务内聚合边界和功能要素的过程

在这里总结一下,每一个细分的领域都会有一个知识体系,也就是DDD的领域模型。当所有子域研究完成,并分别建立了子域的知识体系后,我们就建立了整个领域的知识体系,也就完成了整个业务领域的领域模型的建设。

上面我们用自然科学研究的方法,说明了领域可以通过细分为子域的方法来降低领域研究的复杂度。现在我们把这个话题再切回到业务领域,对比验证下二者的细分过程是否是一致的。这里以保险行业为例。

保险是个比较大的领域,很早以前的保险核心系统将所有功能都放在一个系统里来实现,这个系统就是我们常说的单体系统。后来单体系统开始无法适应保险业务增长的发展要求,因此很多大型保险企业开始尝试中台数字化转型,通过引入分布式微服务架构来替换原来的集中式单体系统。

既然采用分布式微服务架构,那首先要做的就是划分业务领域边界,建立领域模型,然后实现微服务落地。为完成保险领域建模和微服务建设,我们可以根据业务内聚和关联度以及流程边界将保险领域细分为:承保、收付、再保以及理赔等子域,而承保子域还可以继续细分为投保、保全(寿险)、批改(财险)等子子域。

在投保限界上下文边界内你可以建立投保领域模型,投保领域模型最后映射到系统就是投保微服务。这就是一个保险领域边界的大致细分和微服务的设计过程。

当然你可能会说,我不是保险行业的人,要怎么理解这个过程呢?

我认为,不同行业的业务模型可能会不一样,但领域建模和微服务设计的过程和方法是基本类似的,其核心思想就是将复杂的业务问题域逐级分解,大事化小,将复杂问题简单化,从而降低业务理解和系统实现的复杂度。

子域的分类和属性

在领域不断划分的过程中,领域会被细分为不同的子域,你可以根据子域自身的重要性和功能属性将它们划分为三类子域,分别是:核心子域、通用子域和支撑子域。当然,这些子域的重要性是放在整个企业内来衡量的。

在企业内决定产品或企业核心竞争力的功能子域是核心子域,它是让企业业务和商业模式成功的关键核心能力,是企业在面对竞争对手时所拥有的核心竞争力。那些没有太多个性化的诉求,同时又会被多个子域重复使用的通用功能子域是通用子域。另外,还有一种功能子域是企业必需的,但它既不是决定产品或企业核心竞争力的功能,也不是被其他子域复用的通用功能,这类子域是支撑子域。

那为什么要划分核心子域、通用子域和支撑子域?其主要目的是什么呢?

我们还是拿上面桃树的例子来说吧。在建立桃树知识体系的过程中,我们将桃树细分为根、茎、叶、花、果实和种子等六个子域。

那桃树的这些子域里是否有核心子域?如果有的话,到底哪个是核心子域呢?

不同的人由于立场和出发点不一样,对桃树子域的理解和重视程度也会不同。如果这棵桃树生长在公园里,那么在园丁的眼里,他喜欢的是“人面桃花相映红”的阳春三月,这时桃花就是桃树的核心子域。但如果这棵桃树是生长在果园里,那么对果农来说,他则是希望在丰收的季节收获硕果累累的桃子,这时果实就会变成桃树的核心子域。

不同诉求的人在不同的场景下,对桃树核心子域的定义是截然不同的,因此对桃树的处理方式也会大不一样。园丁会关注桃树花期的营养,而果农则更关注桃树落果期的营养,有时为了保证果实(可以理解为核心子域)的营养供给,甚至还会裁剪掉疯长的茎和叶(可以理解为通用子域或支撑子域)。

同样的道理,企业在IT系统建设过程中,由于企业资金预算和各种资源的限制,对不同类型的子域应该有不同的关注度,制定不同的资源投入策略,让“好钢”用在“刀刃”上。

从表面上看,很多同行业的企业在业务模式上似乎差异不大。但细细对比和分析,你就会发现它们的战略方向和商业模式还是存在很大差异的。战略方向不一样,企业的关注点就会不一样,因此在划分核心子域、通用子域和支撑子域时,其结果也会出现非常大的差异。

同样都是电商平台的淘宝、天猫、京东和苏宁易购,虽然它们都在做电商业务,但它们的商业模式和战略重点却存在很大差异。淘宝是C2C业务,个人卖家对个人买家,而天猫、京东和苏宁易购则主要是B2C业务,企业卖家对个人买家。即便是苏宁易购和京东都是B2C商业模式,但它们之间也是存在差异的,苏宁易购是典型的传统线下卖场转型成为电商,而京东则是直营加部分开放合作平台的商业模式。

战略方向和商业模式的不同最终会导致核心子域划分结果的不同。有的企业核心子域可能是在客户服务领域,有的可能在产品质量保证领域,有的则在物流领域。有的主要服务于企业,有的则主要服务于客户。所以虽然行业相同,但企业战略目标和定位不一样,核心子域也就会不一样。

在企业业务领域不断细分、构建领域模型和完成微服务建设时,我们需要结合企业战略方向和商业模式来确定建设重点。首先找到核心子域,并将重点资源和资金投入核心子域建设上。

如果你的企业刚好有意向转型微服务架构的话,建议你和你的技术团队将核心子域的建设排在首位,对核心子域的建设,最好要有绝对的掌控能力和自主研发能力。如果资源实在有限的话,在支撑子域或者通用子域建设时,暂时采用外购方式也未尝不可。

小结

DDD领域划分的核心思想就是将问题域逐级细分,采用分而治之的策略,将复杂问题简单化,从而降低业务理解和系统实现的复杂度。

业务领域的子域划分其实是一种比较粗的领域边界的划分阶段,它不考虑子域内的领域对象以及对象之间的关系和层次结构。子域的划分往往可以按照业务流程或者功能模块的边界进行粗分,其目的就是为了逐步缩小业务边界,让你能够在一个相对较小的空间内,比较舒适地用事件风暴来梳理业务场景,构建领域模型。

在很多业务场景中,很多子域的边界天然就是流程节点的边界,比如商品、订单、货物,它们分别属于不同的流程环节,基于这些流程环节很自然地就形成了不同子域的边界。

划分核心子域、支撑子域和通用子域的主要目的是:通过领域划分,区分不同子域在企业内的不同功能属性和重要性,使企业可对不同子域采取不同的资源投入和建设策略。

在子域的划分过程中,有些人可能会对于如何区分核心子域、支撑子域和通用子域有一些疑惑,其实你大可不必那么纠结。

我们主要基于企业关注点的不同来划分这三个子域,以便将企业核心资源投入关键的核心子域。有些子域既属于通用子域,也属于核心子域,将它放在通用子域主要是考虑了它的可复用能力,但是它在企业内却是非常核心的通用功能,在业务环节中处于核心位置。因此这类通用子域在应用建设过程中,也需要按照核心子域的标准投入关键资源。

而从关注度和资源投入来看,支撑子域和通用子域基本上是同一个层级的,区分度并不大。我们其实也没必要纠结它到底属于通用子域还是支撑子域。而且,有些子域随着时间的变化,在这三个域之间出现转换也是有可能的。所以,我们在子域分类时,重点关注核心子域就可以了。

Released under the MIT License.