搜索 | 会员  
基于DDD的商城系统实战(二)--如何使用事件风暴进行领域建模
来源: CIO之家的朋友们   作者:CIO之家的朋友  日期:2023/3/20  类别:架构设计  主题:综合  编辑:烈斯达
如果领域分解出的子域已经足够简单而清晰,问题域难度已经在解决问题的能力之下,这时我们可以聚焦一个子域,考虑如何根据上下文语义边界来划分限界上下文,建立通用语言,完成领域建模。

前言

上一篇我们分享了DDD 整体设计过程的四个关键阶段,对我们要实现的商城系统做了领域分解。如果领域分解出的子域已经足够简单而清晰,问题域难度已经在解决问题的能力之下,这时我们可以聚焦一个子域,考虑如何根据上下文语义边界来划分限界上下文,建立通用语言,完成领域建模。

为什么要领域建模

领域驱动设计的定位是应对软件开发的复杂度,在开发软件系统,我们需要理解业务领域知识,希望能够整理庞杂的知识,理清知识脉络,抓住问题的本质。在描述问题的形式,除了人的自然语言之外,我们还需要一种能够描述各种概念的形式,把概念整理清楚,以便一目了然的理解各种概念的关系。

image.png

领域建模输出的是领域模型,领域模型是比自然语言更清晰描述问题的形式,以图形的方式组织各种概念,有助于人对复杂信息的理解,是在具体工作前有效分析的基础。

结合DDD 与微服务的关系:领域建模输出的领域模型,作为微服务设计的战术设计的输入,领域模型可以清晰地划分微服务的逻辑边界和物理边界,用于指导微服务的设计和拆分。可以说,在 DDD 的实践中,好的领域模型直接关乎微服务的设计水平。

领域建模的过程

领域建模有几个关键步骤:

image.png

1. 事件风暴:通过头脑风暴的形式,列出领域中的所有领域事件,整合之后形成最终的领域事件集合,然后对每一个事件,标注出导致该事件的命令,每一个事件标出命令发起方的角色。命令可以是用户发起,也可以是第三方系统调用或者是定时器触发等。

2. 提取领域对象:从命令和领域事件中提取产生这些业务行为的领域对象,即实体或值对象。

3. 寻找聚合:从实体中找出聚合根,根据业务内聚原则找出聚合根关联所有的实体和值对象,构建”高内聚,低耦合”的聚合。确保关联紧密的领域对象能够内聚在一起,一起按照业务规则完成聚合的业务逻辑。

4. 划分限界上下文:根据上下文语义环境,将聚合进行归类,划定业务限界上下文边界和上下文服务地图,构建领域模型。

最终我们得到:

image.png

值得注意的是,在一个限界上下文中存在多个聚合,聚合与聚合之间的边界是一层逻辑边界(虚线表示),它们在同一个微服务实例中运行的。限界上下文之间的边界是物理边界(实线表示),不同的限界上下文是被隔离在不同的微服务实例中的。

实体 Entity、值对象 ValueObject、聚合 Aggregate,是我们要提炼出业务中的精华,合理的抽象为这3个概念,并且这种抽象是需随着领域里的概念变化而变化的。这3者的结合运用会让我们的项目活起来,这是DDD的核心。这里再把这3个概念重新梳理一下。

Entity(实体): 每个实体是唯一的,并且可以相当长的一段时间内持续地变化。我们可以对实体做多次修改,故一个实体对象可能和它先前的状态大不相同。但是,由于它们拥有相同的身份标识,他们依然是同一个实体。
ValueObject(值对象):值对象用于度量和描述事物,当你只关心某个对象的属性时,该对象便可作为一个值对象。实体与值对象的区别在于唯一的身份标识和可变性。
Aggregate(聚合):聚合类是实体的升级,是由一组与生俱来就密切相关实体和值对象组合而成的,这整个组合的最上层实体就是聚合。

构建商品子域的领域模型

让我们以上期做领域分解后得到的”商品子域”,使用事件风暴进行领域建模,同时输出我们将来要实现的商城系统所需要的领域模型。

image.png

功能描述

先来看看我们要实现的商品子域功能,限于篇幅,只举两个功能做分析,我用用户故事的方式来描述:

  1. 作为运营人员,我想要在商品发布系统,选择分类,填写商品信息,以便发布商品,填写商品采购单

  2. 作为采购人员,我想要根据采购单采购商品,并填写库存单,以便更新商品库存

  3. 作为运营人员,我想要在商品采购入库对商品进行审核,以便商品上架

image.png

战略设计

1. 产品愿景

事件风暴时,所有参与者针对每一个要点,在贴纸上写出自己的意见,贴到白板上。事件风暴主持者会对每个贴纸,讨论并对发散的意见进行收敛和统一,形成下面的产品愿景图。

image.png

2. 场景分析

场景分析是从用户视角出发,探索业务领域中的典型场景,产出领域中需要支撑的场景分类、用例操作以及不同子域之间的依赖关系,用以支撑领域建模。

项目团队成员一起用事件风暴分析请假和考勤的用户旅程。根据不同角色的旅程和场景分析,尽可能全面地梳理从前端操作到后端业务逻辑发生的所有操作、命令、领域事件以及外部依赖关系等信息。

根据我们的功能描述,我们有以下三个场景:

第一个场景:发布

用户:运营人员

  • 运营人员登录系统:从权限微服务获取运营人员信息和权限数据,完成登录认证。

  • 创建商品:打开商品编辑页面,选择商品分类,录入商品信息。保存并创建商品,提交保存草稿或发布。

  • 修改商品:查询商品,打开编辑页面,修改商品,提交保存草稿或发布。

  • 填写采购单:打开采购单编辑页面,填写商品SKU等信息,保存采购单。

第二个场景:采购

用户:采购人员

  • 采购人员登录系统:从权限微服务获取采购人员信息和权限数据,完成登录认证。

  • 查询采购单:打开采购单列表,选择采购单,批量导出采购单。

  • 填写库存单:打开库存单编辑页面,选择商品SKU,填写购入数量,保存库存单。

第三个场景:审核

用户:运营人员

  • 运营人员登录系统:从权限微服务获取运营人员信息和权限数据,完成登录认证。

  • 审核商品:获取待审核商品,根据商品sku获取对应的库存单,校对商品信息。

  • 商品上架:商品审核后完成商品上架。

相关的领域事件:

商品采购单创建后,进一步的业务操作:发送采购通知,通知采购人员采购商品以便更新库存
库存单创建完后,进一步的业务操作:发送入库通知,通知运营人员审核商品以便上架商品

image.png

3. 领域建模

领域建模是通过对业务和问题域进行分析,建立领域模型。向上通过限界上下文指导微服务边界设计,向下通过聚合指导实体对象设计。

第一步:找出实体和值对象等领域对象

根据场景分析,分析并找出发起或产生这些命令或领域事件的实体和值对象,将与实体或值对象有关的命令和事件聚集到实体。

下面这个图是分析后的实体与命令的关系。通过分析,我们找到了:商品、采购单、库存单、审批记录等领域对象

image.png

第二步:定义聚合

从上面的实体中,找到了两个实体根:商品,库存,根据聚合根紧密依赖的实体和值对象,我们发现分类与商品紧密依赖,库存单、采购单与库存紧密依赖。

于是就有了商品发布、审批、库存三个聚合:

image.png

第三步:定义限界上下文

由于商品发布与审批共同完成商品上架业务,所以在商品上架的限界上下文内,而库存聚合独立构成库存限界上下文

总结一下

本篇总结了领域建模的意义,领域建模的四个关键步骤,引出了三个重要概念:实体、值对象和聚合,并且举例说明了事件风暴中战略设计的全过程。过程中我个人认为最为困难的是场景分析,毕竟没有获得过业务全景,都是个人YY的,想要尽可能多地遍历所有业务细节不容易,也许这也是为什么事件风暴需要一个团体共同协作完成的原因吧。

以上过程中的场景分析,领域对象分析,聚合划分并不准确,欢迎提意见。


德仔网尊重行业规范,每篇文章都注明有明确的作者和来源;德仔网的原创文章,请转载时务必注明文章作者和来源:德仔网;
头条那些事
大家在关注
广告那些事
我们的推荐
也许感兴趣的
干货