Skip to content

如何用事件风暴构建领域模型

"微服务设计为什么要选择DDD"?

其中有一个非常重要的原因,就是用DDD方法建立的领域模型,可以清晰地划分微服务的逻辑边界和物理边界。

但是,在与开发人员交流时,我发现有一部分人在学习DDD进行微服务设计时,似乎并不太关心领域建模的过程,而只是想通过学习DDD的战术设计思想,快速上手,设计和开发微服务。我认为这是对DDD的误解,偏离了DDD的核心设计思想,即先有边界清晰的领域模型,然后才可能设计出边界清晰的微服务,这两个阶段一前一后,不能忽略。

可以说,在DDD的实践中,好的领域模型直接关乎微服务的设计质量和水平。因此,我认为DDD战略设计会比战术设计更为重要,也正是这个原因,我们需要将领域模型的构建放在更重要的位置。

那么我们应该采用什么样的方法,才能从错综复杂的业务领域中,分析并构建出"高内聚,低耦合"的领域模型呢?

它就是我在前面多次提到的事件风暴(Event Storming)方法。事件风暴是DDD战略设计中经常使用的一种方法,它可以快速分析和分解复杂的业务领域,分析并提取出领域对象,构建聚合,划分限界上下文边界,对业务进行抽象和归纳,完成领域建模。

事件风暴概述

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

事件风暴过程也是建立团队通用语言的过程,这个过程对于项目团队确定项目建设目标、完成业务领域模型分析、系统建设和落地非常重要。

下面我们一起来看看在进行事件风暴时,应该有哪些参与者,需要提前准备什么材料,需要什么样的场地以及团队应该重点关注哪些内容。

  1. 事件风暴的参与者

事件风暴采用工作坊的方式,将项目团队和领域专家聚集在一起,通过可视化、高互动的方式一步一步将领域模型设计出来。其中,领域专家是事件风暴中必不可少的核心参与者。很多企业可能并没有这个角色,那我们该寻找什么样的人来担任领域专家呢?

领域专家是对业务或问题域有深刻见解的专家,他们不仅非常了解业务和系统是怎么做的,同时也深刻理解为什么要这样设计。如果你的企业没有领域专家这个角色,那也没关系。你可以从业务人员、需求分析人员、产品经理或者在这个领域有多年经验的开发人员里,按照这个标准去选择合适的人选。

除了领域专家,事件风暴的其他参与者可以是DDD专家、架构师、产品经理、项目经理、开发人员和测试人员等项目团队成员。

领域建模的过程是统一团队通用语言的过程,因此项目团队成员应尽早地参与到领域建模中,这样才能高效建立起团队的通用语言。等到微服务建设时,领域模型也更容易和系统架构保持一致,微服务也更容易完成落地。

  1. 事件风暴要准备的材料

事件风暴参与者会将自己的想法和意见写在即时贴上,并将贴纸贴在墙上的合适位置,我们戏称这个过程为"刷墙"。所以即时贴和水笔是必备材料。另外,你还可以准备一些胶带或者磁扣,以便贴纸能够随时更换位置。

值得提醒一下的是,在事件风暴的过程中,我们要用不同颜色的贴纸区分不同的领域行为,贴纸颜色至少要有三种。我们可以用蓝色表示命令,用绿色表示实体,用橙色表示领域事件,用黄色表示补充信息等。补充信息主要用来说明注意事项,比如外部依赖和事项说明等。贴纸的颜色并不一定要固定,这只是我的习惯。根据团队的具体条件和喜好统一并有所区分才是重点。

  1. 事件风暴的场地

什么样的场地适合做事件风暴呢?是不是需要和组织会议一样,准备会议室、投影,还有椅子?

这些都不需要!

你只需要一堵足够长的墙和一块足够大的空间就可以了。墙是用来贴纸的,大的空间可以让人四处走动,方便合作。撤掉会议桌和椅子后的事件风暴,你会发现参与者们的效率会更高。

事件风暴的发明者曾经建议准备八米长的墙,这样设计就不会受到空间的限制了。当然,这个不是必要条件,看各自的实际条件吧,不要让思维受限就好。

  1. 事件风暴的关注点

在领域建模的过程中,我们需要重点关注以下这类业务语言和动作等行为。

比如,某些业务动作或行为(事件)是否会触发下一个业务动作,这个动作(领域事件)的输入和输出是什么?是谁(实体)发出的什么动作(命令),触发了这个动作(事件)等。

我们可以从这些暗藏的词汇中,分析出领域模型中的事件、命令和实体等领域对象。

基于事件风暴的领域建模

领域建模的关键过程主要包括:产品愿景分析、场景分析、领域建模、微服务拆分与设计等几个重要阶段。

下面我以用户中台为例,介绍如何用事件风暴构建用户中台领域模型。

### 产品愿景分析

产品愿景分析的主要目标是完成产品顶层价值设计和分析,项目团队在目标用户、核心价值、产品需要具备的核心竞争力等方面达成一致,避免在建设过程中偏离方向。

在分析之前,项目团队要思考这样两个问题。

1)用户中台到底能够做什么?

2)用户中台的业务范围、目标用户、核心价值和愿景是什么,与其他同类产品的差异和核心优势在哪里?

思考的过程也是明确用户中台建设方向和统一团队思想的过程。

参与者要对每一个点发表意见,用水笔写在贴纸上,贴在右侧贴纸的位置。这个过程需要参与者充分发表意见,最后由主持人将这些发散的意见统一和收敛,精炼浓缩形成团队通用语言,建立产品愿景墙。

如果你们团队的产品愿景和目标已经非常清晰了,那产品愿景分析的步骤可以跳过。

场景分析

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

事件风暴参与者要尽可能地遍历所有业务细节,充分发表意见,不要遗漏业务要点。

用户中台有这样三个典型的业务场景。

1)系统和岗位设置,设置系统岗位菜单权限。

2)用户权限配置,为用户建立账户和密码,设置用户岗位。

3)用户登录和权限校验,生成用户登录和操作日志。

我们可以按照业务流程,一步一步搜寻用户业务操作流程中的关键领域事件,比如岗位已创建、用户已创建等领域事件。再找出是什么样的业务行为或操作引起了这些领域事件,这些行为可能是一个或若干个命令组合在一起产生的。比如创建用户时,对于内部员工,第一个命令是从HR系统中获取用户的员工信息,第二个命令是根据获取到的员工信息在用户中台创建用户,创建完用户后就会产生用户已创建的领域事件。

当然这个领域事件可能会触发下一步操作,比如发布到邮件系统通知用户已创建。但也可能领域事件到此就结束了。你需要根据具体的业务场景来分析是否还有下一步业务操作。

场景分析时会产生很多命令和领域事件。我用蓝色来表示命令,用橙色表示领域事件,用黄色表示补充信息。比如,用户信息数据来源于HR系统,我们就可以用黄色贴纸来进行标记:"用户从HR中获取"。

领域建模

领域建模时,我们会根据场景分析过程中产生的领域对象,比如命令、事件等之间的关系,找出产生这些动作的实体,从实体集合中找出聚合根,分析聚合根与实体之间的依赖关系并组成聚合,然后为聚合划定限界上下文边界,建立领域模型,分析领域模型之间的服务依赖关系,如上下文服务地图等。构建完领域模型后,我们可以利用限界上下文向上指导微服务设计,也可以通过聚合向下指导聚合根、实体和值对象等的设计。

领域建模的具体过程可以分为以下四步。

[第一步,提取领域对象。]

从命令和领域事件中提取产生这些业务行为的业务对象,即实体。我们用绿色贴纸来表示实体。通过场景分析产生的命令和事件等数据,我们分析并提取了产生这些行为的实体对象,如用户、账户、认证票据、系统、菜单、岗位和用户日志七个实体.

[第二步,构建聚合。]

根据聚合根的管理性质,我们可以从七个实体中分析并找出聚合根,找出聚合根引用的实体和值对象,构建聚合。

用户实体可以管理用户相关的实体以及值对象,系统实体可以管理与系统相关的菜单等实体,由此我们可以找出用户和系统这两个聚合根。然后根据业务依赖和业务内聚原则,将聚合根以及与它关联的实体和值对象组合为聚合,比如系统和菜单实体可以组合为"系统功能"聚合。

按照上述步骤,用户中台就有了系统功能、岗位、用户信息、用户日志、账户和认证票据六个聚合。

[第三步,划定限界上下文。]

根据业务上下文语义环境,将第二步产生的聚合归类,划定业务领域所在的限界上下文边界。

根据用户域的上下文语境,用户基本信息和用户日志信息这两个聚合共同构成用户信息域,分别管理用户基本信息、用户登录以及操作日志等信息。

认证票据和账户这两个聚合共同构成认证域,分别完成两种不同方式的登录和认证。

系统功能和岗位这两个聚合共同构成权限域,分别实现系统和菜单管理以及岗位配置。

根据这些业务语义边界,我们就可以将用户域划分为三个限界上下文,即用户信息、认证和权限。

[第四步,建立领域模型上下文服务地图。]

找出领域模型之间的服务依赖关系,分析并截断领域模型之间可能存在的循环依赖关系。限界上下文之间的服务关联应该是一种有向无环网状依赖关系。在解除服务循环依赖关系后,可以避免微服务落地时,出现服务循环调用。

到这里我们就完成了用户中台领域模型的构建了。

领域建模过程会产生大量领域对象,这些领域对象在微服务设计时会映射到微服务代码对象,因此非常重要。为了方便管理,我们用表格记下这些领域对象。

### 微服务拆分与设计

原则上,一个限界上下文内的领域模型就可以设计为一个微服务。但由于领域建模时只考虑了业务因素,并没有考虑微服务落地时的技术、团队沟通以及运行环境等非业务因素,因此在微服务拆分与设计时,我们不能简单地将限界上下文和领域模型作为微服务拆分边界的唯一标准,而只是将它们作为微服务拆分的一个非常重要的依据。

微服务设计时,要考虑服务粒度、分层、边界划分、依赖关系和集成关系。另外,除了考虑业务职责单一外,我们还需要考虑将敏态与稳态业务分离、非功能性需求(如弹性伸缩、安全性等要求)、团队组织和沟通效率、软件包大小以及技术异构等非业务因素。

如果不考虑非业务因素,在用户中台微服务设计时,我们完全可以按照领域模型与微服务一对一的关系来拆分和设计,将用户中台拆分为:用户、认证和权限三个微服务。

如果用户日志数据量巨大,大到需要采用大数据技术来实现,而用户信息聚合则采用了一般的微服务技术栈,那么这时候用户信息聚合与用户日志聚合就会产生技术异构。虽然在领域建模时,我将这两个聚合放在了同一个用户信息领域模型内,但由于它们在落地时会出现技术异构,所以它们并不适合放到同一个微服务里。

此时,我们可以将用户信息和用户日志两个聚合,作为微服务拆分的基本单元,拆分为用户基本信息管理和用户日志管理两个技术异构的微服务,分别采用不同的技术栈来实现。

小结

事件风暴是一种不同于传统需求分析和系统设计的方法,初次接触时可能很难建立感性认识。最好的学习方法就是找几个业务场景和项目团队多做几次事件风暴工作坊,相信你很快就能上手了。

综合我的经验,一般,一个中型规模的项目,完成领域建模和微服务设计的时间大概在两周左右,这与我们传统的需求分析和系统设计的时间基本差不多。

如果在领域建模的过程中,团队成员全员参与,在项目开发之前就建立了共同语言,这对于后续的微服务开发是很有帮助的,时间成本也可能会大大降低。

当然,事件风暴只是领域建模的一种方法和手段。如果你通过其他需求分析方法也能分析出业务领域的所有领域对象和领域事件,以及这些对象在领域模型中的业务行为和依赖关系,也能在团队建立通用语言,那么采用多种手段结合的方式也未尝不可。

总之,构建出边界清晰的领域模型,才是我们的最关键目标,这个过程我们可以灵活采用多种手段。

记住:目标只有一个,而手段却可以有很多。

Released under the MIT License.