1.Event Storming
1.1 Event Storming 介绍
Event Storming(ES):由不同角色共同参与,用彩色贴纸进行交流的工作坊。
如上图,一群同学围绕一个业务场景,用贴纸进行交流,这就是 ES 工作坊。通过贴纸进行交流,让大家用同一种沟通语言,同一个思维方式,让大家的思维在一个频道上,这是 ES 的形式,也是 ES 的目的。
1.2 Event Storming 语法
ES 定义了一套彩色贴纸的“语法”:不同颜色的贴纸都有定义。浅黄色代表 Actor (角色)、蓝色表示 Command (命令)、粉色代表 Policy (业务规则)、浅粉色代表System(系统)、橙色代表 Event(事件),浅绿色表示 Read Model (读模型)、红色代表 HotSpot (热点/问题)。
用 ES 的语法表达用户的下单流程:买家 (浅黄色贴纸) 提交订单(蓝色贴纸),如果订单里商品是在线状态,购买量小于商品库存量(粉色贴纸 Policy) ,那么订单创建成功(橙色事件贴纸),已创建的订单(绿色贴纸) 展示给用户。订单创建后需要通知买家(业务规则,粉色贴纸),系统执行发送站内信(蓝色贴纸)
1.3 如何在业务中使用 ES
下面我们通过一个业务场景(优惠券的投放和使用)介绍如何使用 ES。
业务背景介绍
电商网站提供各种优惠券:满减券,折扣券,有无门槛券。
下图描述电商运营小二在活动中投放优惠券的整体流程:小二先创建优惠券,然后再创建一个活动,把优惠券和活动关联起来。活动通过公司财务的审批后才可发布上线。消费者在活动页面领取优惠券,在下单流程使用优惠券抵消金额。最后活动结束时要对整体活动的数据进行统计分析。
准备 Event Storming
在开始 ES 前,先做好准备:
准备物料:彩色贴纸、笔纸、一个足够大的房间等。房间里不要有椅子,因为在 ES 过程中,我们希望大家都全神贯注的投入,而不是坐在椅子上开始放松。
邀请正确的人:有问题的人和有答案的人。程序员、交互设计师、测试等都是有问题的人,需要通过 ES 理解业务和产品;有答案的人通常是用户、业务或产品,他们通常能回答业务的背景,诉求和目标。Event Storming 的过程
ES 可以分为开场介绍、ES 沟通业务和讲故事三个阶段。
开场介绍
在 ES 中有一个特殊的角色叫做 Facilitator(推动者),一般是 ES 的组织者。在 ES 开始前,Facilitator 向大家介绍 ES 是什么,有什么好处,以及彩色贴纸的用法。然后介绍讨论的范围和目标。
比如,今天讨论优惠券场景,目标是理清营销活动过程中优惠券的业务流程。最后 Facilitator 强调 ES 的规则:所有的讨论都写在贴纸上;不允许使用电脑,手机;也不允许坐下。在 ES 的后续过程中,Facilitator 还需要承担另外两个重要职责:保持参与者的专注,通过提问驱动交流。
ES 的方式沟通业务
第一步先梳理事件(橙色贴纸): 事件是已发生且重要的事情。事件必须是既成事实,且业务关注的事情。通常 Facilitator 会先准备第一个事件(可以是系统中任一事件), 然后把它贴到墙上。
假设第一个事件是:优惠券已领取。接下来 Facilitator 通过提问引导大家找到更多的事件:
- 事件发生前有哪些事件(“优惠券已领取”前须先有“活动已发布”事件)?
- 事件发生后下一个事件是什么(“优惠券已领取”后有“优惠券已使用”,“优惠券已过期”等事件)?
提问会引导参与 ES 的同学将新发现的事件不断补充到墙上。事件要保持整体的时间顺序:先发生的事情贴在左边,后发生的事情在右边。通常大家容易关注系统的正常流程,也就是 Happy path。这时候 Facilitator 需要引导大家关注业务的非正常流程 Unhappy path。边界条件,异常情况通常是业务复杂性的重要原因,也是非常容易被忽视的部分。
- 事件一定会发生吗(优惠券一定领取成功吗?不是,贴上“优惠券领取失败”事件)?
追问 unhappy path 梳理出业务的完整视图,当大家发现新事件的速度接近停滞的时候,就应进入梳理业务规则的阶段了。
Policy,业务逻辑或规则,这是业务中最重要的部分。Facilitator 会提出以下问题:
- 事件是否一定成功?如果不是,那么成功的前提条件是什么?
- 该事件是否会导致其他事件的发生(Reaction)?
例如“活动已提交”事件:
- 活动提交成功的前提条件:活动已关联有效优惠券,且已选择了生效方式,并且选择了适用人群。
- 活动提交后,会导致审核任务已创建事件,这里的业务规则是:活动提交或需创建审核任务。
接下来找出三个角色:Actor (和系统交互的人),Command (用户动作) 和 Read Model (辅助用户决策的工具)。Facilitator 提出以下问题:
- 是什么触发了事件?即事件发生的原因 (ES 的语法:when Event, then Command)
- 谁执行了动作。是人,系统,还是时间(例如定时触发的事件)?
- 做出动作前,用户需要获取哪些信息?
以上的问题会引导大家找到 Actor, command 和 Read Model。 在营销活动已提交事件中:小二(Actor)执行了提交活动(Command), 从而产生了“活动已提交”事件。
最后介绍 Hotspot:业务痛点、瓶颈、模糊点。Hotspot 是 ES 过程中随时都应该发现并记录下来的。Facilitator 可以引导大家发现业务中未描叙到的问题,例如:用户使用优惠券进行支付的场景中,如果用户支付失败,已使用的优惠券该如何处理呢?优惠券应该返还给用户,还是不做处理?通过提出这样的问题,引导大家对业务流程进行更深入的讨论。通常在 ES 的过程中,识别并记录 Hotspot,不要在 ES 中尝试解决所有的 hotspot。
以上介绍了 ES 的主要元素:Event,Policy,Actor,Command,Read Model,Hotspot。用 ES 描述了优惠券发放的业务流程,最后一步是“讲故事” (storytelling) 的阶段。
讲故事
Facilitator 邀请不同的人担任志愿者,每个志愿者讲一段故事:按时间顺序和 ES 描叙的逻辑, 向其他人介绍业务流程。过程中,听众注意到不一致的地方随时提出问题,大家讨论问题,通过增加/删除/移动贴纸来修复问题,并继续讲故事的流程。
最开始大家会按时间正序讲故事,最后大家还可以倒序讲故事。梳理业务的异常场景,倒序讲故事的方法更有效。例如为什么会发生“优惠券领取失败”事件,事件的原因是 balabala…
经过讲故事阶段的完善,大家获得了业务的完整理解,这时候可以结束讨论,保存相关材料,遗留下来的 Hotspot 交由相关同学跟进。
Event Storming 常见问题
ES 比其他方式更能帮助大家顺畅的沟通,但是对于首次参与或组织 ES 的同学也有一些疑问。 以下列出一些常见问题:
Q:ES 通常邀请多少人参加?我需要邀请所有角色吗?
A:不一定。ES 鼓励不同角色共同参与,但是参与人的态度更重要,积极主动参与是 ES 成功的关键。通常一个 Pizza (8 - 10人) 的规模,是适合 ES 人数。
Q:我的业务场景和复杂,在 ES 中要梳理完整个业务流程吗?
A: 不需要。ES 需要大家高度参与,因此需要控制好时间。每次 ES 的范围选择复杂业务场景的一部分,保证 ES 的效果。
Q:我应该在什么阶段做 ES?
A:项目的任何阶段都可以做 ES。ES 既可用于梳理业务现状,也可以用于设计业务的未来方案。
Event Storming 小结
下面的四个图直观的解释了 ES 的作用:
- 图 1,说明不同角色通过语言交流,虽然达成表面一致,实际上大家理解不一致。
- 图 2,ES 要求大家通过贴纸的形式可视化出来脑海中的想法,从而使分歧自动显现。
- 图 3,ES 通过不断的提问触发讨论,从而能够拉通认知,消除分歧点和模糊点。
- 图 4,ES 拉通了大家对业务的理解,从而达成了真正的共识。
总的来说,ES 让不同的角色用同一种语言(彩色贴纸)从全局对业务达成共识。
2.从 ES 到代码
简单介绍下 ES 如何顺畅过渡到 DDD(Domain-Driven Design 领域驱动设计)。
提取业务概念
DDD 中最重要的是统一语言:交流使用统一语言;模型表达统一语言;代码表达统一语言。语言是由概念组成的,ES 的过程已经将概念写在贴纸上,并且在交流中反复使用。例如:优惠券,营销活动,已领取优惠券,领取方式,人群等。
一部分概念有生命周期,并且有唯一的标识符。例如:营销活动,优惠券,已领取优惠券。这些就是 DDD 中的实体;还有一部分概念标识一个完整的业务含义,但是没有生命周期,并且属性相同的两个对象可以替换,这些对象就是 DDD 中的值对象,例如:领取方式,生效方式,人群。
提炼模型
概念和概念之间是有关系的。比如说,优惠券和营销活动有关联关系,已领取优惠券是在某个营销活动下领取的,营销活动也包含很多信息,它的生效方式是什么,领取方式是什么,人群是谁。概念与概念之间的关系也就是领域模型。
从模型到实现
将 ES 贴纸重新组合:围绕一个核心概念,将与该概念有关的 Event,Command,Policy 组合在一起。例如下图左边围绕营销活动为中心重新组织了贴纸(Command,Policy,Event),这些贴纸和右边的代码映射起来,这也就是 DDD 中说的代码表达统一语言。到此,简单介绍了如何从 ES 到概念,从概念到模型,以及模型和代码实现是怎么关联起来的。
架构,代码和约束
下图简单描述应用架构,代码结构,以及如何通过 ArchUnit 实现架构约束。