个人认为,相比较传统领域分析方法,事件风暴的革命意义在于它建立了以“领域事件”为核心的建模思路,这相当于改变了我们观察业务领域的世界观。
当我们在理解业务需求时,我们看到的常常是功能、流程,并通过从需求描述中梳理领域概念,进而借助这些概念去识别那些参与到业务场景中互为协作的领域对象,这往往让我们忽略了一个在任何领域中都必须存在的概念,即“事件”。这些事件是每次用户操作、业务活动留下来的不可磨灭的足迹,它牵涉到状态的迁移,业务事实的发生,忠实地记录了每次执行命令后可能产生的结果。倘若这些事件还直接影响到该领域的运营和管理时,则可以将它们认为是“关键事件”。
正如Martin Fowler对领域事件的定义:“重要的事件肯定会在系统其它地方引起反应,因此理解为什么会有这些反应同样也很重要。”在识别和理解事件时,正是要从这样的因果关系着手,考虑为什么要产生这一事件,以及为什么要响应这一事件,进而思考如何响应这个事件,驱动着设计者的“心流”不断思考下去,就像搅动了一场激荡湍急的风暴一般。我想着或许是Alberto Brandolini将其命名为事件风暴的缘由吧。
在事件风暴中,往往使用橙色标签来代表一个“关键事件”。由于事件代表的是一个已经发生的事实(fact),所以往往用动词的过去时态来表达,例如OrderConfirmed事件。
在识别“事件”时,团队应与业务人员一起通过梳理业务流程,在统一语言的指导下共同寻找这些可能直接影响业务价值与运营目的的“关键事件”。在一个业务场景中,一系列“关键事件”连接起来,会形成明显的基于一条时间线的状态迁移过程。如下图所示:
这种状态迁移过程体现了业务的因果关系。这种因果关系是一种不断传递的过程,导致事件发生的因,在事件风暴中被称之为命令(Command),相当于事件的发布者,在事件风暴中使用蓝色标签来表示。一旦事件发生,作为该命令的结果又可能引起别的业务反应,事件的订阅者关心这一结果,然后触发新的命令,变成了下一个流程的起因。命令往往由动宾短语组成,例如Place Order、Send Invitation等。
注意,在识别事件时,要注意区分触发事件的四种情形:
- 由用户活动触发:例如用户将商品加入到购物车
- 外部系统:支付系统返回交易凭证
- 时间消逝导致:订单的支付时间超时
- 另一个领域事件的结果:支付命令产生支付完成事件(PaymentProcessed),该事件导致订单完成事件(OrderCompleted)
事件由命令触发,那么谁又是命令的发起者呢?答案是参与者(Actor)。参与者的引入就将对事件的分析与业务场景结合起来,这就驱动着参与事件风暴的所有成员要对业务达成一致(形成统一语言),并从用户体验(User Experience)的角度去分析每个业务场景。这时作为参与者对业务的参与,就不再是发起一个业务流程,执行一个业务动作,而是做出决策(Decision)。在事件风暴中,决策就是命令,但“决策”更具有拟人化的意义,正如在现实生活中,当一个管理者要做出决策时,需要如下两方面数据的支撑:
- 信息:必须基于足够充分的信息才能做出正确的决策,提供这些信息的对象就称之为读模型(Read Model),在事件风暴中用绿色标签表示。
- 策略:一旦做出决策就会触发一个业务流程,流程的执行暗含了业务规则,该规则被命名为策略(Policy),在事件风暴中用紫色标签表示。
描述策略时,往往可以使用“一旦(Whenever)”这个关键字来引导对策略规则的描述。策略引发的决策可以是自动的,也可以是参与者人为触发的。Alberto Brandolini给出了描述策略的实例,如:
whenever the exposure passes the given threshold, we need to notify the risk manager. 一旦关注的值超出给定的阈值,我们就需要通知风险管理者。
whenever a user logs in from an new device, we send him an SMS warning. 一旦用户从一个新设备中登录,我们就应该给用户发送一条短信警告。
在运用事件风暴时,我们可以通过用户体验(例如用户旅程等UX方法)剖析业务场景,从参与者到命令再到事件,又可以围绕着表达状态迁移的事件为核心,将策略与读模型组合在一起帮助我们推导出命令对象。Alberto Brandolini整体描述了事件风暴的驱动过程:
一旦我们识别了事件和对应的命令,我们就可以根据这些对象的生命周期与职责内聚性识别出聚合(Aggregate)与聚合根。聚合在事件风暴中使用黄色标签来表示。聚合是命令的真正发起者,这是相对于前面提到的参与者而言。在问题域中,是由参与者(用户、系统或其他特殊组件,如定时器)发起命令来“开启”一个业务流程。但在解决方案域,我们是从职责的角度去看待命令的,这就需要在领域模型中去寻找履行该职责的对象,即聚合。例如,在电商系统的业务流程中,问题域表达的是“买家购买了商品”,对应的解决方案域,则是“购物车添加了购物项”,因此分析获得ShoppingCart这个聚合对象。
一旦获得了这些内聚的聚合,就可以根据各自的相关性对聚合进行分组,从而获得限界上下文。在获得限界上下文的过程中,可以从业务、团队合作与技术实现等诸多方面进行判定。由于限界上下文属于解决方案域的内容,在初步获得限界上下文之后,团队就可以考虑这些限界上下文的技术实现。尤其是在微服务架构下,需要针对微服务特征来确定限界上下文的粒度与边界是否合理。此时,我们可以引入上下文映射,通过识别限界上下文之间的协作关系进一步确认它的合理性。