我是DDD的新手,所以我只是理解它周围的基本概念。有人可以指导我更多关于DDD中的聚合对象吗?特别是,为什么要使用“聚合”对象以及在设计聚合时应用哪些关键原则?
谢谢,
答案 0 :(得分:3)
让我们从头开始吧。很久以前,在一个遥远的星系中,有一些ACID transactions的SQL数据库。我们真正感兴趣的是ACID缩写的原子性和一致性。例如,如果您有两个更改a1 -> a2
和b1 -> b2
并且您在这样的事务中进行了更改,那么更改必须是原子的,您将只有2个有效的状态选项:a1, b1
和{{ 1}}。因此,如果a2, b2
更改失败,则整个事务将失败。这称为立即一致性。
相比之下,没有SQL数据库,它们不符合ACID。通过这些数据库,您的更改不是原子的,您可以拥有多个状态:a1 -> a2
,a1, b1
,a2, b1
,a1, b2
,具体取决于更改的顺序或更改失败。这称为最终一致性。
如果您的分布式系统具有涉及多台计算机的复杂更改,那么您有两种选择。您可以使用最终的一致性,这将非常快,但数据在多台计算机上不会保持一致。或者您可以使用与2 phase commit的即时一致性,并且更新速度非常慢,但数据在机器之间将保持一致。
通过DDD,聚合是一致性边界:内部变化具有即时一致性,外部变化具有最终一致性。要坚持使用相同的示例,您需要使用命令更改2件事:a2, b2
和a1 -> a2
。如果这些内容属于同一聚合b1 -> b2
,那么您可以使用即时一致性在同一事务中更改它们:x
。如果这些内容采用不同的聚合:(x.a1, x.b1) -> (x.a2, x.b2)
,x
,则您无法在同一事务中更改它们,因此您必须使用最终一致性:y
和x.a1 -> x.a2
将是两个彼此独立承诺的交易。
根据弗农的书,DDD有一条规则;您无法在单个事务中更改多个聚合。如果你这样做,那么它就是代码气味,这是以不同方式选择一致性边界的标志,或者在其他方面设计不同的聚合。
因此,通过设计聚合,您必须牢记这些一致性边界。如果你不这样做,那么它将导致并发问题。例如,您在汇总y.b1 -> y.b2
上有a
和b
个属性。这些属性彼此独立,因此x
和(x.a1, x.b2)
都是有效状态。如果John想要更改(x.a2, x.b1)
并且Jane想要在两个并发请求中更改x.a1 -> x.a2
,那么其中一个请求将会失败,尽管这两种情况都是:x.b1 -> x.b2
和{{1}将导致相同的状态(x.a1, x.b1) -> (x.a2, x.b1) -> (x.a2, x.b2)
,并且每个步骤都是有效的。因此,John或Jane将通过同时处理相同的聚合来度过糟糕的一天。如果它们发送多个并发请求,可能都是它们。您可以通过创建新聚合(x.a1, x.b1) -> (x.a1, x.b2) -> (x.a2, x.b2)
并将(x.a2, x.b2)
属性移动到该聚合中来解决此问题。因此,两次交易中的更改将为y
和b
,这不会造成麻烦。
如果您有两个聚合x.a1 -> x.a2
和y.b1 -> y.b2
且属性x
和y
无法独立更改,则反向示例。因此x.a
和y.b
州无效。这是将这两个聚合合并为一个并使用直接一致性而非最终一致性的标志。
您的系统很有可能在多台计算机上运行。较大的组件,如有界上下文,聚合最终将是一致的,而小的组件,如值对象,实体将立即保持一致。因此,您可以在没有分布式事务和两阶段提交的情况下在多台计算机上部署有界上下文,从而实现快速可靠的系统。另一方面,由于您使用的交易,聚合只能拥有有效状态。
请注意,我不是该主题的专家,我只是读了一本书。 =]
1y之后:
我发现了一个非常good article about aggregates。根据它,你应该在不变量周围加上一致性边界,以防止违反合同。因此,如果您有一个不变量列表,那么您可以使用它们来定义一致性边界。聚合边界将类似。理想情况下,它们包含每个不变量,但是如果它们变得太大,它们将导致过多的并发异常,因此在复杂的情况下,它们不能包含一些不变量。
答案 1 :(得分:1)
这是一个概念,允许您指定哪些实体可以原子方式更改,哪些实体不能更改。
这也使聚合成为通过存储库加载和持久化数据的主要容器,即存储库处理整个聚合,而不是单个实体。
要找到合适的聚合设计,您需要完全了解您的用例,并尝试找出在一个事务中需要以原子方式更改哪些实体,以及您可以求助于最终一致性的位置。尝试使聚合变小,但始终首先考虑用例。