事件风暴(一)
1.介绍
一般来说,为了理解需求,我们首先要分析系统具有哪些功能,这些功能由什么人操作,会产生什么效果。这个过程传统上叫做“捕获行为需求”
捕获行为需求的方法有好几种,在传统的软件工程中,最常用的方法是“用例”,也就是Use Case。但是,Eric Evans在《领域驱动设计》这本书里,并没有规定捕获行为需求的具体方法。直到2013年,一位叫Alberto的DDD专家提出了“事件风暴”,也就是Event Storming
事件风暴是一种以工作坊形式开展的,用于协作探索和研究业务领域,特别是具有复杂流程的业务领域的系统分析方法。事件风暴也常用于开展领域驱动战略设计,可以快速分析和分解复杂的业务领域,完成领域建模
2.传统的方式
战略设计的根本目标——完成对业务全景的探索,从而实现从问题空间到解空间的最终转化。这一目标可以通过传统的UML建模方法或敏捷方法实现。UML建模方法的优势在于表达严谨、成熟度高,使用严格的UML图形符号,但有一定的学习成本和专业要求。而敏捷方法对技术人员要求很高,实践效果往往并不理想
在产品开发和迭代快节奏的情况下,新加入团队的成员需要快速了解现有业务。过去技术人员往往只需了解局部业务,产品经理也无法对所有业务进行完整描述。业务需求无论是各种用例还是用户故事,抑或是厚厚一沓需求文档,都难以让新老成员快速产生完整认知
3.设计思想
在软件系统设计和开发中,我们使用统一语言的原因是希望团队中的所有人达成一致。事件风暴提供了一套管理复杂软件系统多人协作的步骤和方法,可以尽可能让所有人参与表达、专注和思考,促成有效沟通。事件风暴制定了一些表现媒介和活动规则,并基于“面对面沟通”和“可视化”协作,使具有不同背景的团队成员之间可以进行跨学科、跨部门的沟通交流。下图展示了“面对面沟通”和“可视化”在共识达成过程中的重要性:
显然,“面对面沟通”和“可视化”可以使团队成员更容易达成一致
事件风暴充分利用了“面对面沟通”和“可视化”这两种协作方式。基于事件风暴的适应性,不同背景的项目干系人可以进行复杂的、跨学科的沟通交流——这是一种跨越信息孤岛和专业界限的新型协作方式
事件风暴具有多种用法,适用于不同的场景。一方面,事件风暴非常适合新成立的项目,因为新项目一般都会存在需求不清晰、理解不统一的情况,而事件风暴可以通过协作的方式厘清业务,促进领域专家和技术人员达成一致
另一方面,对于遗留系统,虽然普遍存在业务知识流失比较严重的现象,但事件风暴仍然是有意义的
4.目标
- 发掘现有的健康业务线中最有改进价值的地方
- 探索新业务模式的可行性
- 挖掘和设计新的服务,为每个参与方带来最好的正向结果
- 设计整洁可维护的事件驱动型(Event-Driven)软件,以支持快速发展的业务
5.使用限制
如果一个系统的业务复杂度不高,或者说业务很清晰,只需要进行相关的架构改造,那么应用事件风暴的意义不大
6.核心概念
事件
介绍
所谓领域事件,就是在业务过程中,业务人员要关注的那些已经发生的事儿。比方说,对于电子商务系统,订单已提交、商品已签收等等,都是领域事件。实际上,领域事件表示的是,业务流程中每个步骤引发的结果。事件风暴的作者认为,从结果入手来梳理需求,比从操作入手,更容易把业务想清楚。事件风暴中的“事件”两个字就来源于领域事件
事件代表某个行为的结果,是业务的重点。从事件可以正推或者反推整个业务流程,并呈现其中的各种业务概念
事件使用正方形橘黄色的便利贴表示
命名规则
一般使用“业务对象名+动作过去式”对事件进行命名。下表展示了“乘坐飞机”这一业务场景下的常见事件及对应的描述:
什么时候结束
- 事件增加速度:当团队增加新事件的速度明显放慢,几乎没有新事件出现时,就意味着这一环节已经接近尾声
- 固定时间:可以约定一个固定的时间范围,时间一到就意味着这一环节告一段落
- 在实际操作过程中,我们往往会综合这两种处理方式,确保提炼事件过程的收敛性
实践经验
提炼业务场景下的各种事件。我们不需要对事件进行排序,也不必担心事件是否冗余,并最终得到所有团队成员认为合理的事件集合,如下图所示:
注意事项
命名问题
咱们还要注意领域事件的命名,如果套用英语的语法来说,一般是完成时 + 被动语态。比如说,订单已提交,这个“已”字就是完成时,代表已经发生的事情。而订单已提交也可以说成订单已“被”提交,实际是被动语态,只不过一般把被字给省掉了
通常使用“主语+动作过去式”的方式来命名事件。典型的事件命名方式如下:TicketSubmitted,StaffAssigned,TicketFinished
从哪个业务流程开始识别
业务流程可能有很多,至于具体先做哪个流程,并没有特别的规定。但是建议从长流程的业务开始,然后再去处理其他的业务流程
不要把技术事件当成领域事件
领域事件一定要是领域专家所关注的,用的是业务术语。像数据库事务已回滚、缓存已命中之类的技术术语,不是领域事件,不在这个阶段讨论
查询功能不算领域事件
领域事件应该是对某样事物产生了影响,并被记录的事情。一般是某个事物的创建、修改和删除。还有一种情况是向其他人或者系统发消息,例如“通知邮件已发送”也算领域事件,因为接收方可能会通过进一步处理来影响某些事物
而像“客户信息已查询”这些就不算领域事件,因为还没有对事物产生实际影响。不过,这并不代表查询功能不重要,查询功能也要以某种方式体现。这一点在后续的课程我们再讲
纠错
业务用语不对
然后,就可以对比咱们两个人写得有什么不一样,再经过讨论得出一致的结果。现在,咱们从左到右看一下
第一步就发现了一个小区别。你写的是“客户已创建”,我写的是“客户已添加”
那么你就会问我:“业务人员一般会说客户已创建还是客户已添加呢?”
我告诉你:“一般是说客户已添加,因为从业务的角度,客户本来就是存在的 ,不需要创建,只是把客户资料添加到我们的系统而已”。你表示同意
然后我又叮嘱了一下:“以后添加客户的时候,都说添加这个词,别再说创建了”。这时候,其实我们已经是在建立“统一语言”了。统一后的结果是下面这个样子:
没用完成时和被动语态
第二步,你写的是“签订合同”,我写的是“合同已签订”
我们说过要用完成时和被动语态,“签订合同”是个动作,不是事件。所以达成一致后,结果变成下面这样:
没使用约定俗成的业务术语
下一步,你写的是“项目已创建”,我写的是“合同已生效”。不过我后面还有一步“立项”,应该和你的“项目已创建”是一回事,所以说明我比你多了一步“合同已生效”
于是你又问了:“合同签订以后不是马上就生效了吗,还要有一个额外的生效步骤吗?”
我解释说:“合同签订的时候未必马上生效,比如1月1日签了合同,但合同中可以约定,真正生效是在2月1日,所以需要一个单独的步骤让合同生效”。这时候,你知道了一条原来不知道的领域知识
然后你又问了:“我写了项目已创建,但是你写的是已立项,你这种写法好像和其他的不太一致呀。”
我解释说:“虽然我们为领域事件命名的时候,常常用‘什么什么已什么什么’的形式,不过如果业务上已经有约定俗成的术语,我们就直接使用术语,这样更容易和业务沟通。现在业务觉得已立项是一个通用的术语,写成项目已创建反而显得生硬”
现在你又知道了,在DDD中的各种命名,一般都优先使用约定俗成的业务术语。统一后的样子如下图:
事件时间线
将事件按照业务场景演进的顺序进行排序和组织。我们在前面介绍事件概念时引入了时间线的表现形式。在具体实操过程中,一个最佳实践是尽量先从成功的业务场景开始梳理事件流。下图展示了一种基础的时间线表现形式:
根据上面的表,我们发现每一个事件都有其自身的关注点,代表的是一种业务状态的变化。而这些业务状态的变化过程实际上是存在一定顺序的。下图展示了“乘坐飞机”场景下的常见事件及其演进时间线:
伴随着时间的演进,从“飞机票已购买”这个事件开始到“乘客已下机”这个事件结束,我们完成了对整个业务全景的探索
确定时间线的过程伴随着修复不合理的事件、删除重复事件等活动,必要时也可以添加新的事件,从而完善业务场景下的事件体系
分支事件流
面对复杂的业务场景,事件流可以引入分支,表示应用在某个事件前后的多个事件流程,如下图所示:
关键事件
介绍
获取大量事件之后,下一步是对这些事件进行梳理,从而确定关键事件(Pivotal Event)。什么是关键事件?在事件风暴中,对业务场景具有重大业务价值的事件被称为关键事件。关键事件前后的事件以竖线的形式划分,如下图所示:
上图展示了订单业务场景下的事件列表。我们认为,对于订单处理,“订单初始化”“订单已发货”“订单已交货”3个事件是关键事件
注意
请注意,关键事件的梳理并没有标准答案,而是需要根据实际情况进行讨论和斟酌。上图展示的只是订单业务场景下关键事件的一种表现形式。如果支付操作对人们非常重要,也可以将“订单已支付”事件作为一个关键事件进行管理
热点
介绍
事件风暴中提出了Hotspot这一概念,用来表示以下含义
- 不确定的点,业务领域中存在的疑问
- 有风险的点,存在不确定性
- 需要注意的一点,用来提醒业务人员和技术人员
就字面意思而言,可以将这个词翻译为“热点”,但笔者认为“问题点”这个词可能更加符合人们的认知。因此,在本书中,我们统一使用“问题点”来表示这个概念。而在表现形式上,我们使用粉红色的菱形便利贴来代表问题点
热点使用紫色的便利贴表示,文字描述可以随意点,没有格式要求
那些算是问题点
在实践过程中,问题点的表现形式非常多样,没有特定的约束,读者可以将自己认为有必要讨论的点都归为问题点。问题点对应的常用场景如下:
- 系统可能存在的瓶颈
- 针对业务场景缺失的领域知识
- 系统可能出现的各种异常场景
与事件的关系
请注意,问题点的讨论是围绕事件展开的,也就是说,事件是问题点的载体。因此,一般将问题点便利贴粘贴在事件旁边,表示该事件值得特别关注,如下图所示:
显然,并不是每一个事件都会存在问题点,而一个事件也可能存在多个问题点。在梳理问题点的过程中,不需要过多考虑问题点本身的合理性。但请注意,问题点中不允许出现任何技术类的描述,诸如“订单超时需要确保订单和库存之间分布式事务的有效性”这样的描述不是一个合适的问题点,因为它引入了“分布式事务”这个技术词语,破坏了DDD中关于统一语言的定义规范
命令
为什么需要
现在我们已经有了一组包含关键事件在内的事件列表,下一步要讨论的问题是:这些事件如何触发?
介绍
事件代表的是业务状态的变化,因此我们需要找出那些触发业务状态变化的操作。事件描述的是已经发生的事实,而决策命令(Decision Command)则描述的是触发事件的因素
与事件一样,命令的命名也有一定的规范,我们需要使用祈使句来表达命令。同时,在事件风暴中,命令通过浅蓝色便利贴进行展示,如下图所示:
在上图中,可以通过“提交订单”命令触发“订单初始化”事件,进而触发“订单已发货”和“订单已交货”等后续事件,最终推动整个订单处理流程的演进
其他情况
- 有些命令没有查询数据:比如添加客户,从需求来看,添加客户时不需要查询出什么其他信息
- 有的命令会有多个查询数据:比如说为项目分配员工,要查出项目和员工两个信息
- 有的命令会有多个执行者:例如更换客户经理,既可以由客户经理把自己的客户转给另一个客户经理,也可以由客户经理的上级来操作,这时就可以有不止一个执行者了
参与者
介绍
有了命令,我们自然会想到一个问题:该命令将由谁来触发?针对这个问题,我们抽象出参与者(Actor)这一概念。参与者代表业务领域中的一个用户角色(如客户、管理员等),是命令的触发者。在事件风暴中,我们使用亮黄色便利贴来展示参与者,如下图所示:
注意
请注意,并不是所有命令都会有一个相关联的参与者,因此只在明显存在参与者的地方才需要添加参与者信息。说到这里,读者可能会问:没有关联到参与者的命令又是由谁来触发的呢?答案就是接下来介绍的自动策略
自动策略
介绍
自动策略(Automation Policy)指的是事件触发命令执行的场景。换句话说,当某个特定事件发生时会自动执行与之相关联的命令。从这一点来说,与参与者一样,事件本身也是命令的一种触发者
在事件风暴中,使用紫色便利贴来标识自动策略
现实生活中的案例
现实世界存在大量使用自动策略的业务场景。例如,在淘宝上购物时,若订单的支付时间超过30分钟,该订单就会被自动取消。显然,这个过程是系统的自动行为,无须人工干预。再如,一旦触发“发货已批准”事件,就意味着订单可以发货了,这时可能触发一个“订单已发货”事件,而这也是一个自动化过程。下图展示了订单超时和发货批准这两个场景下的自动策略效果:
注意
策略的自动触发可以存在一定的规则,而不是无条件触发,可以在便利贴上注明具体的触发规则。例如,在上图中,我们指定“自动退款策略”的触发条件是“只针对线上订单”
读模型
介绍
我们接着来看事件风暴中的读模型(Read Model),这个概念比较简单。读模型是一种业务领域内的数据视图,参与者在其基础上做出执行命令的决策
某个Actor做出决策Command的前提是需要看到某些信息,或者说,支撑Actor更容易做出决策命令Command的信息。读模型一般是通过Web页面(UI/UX)来展示更多的信息,以让用户更容易做出决策
与命令的关系
换句话说,可以认为读模型就是命令的输入。在事件风暴的实施过程中,读模型被置于命令之前,我们使用绿色便利贴来标识该模型,如下图所示:
外部系统
介绍
命令的输入都是读模型吗?显示不是。在现实业务场景下,我们不可避免地需要与各种外部系统进行交互和集成。因此,在事件风暴中,人们提出了外部系统(External System)这一概念。所谓外部系统,即那些不属于正在探索业务领域的任何系统。外部系统可以作为命令执行的输入源,这和读模型的作用一致。外部系统也可以获取事件的通知,此时它的作用是输出。外部系统如图所示:
在事件风暴中,外部系统通过粉色便利贴进行展示。上图展示了外部系统分别作为命令输入及事件输出的应用场景
写模型(聚合)
某个Actor在某个聚合调用某种Command产生了某个Event
比如用户已注册(User Registered)事件,是由普通用户(Normal User)在注册薄(Register)上调用注册用户(Register User)这个命令而产生
一旦所有的事件和命令均被展示出来,就可以考虑通过写模型(Write Model)来组织相关概念了。在事件风暴中,通过黄色大便利贴来展示写模型,如图所示:
可以看到,写模型接收命令并生成事件,本质上就是聚合
限界上下文
在事件风暴的尾声,对业务场景下的所有写模型进行梳理,就能得到系统的限界上下文,如下图所示:
可以看到,某一个限界上下文中的事件可以触发另一个限界上下文中的命令。不同限界上下文之间的这种交互正是事件风暴想要达到的效果
整体解释
根据下图中的名字将整体串起来解释下
- 一个Actor根据看到的Query Model/Information
- 决定对External System或者Aggregate执行一个Command/Action
- 进而产生了某种Domain Event
- 此Domain Event可能触发了某种Policy,此Policy可能又对External System或者Aggregate执行一个Command/Action
- 此Domain Event也可能会导致Query Model/Information发生变化,从而给Actor提供更多信息以进行其他操作
根据图中各个便利贴的名称,可以将事件风暴的整个工作流程串接起来:一个参与者根据看到的读模型,决定对外部系统或者写模型执行一个命令,进而产生某种事件。该事件可能触发某种策略,此策略可能又对外部系统或者写模型执行一个命令。同时,该事件也可能会导致读模型发生变化,从而给参与者提供更多信息以进行其他操作
7.实践形式
事件风暴的灵活性决定了它有多种实践形式,这里主要介绍两种实践形式
- Big-Picture形式(侧重在业务全景):一种进行业务全景探索的EventStorming形式,侧重在业务方,重点是所有的干系人(StakeHolders),含研发Leader或者架构师
- Design-Level形式(侧重在全景中的某个业务上下文):一种用于更细节的软件设计的EventStorming形式,侧重在研发团队内部,含研发Leader或者架构师
8.DDD与事件风暴的关系
一般认为这两者的映射是这样的:
- Big-Picture形式的产出:对应战略设计中的领域分析,以划分领域边界和限界上下文
- Design-Level形式的产出:与DDD的战术设计可以联系起来,可以用来识别聚合根,实体等
其中统一语言是贯穿始终的!
但,两者可以映射起来并不代表他们之间有什么关系,DDD是以强调业务领域为核心的应对复杂业务系统研发的一套方法,而事件风暴只是探索业务领域的其中一种方式(也可以说是工具)
事件风暴对应事件建模范式,是以事件为视角来观察真实世界,通过事件引起的领域对象状态迁移来驱动出领域模型,进而影响软件实现的整体架构。与之对应的是对象建模范式,是以对象为视角来观察世界,一切皆为对象。而DDD则不关心使用哪种建模范式,只要以业务为核心,对系统进行建模即可,也就是说,事件和对象都可以是业务模型
9.三大阶段与事件风暴
10.宏观过程
准备工作
总览
- 人:参与人员
- 事:要讨论的事情
- 时:确定时间
- 地:确定地点
- 物:纸片啥的
确定目的和期望
组织人想好本次活动的目的和自己的期望,并提前与主持人(组织人不一定是主持人)沟通
邀请正确的人参加
传统的建模过程通常需要一名或几名研发人员来一起进行类设计、接口设计,通讯协议和数据映射等。而事件风暴则可能是较大的不同团队的成员来一起构建领域模型
谁是合适的人?根据Brandolini的说法,他们是知道提出正确问题和拥有答案的人。该小组可能是代表用户体验,业务,架构,开发,运维和营销等利益相关者的混合体
- 主持人(Facilitator):建议一定要有一名参与者负责主持会议进行、推动议程讨论。要严格注意时间与流程。最好不要跟Domain Expert重复
- 领域专家(Domain Expert):专案的主要推动者,或是拥有足够领域知识的人建议最好有一定的决定权,在陷入泥沼时才可以做出决定。如果是新创领域,可以事先做好使用者访谈或是找使用者来参加。可以不只一名
- 其他利益相关者(Other Stackholder):可能是参与专案的工程师、设计师,也可能任何能提供专业意见的人士如业务、商业分析师甚至是主管
预定活动场地
- 找到一面限制最少的表面来进行活动。不管是墙面、窗边甚至用多面移动白板组成都可以。你无法预测最后的产出有多少,所以尽你所能,不要因为空间而限制活动的品质
- 在表面上贴上大型画纸卷方便收纳产出以及进行另一场Event Storming
- 以最大化活动空间。将现场的杂物移开,不过可以留下一张小桌子放道具
- 一定要将椅子移走。经验中,只要有人坐下就会开始沉默,最后自我放逐
- 一面白板或海报写上名词定义清单。这场会议中的对话都要遵照清单上的用词
- 提供几张有图示标明(Legend)的海报纸
确定活动时长
根据目的和期望来确定活动的时长,一般是一个下午,3-6个小时。当然也可以连续1整天或者2天
发送活动邀请
提前至少一周发送活动邀请,附带上Event Storming的简介资料和Workshop的目标业务相关的资料,如产品的PRD
物料准备
马克笔多只,不同颜色和大小的即时贴,如蓝色,黄色,橙色,绿色,粉色
活动开始前
主持人提前到会议室,准备墙面,即时贴,马克笔,并将会议室的座椅全部移走,保证大家是站着围着墙面进行活动
活动进行时
具体步骤视具体活动形式和团队现状而定。以下仅作为参考:
- 开始时主持人先简单介绍下事件风暴,说明本次活动的目的以及本次活动的业务范围(尽量在10分钟内,不超过15分钟)
- 大家一起贴业务事件
- 按照时间顺序从头开始整理所有业务事件,这个过程中将热点(风险点或需要关注的点)识别并贴出来
- 从第一个事件开始识别并添加Actor(“谁”触发了事件)
- 划分上下文
- 或者从第一个事件开始直接添加决策命令和Actor,并增加读模型和UI设计草图
- 识别聚合
活动结束后
具体视活动形式有所不同。以下为大致要做的事情:
- 业务人员(产品经理)立刻开始整理收集到的业务知识,并尽快安排解决(额外组织会议或者做进一步调研)发现的问题。确定milestone和功能优先级
- PO开始进行(或完善)用户故事的书写
- 架构师开始进行(或完善)架构设计,或者开始进行必要的技术验证
- UI/UX开始设计草图
- 研发工程师开始进行项目初始化工作
- 测试工程师开始进行case的书写
11.微观过程
12.裁剪
介绍
事件风暴的创始人Alberto Brandolini认为事件风暴流程实际上是一种“指导性”流程,而不是一种“硬性规定”。各个团队可以根据自身的需求进行适当的裁剪,从而形成适合自身团队的工作流程。在本节中,我们将探讨这一话题,并给出实施事件风暴的指导意见
方式
常见的事件风暴裁剪方法包括步骤裁剪和粒度裁剪两种类型,裁剪之后,我们将得到不同版本的事件风暴变体
步骤裁剪
上面给出的开展事件风暴的详细工作流程一共包括11个步骤。在具体实施过程中,并非所有步骤都需要严格执行。如果想以最简单的步骤完成对业务全景的探索,那么可以采用的最简模式如下:
- 识别领域事件
- 识别决策命令
- 识别写模型
- 确定限界上下文
通过以上4个步骤,可以完成事件、命令和领域名词的提炼,并最终形成可用于解空间的限界上下文,从而让领域专家和技术人员对业务场景产生整体认知,完成从问题空间到解空间的转化。这是实施事件风暴的第一阶段
如果想在这个阶段添加更多内容,那么可以在第二阶段中包含以下步骤:
- 确定自动策略
- 确定读模型
- 确定外部系统
为什么将这3个步骤放到第二阶段实施呢?核心点在于它们影响了命令的触发机制和条件。这对于确定事件的状态变化至关重要
事件风暴的“确定时间线”“确定问题点”“确定参与者”等步骤通常可以作为补充步骤来实施,条件不允许的情况下可以省略,因为这些步骤更多的是对业务场景细节的补充,而不是决定业务场景的最终交付产物
最后剩下的一个步骤是“梳理关键事件”,该步骤是否实施的决策来自事件的数量和维度。如果业务场景比较简单,且事件的类型并不复杂,则无须区分核心事件和普通事件;而如果事件数量很多,且具备较为复杂的分类维度,则建议区分核心事件和普通事件,以便更好地把握业务场景下的核心事件
粒度裁剪
关于事件风暴裁剪,另一个值得探讨的话题是如何合理设计产物的粒度。也就是说,开展事件建模时,我们应该如何把控细节。此时同样可以有两种实施策略——蓝图型事件风暴和设计型事件风暴
从命名上看,蓝图型事件风暴用于探索业务场景的全貌,侧重于业务方,通常由领域专家作为主导者。这种类型的事件风暴需要和所有的利益相关人一起探索,发现业务全景,并搭建一个平台,让所有人都能贡献自己的专业知识,了解业务全景、风险点,以及探讨产品中的逻辑漏洞
设计型事件风暴的主导者往往是架构师,侧重于研发团队。这种类型的事件风暴是一种用于更细粒度的软件设计的事件风暴形式。团队所有人都需要了解某个上下文的业务全景,学习更多的业务知识,以便启动研发工作。其中,研发团队需要进行业务建模、统一业务语言并了解业务优先级,而业务人员则应补充更多关于实现落地的细节
从粒度的角度,可以认为设计型事件风暴是蓝图型事件风暴的细化和补充。因此,这两种类型的事件风暴既可以单独使用,也可以组合使用。但是请注意,无论选择哪种事件风暴的实施粒度,都不适合用作底层技术,这是开展事件风暴最基本的原则
可以基于以下原则选择合适的实施粒度:
- 当更多关注业务场景下跨部门的协作与对齐时,应该选择蓝图型事件风暴
- 当软件的业务领域已经比较清晰,软件系统即将进入研发时,应该选择设计型事件风暴
- 当从零开始构建一个复杂的业务系统时,建议同时实施蓝图型事件风暴和设计型事件风暴
13.三大表
建立词汇表
接着我们来建立词汇表,也就是把事件风暴和领域模型中重要的词汇列成表。为什么要建立词汇表呢?主要是有两个作用
首先,我们需要通过词汇表来规范领域模型中的词汇。同一个词,可能会在领域模型中出现多次,时间久了,就可能不一致,因此需要进一步规范
第二,是可以用于后续编程中的命名。按照DDD的要求,程序中的各种命名也需要统一,并且需要与领域模型中保持一致。我们会在词汇表中列出英文全称和缩写,以达到这个目的
词汇表是保证统一语言的重要手段,例子如下:
建立业务规则表
我们在做事件风暴时就开始识别业务规则了,在后面的领域建模中可能又识别出了更多的规则,所以我们需要一张表保存业务规则
建立领域模型表
在后面完成领域建模后会产出很多领域对象,我们我们可以借助表格来记录
14.事件风暴常见问题
在事件风暴里是否要列出所有的领域事件和命令
你可能已经发现,在我们现在做的事件风暴里,其实只列出了部分领域事件和命令。例如,有签订合同这个命令,但没有修改合同和删除合同,但修改和删除功能应该也是系统中必要的
其实,列出所有领域事件和命令并没有原则上的错误,但这样做会让结果变得繁琐,反而让人抓不住重点
所以我的建议是:在事件风暴里只列出主要的、足以用于表达和交流领域知识的步骤,例如签订合同、生效合同等等。而像修改合同和删除合同这样的步骤是显而易见的,在讨论过程中可以提一下,但不必真的列出来,这样是为了保持简洁
那么不列出来,怎么保证这些功能不被遗漏呢?我们可以结合用户故事或者传统的功能列表等方法保存系统功能的全集,这样就能解决了
各个领域事件需要体现严格的时间顺序吗
在上一讲我们说过,只需要按照大致的顺序,贴出领域事件就可以了。这是因为,如果要体现严格的时间顺序,需要用到更复杂的符号,例如条件判断,还有要画更多的连线,这会使事风暴变得非常繁琐
因此,我们应该关注点分离。如果要体现严格的时间顺序,我们可以用流程图、用顺序图等方法,但事件风暴不必关注这一点
每个步骤的颗粒度应该有多大
这里说的步骤,指的是一对领域事件和命令
比如说,“签订合同”这个命令,在具体操作的时候,可能分成录入合同基本信息、录入合同明细、上传附件等等更小的步骤。那么,我们需要为每一个小步骤都识别出领域事件和命令吗?
这就要考虑从业务的角度,我们是把每个小步骤都当作独立的一个事务来看待,还是把它们合起来作为同一个事务
另外,可以设想,如果每个小步骤都向外界发出一个领域事件,对系统后续的功能是不是有意义。那么在目前的需求里,合同作为一个整体来提交就可以了,分成小的领域事件,并没有意义,所以不再分成更小的步骤了
在实践里,有时仍然会有模棱两可的情况,这时,原则上宜粗不宜细。可以先采用比较大的颗粒度。后面必要的时候,再拆细,就可以了
事件风暴适用于所有项目吗
这个问题可以从两个层面回答。第一个层面,事件风暴主要应用在需求不清晰,或者理解不统一的情况下,通过协作的方式理清业务、达成一致,所以通常对于新项目比较适用
至于遗留系统改造的情况,如果这个系统的知识已经流失得很严重,那么事件风暴仍然是有意义的。但如果大家对这个系统的业务知识很清楚,只是要进行架构改造,那么事件风暴的意义就不大了
第二个层面,即便在适用的场合,事件风暴也不是唯一的方法,我们还可以用用例分析、用户故事等方法实现类似的目的。只要抓住协作、统一语言等等要点,这些方法都可以用在DDD的项目里
所以,如果你的项目里还没有正规的、令人满意的捕获行为需求方法,那就可以使用事件风暴。如果已经有了成熟的方法,你可以借鉴事件风暴的思路,在原来的方法里加入协作、统一语言、识别领域名词的实践,也能达到同样的效果
怎么保存和维护事件风暴的结果
到现在为止,事件风暴的结果都是贴在便利贴上的,显然不容易长期保存。一般来说,我们可以在事件风暴的过程中专门安排一个记录员,由他使用PPT之类的画图工具,把贴在纸上的内容重新画一遍,就可以实现电子化的保存了
还有一个更深入的问题是,事件风暴是不是需要长期维护和更新?还是说我们只是把事件风暴当作一次性的步骤,不必长期维护?
通常,如果事件风暴的内容最终会反映到用户故事、用例、功能列表等产出物中,而这些产出物会进行维护,那我们就不必专门更新事件风暴的产出物了,只在需要的时候作为一种沟通工具,将电子化的结果作为一种中间产物保存就可以了
但是,如果你的团队并没有用户故事和用例等保存行为需求的方式,那么我建议你对事件风暴进行维护和更新
如何使用表格来保存事件风暴结果
除了绘图之外,事件风暴也可以用表格的形式来保存,例子如下:
怎么保存领域规则
领域规则是重要的领域知识,必须妥善保存。在事件风暴的过程里我们已经识别出了一些领域规则,在后续的领域建模阶段,可能还会识别出更多。如果只是写在便利贴上,或者画在图上,时间长了,就很难维护了
所以,我们要编一个领域规则表,把所有的领域规则都汇总在里面,然后再把领域规则表和领域模型放在一起,作为领域知识的重要组成部分,后面就是一个例子