阅读 100

DDD实践(1)-事件风暴落地过程

事件风暴是一个团队活动,领域专家和项目团队成员通过头脑风暴的形式,罗列出领域中所有的领域事件,这时我们就得到了一个领域事件集合,然后为每一个事件标注出导致该事件的命令,再为每一个事件标注出命令的发起方的角色。命令可以是用户发起,也可以是第三方系统调用或者定时器触发等。最后对事件进行分类,整理出实体、聚合、聚合根以及限界上下文等,在限界上下文边界内构建领域模型。

一、准备工作:

  • 参与者:领域专家(业务人员、需求分析人员)、架构师、产品经理、项目经理、开发人员、测试人员等。
  • 准备材料:贴纸(至少有3种不同颜色)、水笔、胶带或磁扣。
  • 场地:一面足够大的墙和一块足够大的空间,比如说大会议室。,
  • 关注点:业务动作或行为,A动作是否会触发B动作,是谁发出的这个动作。

二、识别领域事件

事件风暴开始,领域专家和团队成员都聚集在大会议室中,准备好贴纸和水笔,大家通过头脑风暴把领域事件(业务行为)都贴到墙上,如以电商为例我们得到以下领域事件集:

image.png

注意我们的表述是这样的:主语+定语,如“订单已创建”。

这里又引出DDD中的另一个重要的概念——领域事件。
领域事件(Domain Event),是领域专家关心的,在业务上真实发生的事件,这些事件对系统会产生重要的影响,如果没有这些事件的发生,整个业务逻辑和系统实现就不能成立。我们可以通过领域事件对过去发生的事情进行溯源,因为过去所发生的对业务有意义的信息都会通过某种形式保存下来。领域事件在技术实现过程中可以被实现为专门的事件类,便于 实现事件驱动设计(Event Driven)。常见的影响有:

  1. 对内产生了某种数据 触发了某种流程或事情 状态发生了某种变化;
  2. 对外发送了某些消息;
  3. 规则(Policy),是对分支条件或复杂业务规则的抽象,目的是通过降低分支复杂度聚焦主要业务流程,未来在技术实 现时可能是一些分支条件,也可能应用适合的设计模式。

场景分析:是从用户操作视角出发,根据业务流程或用户流程,采用用例和场景分析方法,探索领域中的典型场景,找出领域事件、实体和命令等领域对象,支撑领域建模的过程。

比如电商业务中一个非常重要的参与者是C端用户,C端用户在电商业务中会去下单、去支付、去收货、去申请退款等等,我们就可以按照业务流程,一步一步搜寻用户业务操作流程中的关键领域事件。事件风暴的参与者要尽可能地遍历所有业务细节,充分发表意见,不要遗漏业务要点,我们把识别出来的领域事件写到贴纸上,贴到墙上,比如这个例子中我们用橙色来标注领域事件。

三、识别命令

前面第二步我们识别出了部分领域事件,那么这些事件是谁触发的呢?触发的动作是什么呢?这就是我们下面要进行的工作:识别命令。

命令可以理解为不同角色用户在界面上面的操作,比如“添加商品”,“编辑库存”,“提交订单”等; 有些命令可能产生多个事件,可以将他们用箭头联系起来; 在进行这个过程中,我们也需要将角色,通过不同的颜色标示出来,如本例中我们用蓝色来标识命令,黄色标识角色。

image.png

四、提取领域对象

从命令和领域事件中提取产生这些业务行为的业务对象,即实体。一个简单的做法是把领域事件中的名词都提取出来,如“商品已创建”中的“商品”、“订单已创建”中的“订单”、“库存已锁定”中的“库存”等都是领域对象,我们继续用黄色贴纸来标识这些实体。

image.png

实体(Entity):在DDD的领域模型中有这样一类对象,它们拥有唯一标识符,并且它们的标识符在历经各种状态变更后仍能保持一致,对这些对象而言,重要的不是属性,而是其延续性和标识,这种对象的延续性和标识会跨越甚至超出软件的生命周期,这样的对象就是实体对象。比如订单,每个订单都会有一个唯一且不变的标识——订单号,不管订单的状和属性怎么变化,订单还是那个订单,它的生命周期会贯穿甚至超出整个电商业务。

值对象(Value Object):值对象是通过对象属性值来识别的对象,它将多个相关属性组合为一个概念整体,用于描述领域的某个特定方面,并且是一个没有标识符的对象。

五、构建聚合

实体和值对象都只是个体化的业务对象,它们所表现出来的是个体的行为和能力。在领域模型中我们需要一个这样的组织,将这些紧密关联的个体对象聚集在一起,按照组织内统一的业务规则共同完成特定的业务功能,因此就有了聚合的概念。

在DDD中,聚合是一组紧密相关的领域对象,其目的是要确保业务规则在边界内的不变性,聚合根具有全局标识,所有对聚合内对象的修改,都只能通过聚合根进行,聚合帮助我们简化了复杂的对象网络,逐步做到“高内聚,低耦合”。

从技术的角度可以这么理解,聚合是由业务和逻辑紧密关联的实体和值对象组合而成的。聚合内数据的修改必须由聚合根统一组织,以确保每次数据修改都是按照聚合内统一的业务规则来完成,聚合是数据修改和持久化的基本单元。

比如订单是个聚合,它是由订单基本信息、商品信息、地址信息、发票信息等多个实体组成的,在订单聚合内每次修改商品数据时,它们都必须符合订单聚合的业务规则:“订单总金额等于所有商品明细金额之和”,违反了这个规则就会出现聚合数据不一致等诸多问题。

image.png

六、划定限界上下文

限界上下文(Boundary Context),是业务上下文的边界,在该边界内,当我们去交流某个业务概念时,不会产生理解 和认知上的歧义(二义性),限界上下文是统一语言的重要保证。

关于限界上下文有一个非常形象的定义:

细胞之所以会存在,是因为细胞膜定义了什么在细胞内,什么在细胞外,并且确定了什么物质可以通过细胞膜

一个聚合可能是最小颗粒度的界限上下文,同时,我们常合并业务相关性很高的聚合。

image.png

在未来的技术实现中,应当尽可能避免两个在概念上容易混淆的限界上下文内的业务需求,被同一个团队开发和维护。

七、梳理限界上下文依赖关系

通过分析依赖关系,提前识别依赖矛盾,减少低级设计错误的手段。每一个限界上下文都不会带有全量信息,那么补充信息的来源方向就是依赖方向,或者叫“知道(known)”的方向(我需要知道它的存在)

操作步骤:
  1. 集体分析和讨论,并利用带箭头的实线,以依赖方向为箭头方向,绘制不同限界上下文间的依赖关系。
  2. 若出现以下依赖关系,需要思考是否存在未澄清的问题:
    a. 双向依赖:上下文之间缺少一层未被澄清的上下文,或者两个上下文其实可被合为一个;
    b. 循环依赖:任何一个上下文发生变更,依赖链条上的上下文均需要改变;
    c. 过长的依赖:自身依赖的信息不能直接从依赖者获取到,需要通过依赖者从其依赖的上下文获取并传递,依赖链 路过长,依赖链条上的任何一个上下文发生变更,其链条后的任何一个上下文均可能需要改变;
image.png
【另附】限界上下文之间的映射关系主要有下面这几种:
  • 合作关系(Partnership):两个上下文紧密合作的关系,一荣俱荣,一损俱损。
  • 共享内核(Shared Kernel):两个上下文依赖部分共享的模型。
  • 客户方-供应方开发(Customer-Supplier Development):上下文之间有组织的上下游依赖。
  • 遵奉者(Conformist):下游上下文只能盲目依赖上游上下文。
  • 防腐层(Anticorruption Layer):一个上下文通过一些适配和转换与另一个上下文交互。
  • 开放主机服务(Open Host Service):定义一种协议来让其他上下文来对本上下文进行访问。
  • 发布语言(Published Language):通常与OHS一起使用,用于定义开放主机的协议。
  • 大泥球(Big Ball of Mud):混杂在一起的上下文关系,边界不清晰。
  • 另谋他路(SeparateWay):两个完全没有任何联系的上下文。

八、划分问题子域建立服务地图

操作步骤
  1. 根据“每一个问题子域负责解决一个有独立业务价值的业务问题”的视角出发,可以通过疑问句的方式来澄清和分析子域 需要解决的业务问题,例如“如何进行库存管理?(英文描述类似How to…?)”。
  2. 利用虚线,将解决同一个业务问题的限界上下文以切割图像的方式划在一起,并以“XXX子域”的形式对每个子域进行命 名。
  3. 根据三种类型的子域定义,共同结合业务实际(或者参考设计思维中的电梯演讲),确定每个子域的子域类型。
要点提示:

● 问题子域和限界上下文是完全不同的两个维度,问题子域解决的是问题澄清和优先级排序问题,限界上下文解决的是业务边界识别和统一语言的问题,所以在概念上其实不存在先后关系和包含关系,将两张图放在一起,是为了能够方便设 计和分析,可以理解为两张图的“叠加”或“映射”。
● 对于问题子域和限界上下文的映射关系,业内存在争论(是一对多关系还是多对多关系),经过大量的实践,结合可操 作性和理解上的便易性,我们刻意地选择和约定以下的映射关系:
○ 一个子域可以包含多个限界上下文
○ 一个限界上下文不应跨越多个子域 对于子域类型的判断,会随着视角的切换而有所变化,例如从全局视角识别的支撑域,从该支撑域所负责开发的团队视 角来看,该域则属于这个团队的核心域。
● 可以先识别核心域,再识别通用域,这样的话最后剩下的就全都是支撑域。

image.png

到这里我们就完成了电商领域模型的构建的事件风暴实践了。

作者:林_fbb8

原文链接:https://www.jianshu.com/p/4af0e0a4e850

文章分类
后端
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐