如何实现DDD事件建模的详细步骤 - goeleven


为了分析现有的业务流程,我使用了一种称为事件建模的技术。这种建模技术主要集中于识别在业务流程中发生的有意义的业务事件。一旦识别出这些事件,它们便构成了设计过程的基础,该设计过程导致了DDD,CQRS和ES中描述的一组处理模式得以实现。
事件建模是亚当·迪米特鲁克(Adam Dymitruk)创造的一个术语,但该技术本身是建立在其他人的工作基础上的,例如埃里克·埃文斯(DD),马丁·福勒(Eventsourcing),格雷格·扬(CQRS)和阿尔贝托·勃兰多利诺(事件风暴)。
总的来说,这些模式的实现可以以数字方式支持所分析的业务流程。
如果您想将建模工作作为研讨会来进行,可以将Event Storming纳入其中,但也可以自己完成。
 
事件建模过程
要遵循事件建模过程,需要采取以下7个步骤:

  1. 识别事件
  2. 创建时间线
  3. 故事板
  4. 识别用户输入和命令
  5. 识别用户所需的信息
  6. 将事件分组为自治组件
  7. 识别消息处理模式

 
步骤1:找出事件
第一步,我将确定在执行现有业务流程期间发生的对业务有意义的事件。
例如,我将使用体育俱乐部的筹款流程的简化版本(预定之类的电子商务网站)。
它包含以下事件:
  • SalesOrderBooked
  • SalesOrderCommented
  • OrderConfirmationRequested
  • DiscountGranted
  • PaymentReceived
  • SalesOrderValidated
  • ProcessingStarted
  • DeliveryConfirmed

我将它们记录在橙色的便签纸上,然后将它们放在设计图面上。

“对业务有意义”意味着事件是状态变化的结果,状态变化使业务流程向前发展。因此SalesOrderBooked被认为是有意义的,SalesOrderValidated可能没有意义,因为它不会进一步推动该过程。
通常,识别过程中最重要的事件很简单,但是识别哪些是有意义的,哪些才是正当的,将需要一些时间和思想。
没关系,因为无论如何我都会迭代处理功能,因此在获得新的见解时,我可以在以后的迭代中添加,修改和删除事件。
 

步骤2:建立时间表
接下来,我按时间顺序组织已识别的事件,以便它们共同构成一个连贯的故事。

这样做时,我可能会发现缺少的事件,应将其添加到时间轴中。
我甚至可能会发现太多丢失的事件,以至于可以将它们自己分解为一个新的业务流程。
同样,我可能会发现,某些先前确定的事件实际上属于不同的过程,或者属于所分析过程的不同变体。
无论在哪种情况下,我都将这些事件搁置一旁,并在另一天进行处理。我一次只讲一个故事。
对于其他故事,只需重复该过程即可。
 
步骤3:情节提要
既然已经按照正确的顺序定义了事件,那么我将开始考虑参与该过程的不同人员的用户体验。
当故事中有多个角色时,我会为参加活动的每种类型的人使用泳道。
在此示例中,有一个Funder定购食品,一个Fundraising Manager用于跟进订单并处理物流,还有Checkin clerck一个将在募款日确认订单,处理并交付订单的食品。

对于这些角色中的每一个,我将绘制线框或模型以可视化角色如何参与该过程。
我必须决定哪种视觉方式将以最佳方式传达信息:列表,日历,导航搜索或其他?
如果用户需要使用表格来输入信息,则需要确定需要按下的按钮,表格上的哪些字段用于数据收集等,等等。
 
步骤4:识别用户输入和命令
每种输入形式或按钮都应导致一个或多个命令,这些命令将被发送到系统进行处理。
我将在图形和命令处理之间在输入表单和事件之间添加一个命令,通常以蓝色便签纸的形式。

例如,当Funder某人想要预订筹款活动时,她可以从俱乐部网站发出Book命令,这将导致SalesOrderBooked系统内部发生事件。
我还将花一些时间来定义应在命令上显示的信息,以使系统能够在该命令上执行该信息。通常,我会将其记录为与便利贴相关的评论。

- OrderId: generated
- Buyer 
    - Name: form field
    - Email: form field
- OrderLines
    - Id: generated
    - Quantity: form field
    - OrderedItem
        - Id: ?
        - Name: ?
        - Price: ?

这样,我可以验证用户所需的所有信息都以数据输入字段形式或以可视信息形式存在于模型中。
如果缺少某些信息,则这可能是一个很好的指示,说明我缺少定义它的另一个业务流程。
 
步骤5:识别用户所需的信息
用户将需要在其屏幕上提供信息,以便做出明智的决定并调用正确的命令。
然而,人类并不擅长将大量事件消化成有意义的东西。因此,系统需要创建这些事件中包含的信息的摘要。
在我的分类法中,这些摘要称为状态,由绿色便签纸表示。有时需要采取行动将状态告知用户,例如通过向他们发送电子邮件。在这种情况下,我将使用粉红色的便签纸。

例如,当一个Fundraising Manager想给予订单折扣时,系统将不得不向她提供一个Orders可供选择的清单。这是在此步骤中需要识别的信息。
我将所有必需的状态添加到图形中,并定义对象的形状,以及需要显示的信息。如果状态很简单,我将其添加为连接到便利贴的注释,否则,我可能会在侧面绘制一个小的UML图。
然后,将状态连接到保存信息的事件,以便填充信息。
 
步骤6:将事件分组为自治组件
一旦了解了流程中不同人员之间的数据流向后,就必须决定数据在系统内部的流向。

可以通过将事件分组到泳道中来定义组件,以使每个泳道都具有最大的自治权,并且每个泳道可以由一个单独的团队拥有。
以下步骤是自治的,它们在不同的时间,不同的位置,由不同的人员执行:

  • OrderBooking:此步骤是预先执行,以纸质形式或通过俱乐部网站执行的。所有信息都需要最终到达筹款经理处以计划筹款活动。
  • Payment:资金由司库分开处理,以现金,电汇或在线交易的方式接受。
  • OrderProcessing:此步骤仅在募捐活动当天由一组志愿者执行。

避免按名词分组(这是一个非常常见的错误),请确保按自治分组,并且各组件之间的依存关系应尽可能小。
另外,请确保不违反康威定理,并考虑到您的组织结构,以便每个自治组件也可以在组织内部得到自主支持。
 
步骤7:确定消息处理模式
现在,从产生的事件模型中,我可以确定消息流中存在的消息处理模式。对于每种模式,都有一种在俱乐部管理系统中实现它们的标准化方法。

有多种处理模式可在任何方向上在命令,事件和状态之间转换,在上面的图中,我已经显示了一些处理模式。
  • Aggregate Root聚合根:根据命令做出业务决策,并将其记录为事件。
  • Event Stream Processing:将事件流转换为其他事件。
  • Downstream Activity:基于命令或事件调用动作。
  • Projection投射:将事件流转换为状态。

总共有9种模式可支持命令,事件和状态之间的转换。
通过实施这种有限的模式集,您可以支持现有的大多数(如果不是全部)业务流程。