gpt4 book ai didi

domain-driven-design - DDD:我真的需要全部加载所有对象吗? (性能问题)

转载 作者:行者123 更新时间:2023-12-03 11:34:02 25 4
gpt4 key购买 nike

在DDD中,存储库加载整个聚合-我们要么全部加载,要么都不加载。这也意味着应该避免延迟加载。

我关心的是性能方面的问题。如果这导致将数千个对象加载到内存中怎么办?例如,Customer的汇总返回一万Orders

在这种情况下,是否意味着我需要重新设计和重新考虑我的骨料? DDD是否提供有关此问题的建议?

最佳答案

看看这本来自Vernon的Effective Aggregate Design系列三篇文章。我发现它们对于理解何时以及如何设计较小的聚合而不是大型集群的聚合非常有用。

编辑

我想举几个例子来改进我以前的答案,随时分享您对它们的想法。

首先,关于聚合的快速定义(摘自Scott Millet的“域驱动设计的模式,原理和实践”一书)

Entities and Value Objects collaborate to form complex relationships that meet invariants within the domain model. When dealing with large interconnected associations of objects, it is often difficult to ensure consistency and concurrency when performing actions against domain objects. Domain-Driven Design has the Aggregate pattern to ensure consistency and to define transactional concurrency boundaries for object graphs. Large models are split by invariants and grouped into aggregates of entities and value objects that are treated as conceptual whole.



让我们举个例子来看一下实际的定义。

简单示例

第一个示例显示了定义聚合根如何有助于确保对域对象执行操作时的一致性。

给定下一个业务规则:

Winning auction bids must always be placed before the auction ends. If a winning bid is placed after an auction ends, the domain is in an invalid state because an invariant has been broken and the model has failed to correctly apply domain rules.



这是一个包含“拍卖”和“投标”的汇总,其中“拍卖”为“汇总根”。

如果我们说Bid也是一个单独的聚合根,那么您将有一个 BidsRepository,您可以轻松地做到这一点:
var newBid = new Bid(money);
BidsRepository->save(auctionId, newBid);

而且您在保存出价时未通过定义的业务规则。但是,将拍卖作为唯一的汇总根,您正在执行设计,因为您需要执行以下操作:
var newBid = new Bid(money);
auction.placeBid(newBid);
auctionRepository.save(auction);

因此,您可以在 placeBid方法中检查您的不变量,并且如果他们想放置一个新的出价,没有人可以跳过它。

显然,出价状态取决于拍卖状态。

复杂示例

回到您的与客户相关联的订单示例,似乎没有不变性可以使我们定义一个由客户及其所有订单组成的庞大集合,我们可以通过标识符引用保持两个实体之间的关系。这样,我们避免在获取客户时加载所有订单,并减轻了并发问题。

但是,假设现在业务定义了下一个不变式:

We want to provide Customers with a pocket so they can charge it with money to buy products. Therefore, if a Customer now wants to buy a product, it needs to have enough money to do it.



话虽如此,pocket是客户汇总根内部的VO。现在看来,拥有两个分离的汇总根,一个用于客户,另一个用于订单,并不是满足新不变式的最佳方法,因为我们可以保存新订单而无需检查规则。看起来我们被迫以客户为根本。这将影响我们的性能,可扩展性和并发性问题等。

解?最终的一致性。如果我们允许客户购买产品怎么办?也就是说,具有订单的汇总根,因此我们创建订单并将其保存:
var newOrder = new Order(customerId, ...);
orderRepository.save(newOrder);

我们会在创建订单时发布事件,然后异步检查客户是否有足够的资金:
class OrderWasCreatedListener:
var customer = customerRepository.findOfId(event.customerId);
var order = orderRepository.findOfId(event.orderId);
customer.placeOrder(order); //Check business rules
customerRepository.save(customer);

如果一切都很好,我们将满足我们的不变性,同时保持我们的设计,就像我们一开始想要的那样,每个请求仅修改一个聚合根。否则,我们将向客户发送电子邮件,告诉她有关资金不足的问题。我们可以通过在她的当前预算中添加她可以购买的电子邮件替代选项并鼓励她自己掏腰包,来进一步完善它。

考虑到UI可以帮助我们避免客户支付的钱不足,但是我们不能盲目地信任UI。

希望您发现这两个示例都有用,并让我知道您是否找到针对暴露场景的更好解决方案:-)

关于domain-driven-design - DDD:我真的需要全部加载所有对象吗? (性能问题),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37662541/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com