使用来自其他聚合的数据检查命令的有效性

问题描述 投票:2回答:3

我目前正在开发我的第一个更大的DDD应用程序。目前它运作良好,但我们一直困扰着一个问题,因为我不能停止思考的早期:

在我们的一些聚合中,我们保留了对整个应用程序非常重要的另一个聚合根的引用(基于它们的ID,因此没有硬引用 - 也是基于事件/最终一致性的删除)。现在,当我们创建一个新的Entity“Entity1”时,我们发送一个新的CreateEntity1Command,它包含引用的聚合根的ID。

现在我如何检查这个引用的ID是否有效?现在我们通过读取其他聚合来检查它(没有修改任何东西) - 但这种方法在某种程度上感觉很脏。我想“信任”命令,因为无法手动输入ID但必须选择。问题是,我们的应用程序是一个Web应用程序,并且信任您到达那里的用户输入是不安全的(即使它不是公众可访问的)。

我是否忽略了针对这些问题的任何可能解决方案,还是应该忽略需要更好解决方案的感觉?

web domain-driven-design aggregate
3个回答
1
投票

直接聚合到聚合交互是DDD中的反模式。聚合A不应直接向聚合B发送命令或查询。聚合是严格的一致性边界。

我可以想到你的问题的两个解决方案:假设你有2个聚合根(AR) - A和B.每个AR都有一堆命令处理程序,每个命令引发一个或多个事件。 A中的命令处理程序取决于B中的一些数据。

  1. 您可以订阅B引发的事件并在A中维护B的状态。您只能订阅指示有效性的事件。
  2. 您可以在A和B之间进行完全独立的服务(S)协调。而不是直接将您的请求发送给A,将您的请求发送给S,负责B的查询(检查引用ID的有效性)然后将请求转发给A.这有时称为流程管理器(PM)。

例如,在您创建新实体“Entity1”的情况下,将此请求发送给PM,其作业将验证请求中的数据是否有效,然后将您的请求路由到负责创建“Entity1”的聚合。发送一个新的CreateEntity1Command,其中包含引用的聚合根的ID到此PM,它使用引用的AR的ID来确保它是有效的,如果它是有效的,那么只有它会向前传递您的请求。

有用链接:http://microservices.io/patterns/data/saga.html


2
投票

验证另一个引用的Aggregate是否存在不是Aggregate的责任。它会破坏Single responsibility principle。当CreateEntity1Command到达Aggregate时,应该认为另一个引用的Aggregate处于有效状态,即它存在。

在Aggregate的边界之外,这种检查最终是一致的。这意味着,即使它最初通过,它也可能在此之后变为无效(即它是deletedunpublished或任何其他无效的域状态)。你需要确保:

  • 如果引用的Aggregate尚不存在,则拒绝该命令。在使用域服务将命令分派给Aggregate之前,请在负责用例的应用程序服务中执行此检查。
  • 如果引用的Aggregate之后进入无效状态,则执行更正操作。你应该在Saga / Process经理里面这样做。如果使用CQRS,您订阅相关事件;如果没有,你使用cron。它取决于您的域的正确操作是什么,但主要思想是它应该被建模为一个过程。

因此,长话短说,Aggregate的责任不会超出其一致性边界。

附:抵制将服务(域或非)注入聚合(通过构造函数或方法参数)的诱惑。


0
投票

我是否忽视了解决这些问题的任何可行方法

你做到了。 “域名服务”为您提供了一个可能的循环漏洞。

聚合是一致性边界;他们的行为受到约束

  • 聚合的当前状态
  • 他们传递的论据。

如果聚合需要与其边界之外的某些内容进行交互,那么您将域服务传递给聚合根以封装该交互。聚合可以自行决定调用域服务提供的方法来实现工作。

通常,域服务只是应用程序或基础结构服务的包装器。例如,如果聚合需要知道某些外部数据是否可用,那么您可以传入支持该查询的域服务,检查一些数据缓存。

但是 - 这就是诀窍:你需要意识到来自聚合边界之外的数据必然是陈旧的。即使您查询过时的副本,也可能有另一个进程更改数据。

问题是,我们的应用程序是一个Web应用程序,并且信任您到达那里的用户输入是不安全的(即使它不是公众可访问的)。

这是真的,但它通常不是域名问题。例如,我们可能会指定API中的端点需要某个命令消息的JSON表示 - 但这并不意味着域模型负责获取原始字节数组并为其创建DOM。应用层将承担这一责任;聚合的责任是域关注。

可以通过一些仔细的思考来区分不同关注点之间的边界。这个字节序列是聚合的有效标识符吗?显然是一个应用问题。另一个聚合是否处于允许某些行为的状态?显然是一个域名关注。汇总是否存在......?可以去任何一种方式。

© www.soinside.com 2019 - 2024. All rights reserved.