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

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,110评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,443评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,474评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,881评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,902评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,698评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,418评论 3 419
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,332评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,796评论 1 316
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,968评论 3 337
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,110评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,792评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,455评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,003评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,130评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,348评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,047评论 2 355

推荐阅读更多精彩内容