按照我一向的惯例,在上手实操之前,前期总会做复杂的评估,大致是这个流程:价值—概念—实践。价值自不必说,已经体现在上一篇里,在复杂软件项目开发中三层架构VSDDD的时候简直就是完败,所以对于逻辑复杂的系统,最好采用领域驱动开发的方式。这个体现了学习这个系列的价值。那么接下来就是概念,也可以理解为理论,首先得知道是什么,在理论学习里我又比较喜欢先整体把握,再局部填充的方式,所以本篇就从整体概念里来概览一下。

参与人员

DDD的主要参与者:领域专家+开发人员

领域专家

领域专家:精通业务的任何人,如果开发关于银行的软件,那么银行从业人员就是领域专家,如果开发关于股票的软件,炒股大牛就是领域专家。。对于现阶段我们来说,相当于一个业务熟练的实施人员,他知道关于实施的一切工作,并且具备权威性

开发者

开发人员:<stron>。也就是和代码软件设计代码相关的所有人员,将构建落到实地去。</stron>

通用语言

如何沟通,开发人员完全不了解一些领域,例如我之前在实验室做过一个地震相关的项目,对于断裂带,震源等完全没有概念,非常非常难受。而领域专家也完全看不懂代码写的是什么,甚至最简单的输出,那么如何让团队协作,那么就需要一套大家都能理解的语言,也就是通用语言通用语言和限界上下文的关系是一对一的!

领域and子域

领域

引自https://www.cnblogs.com/xishuai/p/iddd-domain-and-subdomain.html

定义

我们开发某一套股票业务系统,那么这个股票业务系统之内的所有业务都包含在领域中,这个领域称之为股票业务领域,其中可能有很多的子领域,或者是业务模块,但都属于这个领域之内,如果超出这个领域之外,那么业务模块将不包含在快递业务领域之内了。领域专家,其实,就是对某一领域精通的人,关键词是某一领域,而不是所有领域,强调的是界限的重要性。

核心域

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

案例

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

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

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

子域

什么是子域(SubDomain)呢?理解子域的概念,必须和核心域对应起来,子域也是领域的一部分,只不过它的重要性没有核心域那么大,它们之间的关系,你可以看作是人体器官中,心脏和其他器官的关系,在《领域驱动设计》中,其实并没有子域的概念,而是通用子域(Common Subdomain),而在《实现领域驱动设计》中,作者把子域拆分成了支撑子域(Generic Subdomain)通用子域(Common Subdomain)

支撑子域

对于领域来说,除了核心域,用来支撑核心域的子域,就可以称之为支撑子域,我们在消息领域中精炼一下支撑子域,我现在可以想到的就是消息验证服务领域,就是在发消息之前对发件人、收件人、以及对消息内容进行验证,就好比你去邮局寄一封信,工作人员需要验证一下收发件地址一样,消息验证服务领域用来支撑发消息核心域,所以可以把它单独精炼出来进行探讨,还有就是,对于支撑子域来说,在整个领域中,可能会有多个,但大部分都是围绕核心域进行展开的,这也就是“支撑”的具体含义吧,说到这,我现在脑子里面有闪现一个,那就是消息发送之后的通知服务,这个也可以看作是支撑子域,需要记住的是,支撑子域虽然没有核心域那么重要,但它也是领域的一种,也是非常重要的,不要完全忽略它。

通用子域

在整个领域中,可以被公用的子域,称之为通用子域,通用子域还有一个理解是,在某一个业务领域中,它可能是被看作是通用领域,但是在另外一个业务领域中,它可能就被看作是核心域了,举个例子,比如在团购业务系统中,地图服务可能就被看作是通用领域,而对于地图服务商来说,毫无疑问,地图服务将是他们的核心域。

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

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

TML分隔符

问题空间和解决方案

在问题空间中,我们思考的是业务所面临的问题和挑战,而在解决方案空间中,我们思考的是如何实现软件以解决这些业务挑战。注意:我们希望将子域一对一的对应到限界上下文

问题空间

问题空间:核心域+其他子域的组合,注意其中并不包含限定上下文的划分,领域专家和开发人员在探讨领域的设计中,首先,就是对问题空间的探讨,用来确定核心域和其他子域,并列出业务系统中可能会存在的一些问题。

解决方案空间

解决方案空间:一个或多个限界上下文的集合,也就是一组特定的软件模型

项目开发流程

我个人总结了一下一个复杂项目是如何通过DDD来开发的,我认为主要有以下几步吧

1,get一个领域专家

在项目开发初期,一定要搞一个领域专家进来,好处有以下两条:

  • 既然是专家,一定在该领域多年,对业务非常熟悉,可以用最简单的方式让开发人员迅速明白需求
  • 既然是专家,那么是权威的,如果该项目连专家都满意了,谁还敢说不好。

2,进行战略建模


- 开发人员和专家第一时间当然是确立我们的问题空间是什么,提出领域,划分子域,哪些是核心子域,支撑子域,通用子域。
- 然后再创建上下文以及和其一对一的大家都明白的通用语言
- 最后创建上下文映射图(Context Mapping)

3,战术建模

有了战略建模的支持,我们的大体框架就出来了,接下来就是进行战术建模,主要包括以下的内容:

聚合-Aggregate
实体-Entity
值对象-Value Objects
资源库-Repository
领域服务-Domain Services
领域实践-Domain Events
模块-Modules

以上这些部分内容会随着学习的深入补全,对应于上图的战略建模,下边这些部分就是战术建模了:

  • 协作上下文的战术建模:

  • 身份与访问上下文的战术建模:

  • 敏捷项目管理上下文的战术建模: