如何使用事件采购实现复杂表单的命令和事件?

时间:2018-03-08 22:45:34

标签: domain-driven-design event-sourcing axon

我想使用Axon框架实现CQRS和ES

我有一个相当复杂的HTML表单,代表招聘流程有六个步骤。
ES将有助于生成所选日期的历史统计数据并跟踪表单中的更改。

管理员可以随时执行多项操作:

  • 指派负责每一步的人员
  • 为每个步骤提供说明
  • 接受或拒绝每一步的候选人
  • 打开/关闭短信或电子邮件通知
  • 指定标签

表单更新(仅限差异)从UI应用程序发送到后端。

假设我只想对服务器端应用程序进行更改,那么问题应该是什么应该是一个命令以及什么应该是一个事件,我考虑三个选项:

  1. 表单补丁是生成Form Update Event

    的命令
    • 此解决方案的缺点是每个事件处理程序都需要检查表单中的更改是否引用此处理程序ex。如果发送关于拒绝的电子邮件应该发送
    1. 表单补丁是一个生成几个事件的命令: Interviewer Assigned, Notifications Turned OffRejected on technical interview

      • 此解决方案的缺点是可能会生成某些事件而其他事件不会因为中断约束而导致:Notifications Turned Off将成功,但Interviewer Assigned将因未分配未授权用户而失败。也许我应该在命令生成之前检查所有约束?
      1. 表单补丁转换为多个命令ex:Assign InterviewerTurn Off Notifications,每个命令生成事件ex:Interviewer Assigned, Notifications Turned Off

        • 此解决方案的缺点是某些命令可能会失败,因为Assign Interviewer可能会因为分配未经授权的用户而失败。这将导致状态不一致,因为某些事件将存储在存储库中,有些则不会。也许我应该在命令生成之前检查所有约束?

3 个答案:

答案 0 :(得分:4)

我会引起您注意的问题:您是否为您存储的信息创建权限,或者您只是跟踪来自外部世界的信息?

Udi Dahan写道Race Conditions Don't Exist;提出这个有趣的观点

  

时间上的微秒差异不应对核心业务行为产生影响。

如果您的系统中有未经授权的用户,那么在为特定步骤分配责任之前,他们是否真正对其授权的业务至关重要?系统真的可以告诉"故障"是责任分配给错误的用户,而不是用户被错误地授权?

Greg Young谈到exception reports in warehouse systems,并指出在这种情况下模型的责任不是阻止数据更改,而是报告数据更改何时产生不一致状态。

无论如何更新数据,业务成本是什么?

如果邮件的语义是Decision Has Been MadeSomething In The Real World Has Changed,那么您的模型不应该试图阻止该信息被记录。

由于你提到的原因,

FormUpdated并不是一个特别令人满意的事件;你必须做一些额外的工作,以特定领域的术语来施展它。如果有选择,您更愿意这样做一次。从事件从域不可知形式转换为特定于域的特定表单的角度来考虑它是合理的。

HttpRequestReceived ->
FormSubmitted ->
InterviewerAssigned

中间表示是短暂的。

答案 1 :(得分:3)

我可以看到第一个选项的一大缺点。使用Axon的CQRS / ES的最大优势之一是可扩展性。我们可以添加新功能而不必担心回归错误。添加新功能是为它们定义新命令,事件和处理程序的结果。它们都不应该与我们系统中存在的那些不相符。

FormUpdate作为命令需要在其中一个处理程序中添加额外的逻辑。将新属性添加到补丁并因此导致命令将导致当前逻辑的更改。在这种情况下,可伸缩性不再是优势。

答案 2 :(得分:1)

VoiceOfUnreason正在非常好地解释在开始使用这样一个系统时你应该考虑什么,所以一定要看看他的答案。

我唯一想补充的是,我建议你采取第三种选择。 通过您提供的示例,更通用的命令/事件不会告诉您域中发生的事情。更精细的事件可以更好地解释究竟发生了什么,因为事件消息的名称已经指出了它。

将Axon Framework拉入循环,我还可以添加几个指针。 从命令消息的角度来看,只是采取一条路线是安全的,而不是过多考虑它。该框架非常容易让您稍后调整命令结构。在Axon Framework培训中,通常建议让命令消息采用您正在执行的特定操作的形式。因此,将某个人分配到一个步骤通常是AssignPersonToStepCommand,因为这是您希望系统执行的确切操作。

从事件来看,稍后决定要获得细粒度或通用事件通常会有点麻烦。这是通过做事件采购得出的。由于事件是您的真相来源,因此您需要处理系统中所有形式的事件。

由于这个原因,我认为你的决定权重应该取决于你的事件变得多么精细。回到你的问题:在你给出的例子中,我会说选项3最适合。