【问题标题】:DDD: How to design history aggregate in ecommerceDDD:如何在电子商务中设计历史汇总
【发布时间】:2022-07-05 18:16:57
【问题描述】:

我有买方、产品、卖方和报价。买方提出购买产品,卖方要么接受要么拒绝。我还有以下不变量:

如果已经有待处理的产品,则买方无法为该产品提供报价。 卖方不能接受来自买方的不存在的报价。 我创建了以下聚合买家、产品、卖家、ProductOffers。 ProductOffers 包含来自所有用户的所有优惠。 ProductOffers 也有一个 TryMoveOfferToAccepted() 方法,当从买方提出 OfferCreatedEvent 时调用该方法。 TryMoveOfferToAccepted() 然后引发由 Product 聚合处理的事件 TryMoveOfferToAccepted,该聚合检查是否可以购买产品(检查是否有足够的数量...),如果成功引发事件 ProductBought 事件,然后由 ProductOffers 处理(移动报价从待处理到接受)。

这是一个好方法吗?在没有先检查买方的报价是否存在的情况下,我如何确定有人不会调用 Product 的聚合购买方法?

【问题讨论】:

  • 如果一次只能有一个有效报价,为什么不使用ProductOffers AR,为什么不立即为正在进行的报价预留库存以减少/消除?接受报价时缺少库存的风险?至于确保命令仅在 X 发生时发生,那么有时我将命令建模为 notifyXHappened(event) 而不是独立命令,例如product.notifyProductBought(event) 而不是 product.buy() 更好地传达耦合。
  • 无论如何,对我来说,ActiveProductOffer 可能是Product AR 的一部分,而历史将存在于外部,这允许在这里实现强一致性。
  • 我不预订库存,因为买家提出了要约,但他的要约可能会被拒绝。产品可以有来自许多不同买家的许多报价
  • 没关系,我读这个好像是卖单。如果您没有比集合更实用的分布式系统,那么对于唯一性集验证,您总是可以只使用 DB 唯一约束。如果不是,您可以考虑使用BuyerOffers 之类的集合,而不是ProductOffers,具体取决于哪个更大。

标签: aggregate domain-driven-design clean-architecture eventual-consistency


【解决方案1】:

你过度设计了你的问题。

回到您的用例:

  • 买家出价购买产品
  • 卖家接受报价

您可以使用单个聚合来建模,产品(根)+ 报价(对象值或实体)。名称ProductOffer 应该是一个很好的提示,表明该对象不应该是根“聚合”并且聚合到产品。另请注意,单个实体不是聚合的,它们是实体。术语聚合描述了具有多个对象的情况。

卖家可以使用Product.MakeOffer()出价。这将检查 Product.Offers 集合中没有来自该买家的现有待处理报价。

买家可以使用Offer.Accept() 接受报价。由于报价是聚合中的子项,因此您需要从存储库中返回整个聚合,以便您将 Offer.Quantity 与 Product.InStock 进行比较。

附录:

对于拒绝,您不需要那么复杂。聚合可以重叠成一个多义模型。您可以有一个单独的 Offer 实体(与 Product+Offer 聚合使用的实体不同)用于商品拒绝用例。这可以节省一些数据库读取性能。

【讨论】:

  • 如果某个产品的报价太多而我不想将它们全部加载到内存中怎么办?
  • 我是否可以创建聚合 UserProductOffer 以包含来自单个用户的产品的所有报价?这看起来怎么样?
  • UserProductOffer 不是聚合,因为没有根实体。此外,它不允许您强制执行跨越整个产品的任何业务规则。
  • 您不需要从数据库中读取所有 Product+Offers 属性,只需读取那些对规则验证有用的属性。这可以使您的业务对象非常精简,即使有数百万个。
  • 如果您仍然有太多数据,您将需要切换到最终一致性。检查报价可以在没有产品规则验证的情况下接受,引发 OfferAcceptingEvent,让产品检查库存是否允许,引发 OfferAcceptedEvent 或 OfferRejectedEvent,并更新报价。
【解决方案2】:

不要忘记简单。尽可能简化一切。你拥有的东西越少,就越容易控制它们。

【讨论】:

    猜你喜欢
    • 2019-07-03
    • 2019-08-24
    • 2010-11-21
    • 1970-01-01
    • 2020-10-04
    • 1970-01-01
    • 2019-07-29
    • 2018-09-03
    • 2016-12-06
    相关资源
    最近更新 更多