IDDD 实现领域驱动设计-理解领域和子域

时间:2022-02-25 22:27:03

上一篇:《IDDD 实现领域驱动设计-一个简单业务用例的回顾和理解

在《实现领域驱动设计》第二章的前半部分内容中,提到领域和子域的概念,并且作者把这两者又进行了细致的区分,其实在《领域驱动设计》书中,也有进行详细说明,只不过是在第十五章《精炼》中,章节比较靠后,我先是读了《实现领域驱动设计》这部分的内容,但读完之后,完全没有任何的感觉,或者说我自己和作者没有产生一些共鸣,也记不起来自己到底读了什么内容,但是在读《领域驱动设计》对应这部分内容的时候,我觉得有些内容是我想要的,也产生了一些共鸣,这让我对之前短消息项目也有了一些新的思考,我觉得还是蛮有价值的,下面是自己的一些理解。


IDDD 实现领域驱动设计-理解领域和子域

一张很重要的图,引自:《实现领域驱动设计》

Domain 领域

首先,领域(Domain)不是领域模型(Domain Model),不要把他们两个画等号,从字面上进行理解,“领”的意思,可以理解为领土、领地或属于的某一区域,但不管它包含的是什么,它总是有一个界限,也就是说这个界限要进行明确,如果不进行明确,就会产生一些麻烦,比如“领地纠纷”等等,这个界限其实就可以看作是“领”的意思,“域”的意思,就是一个方面的具体称谓,加上“领”,领域的意思,其实就是明确某一方面的称谓。可能有点晕,我们开发某一套业务系统,比如快递行业的业务系统,那么这个快递业务系统之内的所有业务都包含在领域中,这个领域称之为快递业务领域,其中可能有很多的子领域,或者是业务模块,但都属于这个领域之内,如果超出这个领域之外,那么业务模块将不包含在快递业务领域之内了。在上一篇中有说到领域专家,其实,就是对某一领域精通的人,关键词是某一领域,而不是所有领域,强调的是界限的重要性。

从上面图中可以看出,业务领域中所有东西构成了这个业务的领域概念,也就是说它是唯一的,你开发什么业务系统,首先需要明确的是,你业务系统的领域是什么?如果连这个都确定不了,那么领域驱动设计也就没有再进行下去的必要了。让我自己来考验自己一下,之前开发的消息项目(MessageManager),这个消息项目的领域是什么?我想你应该会和我一样,脑海中首先想到的应该就是消息领域(Message Domain),其实我觉得这个答案没什么问题,消息项目不围绕消息领域开展,那围绕什么开展呢,你可能会有一些疑问,比如消息项目中会有一些用户模块,用户模块不应该属于用户领域吗?如果消息项目只有一个消息领域,那它们俩不相违背吗?其实这个答案,可以从上面的图中找到,消息领域是一个大的概念,它包含了这个消息项目中所有的业务领域概念,消息项目中的用户模块,只不过是消息领域的内部的一部分而已,不要被消息领域中的“消息”字眼所迷惑。

对于开发者来说,理解领域的概念是有一些歧异的,比如消息领域,我们开发者该怎么去描述它,或者表达它呢?我想你应该和我一样,首先,新建一个 Message.Domain 类库项目,然后把所有的业务操作都在这个类库中进行实现,实现完成之后,你告诉领域专家,说这个 Message.Domain 项目就是消息领域,仔细一想,好像也确实有些道理,对于开发者来说,消息领域的表达就是项目代码的实现,这样做也无可厚非。但是,有一点非常重要,在消息领域确定的过程中,不是只有开发人员的参与,最重要的还要有领域专家的参与和讨论,其实,对消息领域的最理解的人,不是开发者自己,而是领域专家,消息领域的表达也不只是代码表现这么简单,而是之前提到的通用语言,消息领域在开发者和领域专家之间的传递和确定,这个介质其实就是通用语言,之前有说到通用语言是开发者和领域专家共同创建的,它的表现形式可以是一个白板,也可以是一堆文件,又或者是一个项目代码等等,但不论是什么东西,它能在开发者和领域专家正确传递领域所包含的业务概念即可。

在上面图中,领域中有一个核心域(Core Domain)的概念,核心域是什么?它是领域中最重要的一块,你可以把它看作是人体中的心脏,也就是说是最核心的东西,开发者和领域专家花费最多的精力都是在它上面,一个业务系统一般有且只有一个核心域,但是一般核心域的精炼工作是需要花费很多的时间和精力,而且也很容易出错,如果业务系统中核心域的精炼出现了问题,那么这个业务系统注定是失败的,因为当一个核心域确定下来之后,开发者和领域专家剩余的工作,都是围绕着核心域进行展开的,比如一个人得了心脏病,而医生在诊断的时候,却认为是肝脏出了问题,然后他就对这个病人的肝脏做了手术,可想而知后果会怎样。。。这个看似简单的问题,但其实中间也蕴含了一些重要东西,首先,我们可以把它抽离出来,有三个人物:病人、诊断医生和手术医生,再想一下,我们业务系统开发,也有三个重要对象:业务系统、领域专家和开发者,然后,你再对它们进行对比下,就可以得出一些东西了,诊断医生是最了解病人的,由他来确定病人得了什么病,就好比领域专家把业务系统的核心域精炼出来,手术医生只不是实施者,用的是手术刀,而开发者用的是代码,但和看病不一样的是,核心域的精炼是领域专家和开发者共同探讨决定的,这就避免了诊断医生和手术医生所产生一些不必要的“冲突”,说了这么多,总而言之,核心域的精炼很重要,需要领域专家和开发者共同参与。

回到我们的消息领域上,那在消息领域中,核心域是什么呢?我的个人想法是发消息业务操作,这是消息领域中最重要的一个业务操作,消息的存在就是为了传递信息,在现实生活中,对于消息相类似的就是寄信,对于写信的我来说,我其实就是寄信的领域专家,为什么?因为我自己就是用户,对于寄信用户来说,我写信的目的就是让收件人可以收到我的信,具体这封信是怎么寄出去的,公路、铁路、飞机等等,这些我都不关心,我只关心的是现在这封信有没有到收件人手里。按照这个思路进行理解,对于消息领域来说,领域专家所能描述出来的核心域描述就是:发消息,这个和之前我们提到的待定项提交到冲刺一样,最简单的业务描述就是这样,至于消息发送限制、或者发送之后要不要邮件通知,这都是发消息具体的内部实现,对于消息领域以后的业务变化来说,变的也只是核心域的内部而已,我们只需要改变具体的实现就可以了,有点以不变应万变的意思,不变的是核心域,变的是核心域的内部实现。

描述这么多,可能有点晕,只需要记住两个概念就可以了,领域和核心域,具体的深入理解,只有运用后才可以真正体会到。

SubDomain 子域

什么是子域(SubDomain)呢?理解子域的概念,必须和核心域对应起来,子域也是领域的一部分,只不过它的重要性没有核心域那么大,它们之间的关系,你可以看作是人体器官中,心脏和其他器官的关系,在《领域驱动设计》中,其实并没有子域的概念,而是通用子域(Common Subdomain),而在《实现领域驱动设计》中,作者把子域拆分成了支撑子域(Generic Subdomain)和通用子域(Common Subdomain)。对于领域来说,除了核心域,用来支撑核心域的子域,就可以称之为支撑子域,在整个领域中,可以被公用的子域,称之为通用子域,通用子域还有一个理解是,在某一个业务领域中,它可能是被看作是通用领域,但是在另外一个业务领域中,它可能就被看作是核心域了,举个例子,比如在团购业务系统中,地图服务可能就被看作是通用领域,而对于地图服务商来说,毫无疑问,地图服务将是他们的核心域。

这些概念性的东西可能理解起来很费劲,我们再回到消息领域中,在上面分析中,我们已经确定了“发消息”是核心域,插一句,有人说,那回复消息是什么啊?难道有两个核心域?其实发消息就包含回复消息,因为回复消息也是发消息的一种信息,回到正题上,我们在消息领域中精炼一下支撑子域和通用子域,我现在可以想到的就是消息验证服务领域,就是在发消息之前对发件人、收件人、以及对消息内容进行验证,就好比你去邮局寄一封信,工作人员需要验证一下收发件地址一样,消息验证服务领域用来支撑发消息核心域,所以可以把它单独精炼出来进行探讨,还有就是,对于支撑子域来说,在整个领域中,可能会有多个,但大部分都是围绕核心域进行展开的,这也就是“支撑”的具体含义吧,说到这,我现在脑子里面有闪现一个,那就是消息发送之后的通知服务,这个也可以看作是支撑子域,需要记住的是,支撑子域虽然没有核心域那么重要,但它也是领域的一种,也是非常重要的,不要完全忽略它。

说了支撑子域,再来分析一下,消息领域中的通用子域,其实就是用户领域,用户的概念会贯穿整个消息领域,因为一切都是用户进行操作完成相关业务,用户领域的概念其实和上面说到的地图服务领域是一样的,在用户业务系统中,用户领域就不是通用子域了,而是核心域,对于非用户业务系统来说,用户领域在其他业务系统中,都可以被看作是通用子域。可能还有一点内容容易造成误解,就是消息领域中,“用户”的概念是很重要的,发消息是用户进行发送,那用户领域是不是应该被看作是核心域呢?我记得当时在开发消息项目的时候,曾经就把发消息业务操作放在了用户模型中,认为用户才能发消息啊,那如果是这样的理解思路,所有的业务系统中的业务操作,都应该是放在用户模型中,因为只有用户才能进行这些操作,但好像并不是这么回事,我们有点过于“面向对象”了,应用软件中和现实生活中的用户概念是不太一样的。

在业务领域中,对于通用子域来说,是比较容易精炼的,但是对于支撑子域来说,精炼它是有些难度的,难点就在于它和核心域的区分,有时候,我们可能会从核心域中剥离支撑子域,当然,最重要的,还是领域专家和开发者之间如何确立通用语言并与之沟通。


啰里八嗦的,就记录到这!