Domain driven design 如何使用事件源为复杂表单实现命令和事件?

Domain driven design 如何使用事件源为复杂表单实现命令和事件?,domain-driven-design,event-sourcing,axon,Domain Driven Design,Event Sourcing,Axon,我想使用Axon框架实现CQRS和ES 我有一个非常复杂的HTML表单,它用六个步骤表示招聘过程 ES将有助于生成选定日期的历史统计数据,并跟踪表单中的更改 管理员始终可以执行多个操作: 指定负责每个步骤的人员 为每个步骤提供注释 在每个步骤上接受或拒绝候选人 打开/关闭SMS或电子邮件通知 分配标签 表单更新(仅限差异)从UI应用程序发送到后端 假设只对服务器端应用程序进行更改,问题是什么应该是命令,什么应该是事件,我考虑三个选项:< /强> 表单补丁是一个生成表单更新事件的命令

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

我有一个非常复杂的HTML表单,它用六个步骤表示招聘过程
ES将有助于生成选定日期的历史统计数据,并跟踪表单中的更改

管理员始终可以执行多个操作:

  • 指定负责每个步骤的人员
  • 为每个步骤提供注释
  • 在每个步骤上接受或拒绝候选人
  • 打开/关闭SMS或电子邮件通知
  • 分配标签
表单更新(仅限差异)从UI应用程序发送到后端

<强>假设只对服务器端应用程序进行更改,问题是什么应该是命令,什么应该是事件,我考虑三个选项:< /强>


  • 表单补丁是一个生成
    表单更新事件的命令


    • 此解决方案的缺点是,每个事件处理程序都需要检查表单中的更改是否引用此处理程序,例如,是否应发送关于拒绝的电子邮件

  • Form patch是一个生成多个事件的命令,例如:<代码>指定面试官,关闭通知,
    在技术面试中被拒绝


    • 此解决方案的缺点是,某些事件可能会生成,而其他事件则不会生成,因为违反了限制条件,例如:
      关闭通知
      会成功,但
      指定的采访者
      会因分配未经授权的用户而失败。也许我应该在生成命令之前检查所有约束

  • 表单修补程序转换为多个命令,例如:
    指派面试官
    关闭通知
    ,每个命令生成事件,例如:
    面试官指派,通知关闭

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

  • 我想提醒你注意的问题是:你是在为你存储的信息建立一个权威机构,还是只是在跟踪来自外部世界的信息

    乌迪·达汉写道;提出这个有趣的观点

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

    如果您的系统中有未经授权的用户,那么在为他们分配特定步骤的责任之前对他们进行授权对业务是否真的至关重要?系统真的能判断出“错误”是责任分配给了错误的用户,而不是用户被错误地未授权

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

    无论如何,如果您更新数据,业务的成本是多少

    如果消息的语义是做出了
    决策
    ,或者
    现实世界中的某些东西发生了变化
    ,那么您的模型不应该试图阻止记录该信息

    FormUpdated
    并不是一个特别令人满意的事件,因为您提到的原因;您必须做大量额外的工作才能将其转换为特定领域的术语。如果有选择的话,你宁愿做一次。在进行过程中,将事件从领域不可知的形式转换为领域特定的形式是合理的

    HttpRequestReceived ->
    FormSubmitted ->
    InterviewerAssigned
    

    中间表示是短暂的。

    VoiceOfUnreason很好地解释了在开始使用这种系统时应该考虑的问题,所以一定要看看他的答案

    我唯一想补充的是,我建议你选择第三种选择。 在您给出的示例中,更通用的命令/事件并不能说明域中发生了什么。更细粒度的事件可以更好地解释到底发生了什么,因为事件消息及其名称已经指出了这一点

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

    从事件来看,稍后决定您想要的是细粒度事件还是泛型事件通常有点难堪。这源于事件源。因为这些事件是你真相的来源,因此你需要处理你系统中所有形式的事件


    因此,我认为,您的决策的权重应该取决于事件的细粒度。回到你的问题:在你给出的例子中,我认为选项3最合适。

    我可以看到第一个选项的一个大缺点。使用Axon的CQRS/ES的最大优势之一是可伸缩性。我们可以添加新特性,而不用担心回归错误。添加新功能是为它们定义新命令、事件和处理程序的结果。它们中没有一个不应该与我们系统中现有的系统相匹配

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