Luc*_*ler 1 domain-driven-design aggregate boundary bidirectional
为了说明这个问题,我们使用一个简单的例子:有两个聚合 -Lamp
和Socket
。必须始终强制执行以下业务规则: aLamp
和 aSocket
都不能同时连接多次。为了提供适当的命令,我们设想了一个Connector
带有Connect(Lamp, Socket)
-method 的服务来插入它们。
因为我们希望遵守一个事务只涉及一个聚合的规则,所以不建议在事务中对两个聚合设置关联Connect
。所以我们需要一个象征Connection
自身的中间蕴。因此Connect
-transaction 只会Connection
使用给定的组件创建一个新的。不幸的是,此时麻烦开始了;如何保证连接状态的一致性?可能会发生许多并发用户想要在同一时间插入相同的组件,因此我们的“一致性检查”不会拒绝该请求。新的Connection
聚合将被存储,因为我们只锁定聚合级别。即使不知道这一点,系统也会不一致。
但是我们应该如何设定聚合的边界来确保我们的业务规则呢?我们可以设想一个Connections
聚合,它收集所有活动连接(作为Connection
实体),从而使我们的锁定算法能够正确拒绝重复的Connect
请求。另一方面,这种方法效率低下且无法扩展,而且在领域语言方面也是违反直觉的。
你知道我错过了什么吗?
编辑:为了总结这个问题,想象一个聚合User
。由于聚合的定义是基于事务的单元,我们可以通过锁定每个事务的该单元来强制不变量。一切皆好。但现在出现了一条业务规则:用户名必须是唯一的。因此,我们必须以某种方式使我们的总体边界与这一新要求相协调。假设有数百万用户同时注册,这就成了一个问题。我们尝试确保非锁定状态下的这种不变性,因为多个用户意味着多个聚合。
根据 Eric Evans 所著的《领域驱动设计》一书,一旦单个事务中涉及多个聚合,就应该应用最终一致性。但这真的是这样吗?这有道理吗?
在这里应用最终一致性需要注册User
并随后使用用户名检查不变量。如果两个User
s 实际上设置了相同的用户名,系统将撤消第二次注册并通知User
. 想到这种情况让我感到不安,因为它扰乱了整个注册过程。例如,发送确认电子邮件必须延迟等等。
我想我只是忘记了一些一般的事情,但我不知道是什么。在我看来,我需要类似Repository
级别上的不变量之类的东西。
我们可以设想一个连接聚合,它收集所有活动连接(作为连接实体),从而启用我们的锁定算法,该算法将正确拒绝重复的连接请求。另一方面,这种方法效率低下且无法扩展,而且在领域语言方面也是违反直觉的
相反,我认为您采用这种方法是正确的。这看起来很复杂,因为您使用的示例没有任何意义 - 现实生活中没有系统可以检查一盏灯是否连接到多个插座或一个插座是否连接到多个灯。
但是将该方法应用于第二个示例会导致您问自己在这种情况下“连接”聚合是什么,即用户名在哪个范围内是唯一的。在一个Company
?对于给定的Tenant
或Customer
? 对于整体<whatever-subdomain-youre-in>System
?找到范围的名称,您就拥有了它 - 一个强制执行唯一名称不变的聚合。仔细选择名称,如果通用语言中尚不存在该名称,请在领域专家的帮助下发明一个新概念。DDD 不仅尊重现有的领域术语,还允许您在实现突破时引入新的领域术语。
但有时,您会发现对此聚合的并发访问过于密集,并会产生有问题的争用。通过领域专家的同意,您可以在发生冲突时通过补偿操作引入最终一致性 - 例如,在昵称后附加后缀并通知用户。或者,您可以将“热”聚合拆分为更小、更智能、更高效的聚合。