DDD 流程管理器:它们是业务逻辑的一部分吗?

dom*_*min 9 workflow domain-driven-design business-process-management hexagonal-architecture

一些消息来源声称流程管理器不包含任何业务逻辑。例如,微软的一篇文章是这样说的:

\n
\n

您不应使用流程管理器在您的域中实现任何业务逻辑。业务逻辑属于聚合类型。

\n
\n

再往上他们还这么说(强调我的):

\n
\n

需要注意的是,流程管理器不执行任何业务逻辑。它仅路由消息,并且在某些情况下在消息类型之间进行转换

\n
\n

但是,我不明白为什么消息之间的转换(例如从域事件到命令)不是业务逻辑的一部分。您需要领域专家才能知道正确的步骤顺序以及步骤之间的转换。在某些情况下,您还需要在步骤之间保留状态,甚至可能根据某些(业务)条件选择后续步骤。因此,并非所有内容都是给定步骤的静态列表(尽管\xe2\x80\x99d 也调用业务逻辑)。

\n

在我看来,在很多方面,流程管理器(或就此而言的传奇)只是另一种持久状态的聚合类型,并且可能具有一些业务不变量。

\n

假设我们用六边形架构实现 DDD,I\xe2\x80\x98d 将进程管理器放置在应用程序层(不是适配器!!),以便它可以对消息做出反应或由计时器触发。它将通过存储库加载相应的流程管理器聚合,并调用其上的方法来设置其(业务)状态或要求其发送下一个命令(当然,实际发送是由应用程序层完成的)。该聚合位于领域层,因为它负责业务逻辑。

\n

我真的不明白为什么人们要区分业务规则和工作流规则。如果删除除领域层之外的所有内容,您应该能够重建工作应用程序,而无需再次咨询领域专家。

\n

我\xe2\x80\x98d 很高兴从你们那里得到一些我可能缺少的进一步见解。

\n

dom*_*min 1

领域逻辑不仅存在于聚合和领域服务中。其他地方有:

\n
    \n
  • 适当处理领域事件。领域事件可以转化为一条或多条命令进行聚合;他们可以根据事件本身和/或其他聚合的状态的某些条件/策略触发这些命令;他们可以通知正在进行的业务流程以继续其下一步,等等。所有这些都是领域逻辑的一部分。
  • \n
  • 业务流程是一个(可能是分布式的)状态机,可能涉及各种参与者/用户/系统。允许的状态以及它们之间的转换都是域逻辑的核心部分。
  • \n
  • 传奇是跨越多个本地或外部聚合的最终一致事务,它成功完成或以尽力而为的方式补偿已经执行的步骤构成传奇的步骤只能由领域专家知道,因此是领域逻辑的一部分。
  • \n
\n

在我看来,这三件事被 \xe2\x80\x93 误认为是仅应用程序层的问题的原因如下:

\n
    \n
  • 为了处理域事件,我们必须加载并稍后保存受影响的聚合。因此,处理程序必须是应用程序层的一部分。但关键的是,不仅仅是。如果我们尊重六边形架构背后的思想,那么对于驻留在应用程序层的每个域事件处理程序,在域层中都必须有一个对应的事件处理程序。即使对于最简单的情况,其中一个域事件恰好转换为某个聚合上的一个命令方法调用。这在许多示例中可能被省略,因为它最初几乎没有增加任何价值。但试想一下,稍后翻译将基于一些进一步的业务条件。我们是否也将其放在应用程序层处理程序中?请记住:我们所有的域逻辑都应该位于域层中。\n
      \n
    • 旁注:即使我们尊重这种关注点分离,我们仍然可以选择让域事件由聚合本身处理,或者让它由瘦域服务转换为聚合命令。然而,这种选择是基于完全不同的考虑:我们是否想要更紧密地耦合聚合。这里没有正确或错误的答案。有些事情自然而然地耦合得更紧密,而另一些事情可能会受益于一些额外的间接性以提高灵活性。
    • \n
    \n
  • \n
  • 为了正确实现业务流程或传奇,我们必须处理各种特定于应用程序的问题,例如消息去重复、幂等性、重试、超时、日志记录等。尽管有人可能会认为域逻辑本身应该负责至少亲自处理其中一些方面(请参阅Vaughn Vernon 关于建模不确定性的精彩演讲)。但请记住,(允许的)步骤/操作序列的本质完全基于领域逻辑。
  • \n
\n

最后说一下耦合。在我看来,社区中有一种趋势,即耦合本身就是一件坏事,因此必须通过一切手段避免/减轻。这可能会导致诸如将事件命令翻译(记住:域逻辑!)放在六边形/洋葱/干净架构的适配器层中之类的解决方案。该层的职责是将某些东西适应具有相同语义/功能形式略有不同的其他东西(想想电源适配器)。它不是托管任何类型的域逻辑的地方,即使它非常简单。企业到处都有依赖性和耦合性。艺术就是在它实际所在的地方拥抱它,否则就避免它。我们在 DDD 中建立合作伙伴关系或客户/供应商关系是有原因的。如果我们关心域逻辑隔离,那么这些依赖关系就会反映在它们所属的位置:在域层中。

\n
    \n
  • 附注:反腐败层(DDD) 是适配器一个有效示例。例如,它可能需要一堆远程域事件,并以适合本地模型所需的任何方式转换/组合它们。它们仍然是过去发生的事件,而不是神奇地变成命令。改造只改变形式,不改变功能。从领域的角度来看,它并没有消除不可避免的耦合。它只是用稍微不同的语言重新表述相同的内容。
  • \n
\n