各位好,这是我对DDD理解的第二篇文章,在这里分享给大家
在这一章当中,我们会使用一些方式,把前面一章得到的子域进行分析,然后得到领域模型、聚合并最终指导我们划分限界上下文,形成上下文映射图。这一章过后,我们才会具体的来分析,到底该怎么来写代码,请耐心看下去哈
可能会有同学说,我们部门在架构,在拆分的时候,也定义了一些模块出来。如果让我来做电商项目,我也能把支付、商品、物流等模块拆分出来,只是我不叫子域,我们可能叫模块,叫组件。那么为什么我要使用子域这个叫法呢?
我想先回答这个问题,其实思维逻辑是相通的,没必要纠结这一个叫法的不同。但是如果现在我们换了一个部门工作,其他的同事会采用子域、支撑子域这种概念,那么我们如果不采用这种叫法,就会出现鸡同鸭讲的情况,这不利于我们部门之间的沟通。现在好了,我们有同一套语言描述,可以帮助我们之间相互交流,这个统一的叫法,在DDD里面就叫做通用语言。
当然了,通用语言不是单纯的指DDD当中的名词,而是指,我们在分析一个子域的时候,我们团队应该使用一种语言,提升交流的效率。比如,就商品子域而言,商家上架新商品的时候,我们可以叫商品上新,还可以叫商品上架,甚至可以叫商品更新,那么我们负责商品子域的团队,就应该确认,这个上架新产品的行为,到底叫什么。最后可以通过商讨,就叫商品上新,以后凡是这个业务概念,都叫商品上新。
接下来,我再给大家介绍一个概念:事件风暴,它将会指导我们细化一个子域,将帮助我们把子域掰开了,揉碎了,看看里面到底包含什么。
我们以商品子域为例,现在我们邀请我们负责这个子域的同事们,包含产品人员、架构人员、测试人员、开发人员来一起开会。会前,我们会提前准备一些材料和工作,比如便签,比如在线共享文档,专门用来记录我们会议产生的信息。然后我们用通用语言按照谁谁谁,使用了什么命令,导致什么聚合的什么事件被触发,并对当前这个子域当中产生了什么影响的语言范式,来一个一个的分析子域当中的事件,这就是事件风暴。我们下面直接对商品子域开始分析:
- 用户通过执行商品查看的命令,导致商品查询事件被触发
- 用户通过执行商品收藏的命令,导致商品收藏事件被触发,并将该收藏数据打包成一个用户行为数据包,发送给数据分析服务
- 用户通过执行下单的命令,导致订单的下单事件被触发,并对告知支付服务响应支付请求、库存服务响应库存的扣减
- ...
虽然我这里只分析了三点,但是真正在执行的时候,我们的与会人员会一直在会议室以内,通过事件风暴的方式,一直讨论,将所有的事件全部拆分清楚。
接下来就是重点了,我们已经拿到了事件的集合。现在我们需要从集合当中,把聚合给抽象出来,聚合到底是啥,这个概念我要想在这里说清楚,会涉及到实体、值对象的概念。这会很复杂,所以在这里我暂时不详细说明,我只给出这里的答案。就是事件被触发的实体,就是我们认为的聚合。比如这里的商品,它的查询事件,收藏事件等等被触发了,所以它就是一个聚合。
好,按照上面的逻辑,我们可以分析出来两个聚合:
- 商品聚合
- 订单聚合
现在又是重点了,当聚合划分出来了之后,我们可以按照聚合的离散程度,按照高内聚、低耦合的思路,划分出限界上下文(这里说细一点,有可能有些聚合他们之间的关系不是那么离散,或者说关系比较近,比如商品和商品类别。那么这种情况,那些关系比较近的聚合就都可以放置在同一个限界上下文里面)。显然,我们可以通过上面的两个聚合拆分出两个限界上下文:商品限界上下文、订单限界上下文。那么什么是限界上下文呢?
-
限界上下文是一个明显的业务边界,在这个边界里面,我们所用到的所有通用语言会具有独立的,意义唯一的含义。比如说,用户是一个通用语言,那么用户在订单限界上下文当中,就专门指那些支付的人;如果放在商品限界上下文中,用户就专门代指那些对商品聚合产生事件的那些人。相反的,在物流和库存当中,用户这个概念是不统一的,因为用户可能是发送物流的人,也可能是库存的保管员。所以,物流和库存是不能划分成为一个限界上下文的
-
限界上下文是一个特定问题空间的一个解空间。还记得我们第一章说到的,我们从问题空间出发,找到我们的子域吗?有问题空间,又有对应的解空间,只是说,我们这里的解空间比较小,因为我们的问题空间很大,我们不可能用一个限界上下文就解决了整个电商项目的需求。那么在这里,我们的商品限界上下文,就是商品问题空间的解
-
一般来说,一个特定的子域,就是一个限界上下文。在我们这里,商品限界上下文原本就是从商品子域当中划分出来的。如果我们在真正实施的时候,发现我们的限界上下文和子域是完美的一对一,那么说明我们的建模是良好的。当然了,有朋友可能会说,我存在不是一一对应怎么办呢?别担心,我们回到我们上面的例子来说:在商品子域当中,用户可以下单支付,现在,支付肯定不是商品限界上下文当中的内容,我们只需要把支付划分出去就可以了,这也是很多书籍上对限界上下文和子域描述:往往两者不是一对一的关系,可能相互包含,我们需要细细梳理,再划分出来。
-
一个限界上下文,就是一个微服务。终于,我们DDD到底该怎么指导我们划分微服务,这个问题的答案由我们得出来了。也许有朋友说,我这不是微服务架构,是不是就不能用DDD了呢?显然不是的,限界上下文还可以是一个工程项目,或者是一个模块,甚至是一个核心算法,这些都是可以的
中期总结:按照上面的思路,我们通过事件风暴将商品子域细细拆分、然后得到事件集合,最后细化出聚合,然后根据聚合的离散层度,划分出限界上下文。那么根据上一章的输出,我们将七个子域全部划分成七个限界上下文,如图:
限界上下文映射图
其实上面的图,就是限界上下文映射图了,那么这个图有什么用呢?
作为一个限界上下文或者说微服务的开发者,这个图可以事先帮助我们分析出:我们负责的微服务到底会与哪些其他微服务产生联系。比如,我现在是商品上下文的开发者,我发现我现在会与下面的所有的上下文产生关系,如果某些上下文有隐藏的问题,这将帮助我们提前分析出我自己的微服务有哪些隐患。而具体的上下文之间,该怎么来交互,我将把这些知识放置在后面几章。
总结:本章,我们主要阐述了,拿到具体的子域之后,我们该通过什么方式去分析子域里面的东西,然后得出我们的聚合,以及构建一个限界上下文。至此,我们战略层面的建模就已经完毕了,接下来就是我们该怎么实现这些模型了,这就是我们下一章的内容。