简体   繁体   English

在域驱动的设计中,为什么要使用“聚合”对象?在设计聚合时将应用哪些关键原则?

[英]In domain driven design, why would you use an “aggregate” object and what key principles would you apply when designing an aggregate?

I am new to DDD, and so am just understanding the basic concepts around it. 我是DDD的新手,所以我只是了解它的基本概念。 Can someone please guide me more towards aggregate objects in DDD? 有人可以指导我更多地介绍DDD中的聚合对象吗? particularly, why would you use an “aggregate” object and what key principles would you apply when designing an aggregate? 特别是,为什么要使用“聚合”对象,以及在设计聚合时将应用哪些关键原则?

Thanks, 谢谢,

Let's start it from the beginning. 让我们从头开始。 A long time ago in a galaxy far, far away there were SQL databases with ACID transactions . 很久以前,在一个遥远的星系中,存在着带有ACID事务的 SQL数据库。 What we are really interested here are the atomicity and consistency from the ACID ancronym. 我们真正感兴趣的是ACID首字母缩略词的原子性和一致性。 For example if you have two changes a1 -> a2 and b1 -> b2 and you make them in such a transaction then the changes must be atomic and you will have only 2 valid state options: a1, b1 and a2, b2 . 例如,如果您有两个更改a1 -> a2b1 -> b2并且在这样的事务中进行了更改,则这些更改必须是原子的,并且您将只有两个有效的状态选项: a1, b1a2, b2 So if the a1 -> a2 change fails, then the whole transaction fails. 因此,如果a1 -> a2更改失败,则整个事务都会失败。 This is called immediate consistency. 这称为立即一致性。

In contrast there are noSQL databases, which are not ACID compliant. 相反,不存在不符合ACID的SQL数据库。 By these databases your changes are not atomic and you can have multiple states: a1, b1 , a2, b1 , a1, b2 , a2, b2 , depending on what order the changes are made or which changes fail. 通过这些数据库,您的更改不是原子的,您可以具有多个状态: a1, b1a2, b1a1, b2a2, b2 ,具体取决于更改的顺序或更改失败。 This is called eventual consistency. 这称为最终一致性。

If you have a distributed system with complex changes which involve multiple computers, then you have two options. 如果您的分布式系统具有涉及多台计算机的复杂更改,则有两个选择。 You can use eventual consistency, which will be very fast, but the data won't be consistent on multiple machines. 您可以使用最终的一致性,这将非常快,但是数据在多台计算机上将不一致。 Or you can use immediate consistency with 2 phase commit , and the updates will be very slow, but the data will be consistent between the machines. 或者,您可以将即时一致性与两阶段提交配合使用,并且更新将非常缓慢,但是计算机之间的数据将保持一致。

By DDD the aggregate is a consistency boundary: the inside changes with immediate consistency and the outside changes with eventual consistency. 用DDD表示,聚合是一个一致性边界:内部以立即一致性进行更改,外部以最终一致性进行更改。 To stick with the same example, you want to change 2 things with your command: a1 -> a2 and b1 -> b2 . 坚持同一示例,您想使用命令更改两件事: a1 -> a2b1 -> b2 If these things are in the same aggregate x , then you can change them in the same transaction: (x.a1, x.b1) -> (x.a2, x.b2) using immediate consistency. 如果这些东西在相同的集合x ,则可以在同一事务中更改它们: (x.a1, x.b1) -> (x.a2, x.b2)使用立即一致性。 If these things are in different aggregates: x , y , then you cannot change them in the same transaction, so you have to use eventual consistency: x.a1 -> x.a2 and y.b1 -> y.b2 will be the two transactions which will be committed independently from each other. 如果这些东西在不同的集合中: xy ,则您无法在同一事务中对其进行更改,因此必须使用最终的一致性: x.a1 -> x.a2y.b1 -> y.b2将是两笔交易将彼此独立进行。

By DDD there is a rule according to Vernon's book; 根据弗农的书,DDD有一条规则。 you cannot change multiple aggregates in a single transaction. 您不能在单个交易中更改多个汇总。 If you do so, then it is a code smell, which is a sign to choose the consistency boundaries differently, or in other terms design the aggregates differently. 如果这样做,则会产生代码异味,这是不同地选择一致性边界的标志,或者换句话说,不同地设计了聚合。

So by designing aggregates you have to keep in mind these consistency boundaries. 因此,通过设计聚合,您必须牢记这些一致性边界。 If you don't do so, then it will cause concurrency issues. 如果不这样做,则将导致并发问题。 For example you have a and b properties on your aggregate x . 例如,集合x上具有ab属性。 These properties are independent from each other, so either (x.a1, x.b2) and (x.a2, x.b1) are valid states. 这些属性彼此独立,因此(x.a1, x.b2)(x.a2, x.b1)是有效状态。 If John wants to change x.a1 -> x.a2 and Jane wants to change x.b1 -> x.b2 in two concurrent requests, then one of the requests will fail despite the fact, that both scenarios: (x.a1, x.b1) -> (x.a2, x.b1) -> (x.a2, x.b2) and (x.a1, x.b1) -> (x.a1, x.b2) -> (x.a2, x.b2) would result the same state (x.a2, x.b2) and each of the steps are valid. 如果John要在两个并发请求中更改x.a1 -> x.a2而Jane要在两个并发请求中更改x.b1 -> x.b2 ,则尽管有以下两种情况,但其中一个请求将失败: (x.a1, x.b1) -> (x.a2, x.b1) -> (x.a2, x.b2)(x.a1, x.b1) -> (x.a1, x.b2) -> (x.a2, x.b2)将得到相同的状态(x.a2, x.b2)并且每个步骤都有效。 So either John or Jane will have a bad day by working on the same aggregate simultaneously. 因此,John或Jane会因为同时处理同一个聚合而日子不好过。 Probably both of them if they send multiple concurrent requests. 如果它们同时发送多个并发请求,则可能两者都使用。 You can resolve this problem by creating a new aggregate y and moving the b property into that. 您可以通过创建一个新的聚合y并将b属性移动到其中来解决此问题。 So the changes will be x.a1 -> x.a2 and y.b1 -> y.b2 in two transactions, which won't cause trouble. 因此,在两个事务中更改将分别为x.a1 -> x.a2y.b1 -> y.b2 ,这不会造成麻烦。

The inverse example if you have two aggregates x and y and the properties xa and yb cannot change independently. 如果您有两个聚合xy并且属性xayb不能独立更改,则为反示例。 So the x.a1, y.b2 and x.a2, y.b1 states are invalid. 因此, x.a1, y.b2x.a2, y.b1状态无效。 This is a sign to merge these two aggregates into one and use immediate consistency instead of eventual consistency. 这是将这两个聚合合并为一个并使用立即一致性而不是最终一致性的标志。

There is a good chance that your system will run on multiple machines. 您的系统很有可能在多台计算机上运行。 The bigger components, like bounded contexts, aggregates will be eventually consistent, while the small ones, like value objects, entities will be immediately consistent. 较大的组成部分(如有限上下文)将最终保持一致,而较小的组成部分(如值对象,实体)将​​立即保持一致。 Thus you can deploy your bounded contexts on multiple machines without distributed transactions and 2 phase commit, which will result a fast and reliable system. 因此,您可以在多台计算机上部署有限的上下文,而无需进行分布式事务和两阶段提交,这将带来一个快速而可靠的系统。 On the other hand the aggregates can have only valid states thanks to the transactions you use by them. 另一方面,由于您使用聚合,聚合只能具有有效状态。

Note that I am not an expert of the topic, I just read a book. 请注意,我不是该主题的专家,我只是读了一本书。 =] =]

1y later: 1年后:

I found a very good article about aggregates . 我发现了一篇关于骨料的很好的文章 According to it you should put consistency boundaries around invariants to prevent contract violation. 根据它,您应该在不变量周围设置一致性边界,以防止违反合同。 So if you have a list of invariants, then you can use them to define consistency boundaries. 因此,如果您有不变量的列表,则可以使用它们来定义一致性边界。 Aggregate boundaries will be similar. 总体边界将相似。 Ideally they include every invariant, but if they grow too big, they will result too many concurrency exceptions, so in complex cases they can't include some of the invariants. 理想情况下,它们包括每个不变式,但是如果它们变得太大,则会导致太多的并发异常,因此在复杂的情况下,它们不能包括某些不变式。

An aggregate is a consistency boundary 聚合是一致性边界

It's a concept that allows you to specify which entities can be changed atomically, and which not. 此概念使您可以指定可以原子更改的实体,以及不能更改的实体。

This also makes aggregates the primary container for loading and persisting data through a repository, ie repositories handle whole aggregates, not single entities. 这也使聚合成为通过存储库加载和持久存储数据的主要容器,即存储库处理整个聚合,而不是单个实体。

To find a suitable aggregate design, you need to fully understand your use cases and try to find out which entities need to be changed atomically in one transaction, and where you can resort to eventual consistency. 为了找到合适的集合设计,您需要完全了解用例,并尝试找出在一次事务中需要自动更改哪些实体,以及在哪里可以求助于最终的一致性。 Try to make aggregates small, but always consider the use cases first. 尝试使聚合较小,但始终首先考虑用例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM