DDD:领域驱动设计蒸馏不变量

问题描述 投票:0回答:2

我发现了很多围绕该主题的讨论 - 但只是为了确定:

  • 不变量/业务规则应该位于聚合内部
  • 以他为例,添加一条额外的业务规则:冲刺不允许超过 30 个故事点
    • 问题是,信息“30”在冲刺聚合中

问题:

  • 业务角色应该放在哪里? BacklogItem 聚合还是 Sprint 聚合?
  • 或者我是否必须将聚合边界更改为一个?
  • 或者 Sprint Aggregate 是否发送“BacklogItemRejected”事件?这听起来有点“过度设计”?
domain-driven-design
2个回答
0
投票

我会创建域服务,它应该用于管理不适合单个聚合的逻辑。

public class SprintService {

 public void addToSprint(BacklogItem item, Sprint sprint) {
  if (!sprint.canAddBacklogItem(item)) {
   throw new IllegalArgumentException("Item exceeds the maximum capacity.");
  }

  sprint.addBacklogItem(item); 
 }
}

我认为这种方法也可用于促进聚合之间的协作。


0
投票

这是一个非常有趣的问题,也涉及到很多关于 DDD 和实际开发的笔记。

首先,当您设计聚合时,您正在获取领域知识,将其拆分并决定什么需要事务一致性,什么不需要(最终一致性)。该决策将取决于许多因素(可能是与业务相关的因素,也可能是每个用例将执行的项目数量,等等)。具有事务一致性的可以一次保存一个(基于它们的 ID)(如果两个操作尝试同时保存相同的聚合,则需要拒绝其中一个)。

在您发布的图片中,有一个决定,即事务一致性是不可能的。如果设计是 BacklogItem 和 Sprint 应该是单个聚合,而 Sprint 是根聚合,则任何 BacklogItem 都应该通过 Sprint 进行修改。这会产生很多意外情况,因为如果一个用户正在修改 BacklogItem A(任何属性,比如说标题或其他任何内容)和另一个 BacklogItem B,并且他们都尝试保存到数据库,则其中一个应该被拒绝。

为了避免这种情况,团队决定使用最终一致性。这意味着每个 BacklogItem 都是单独修改的。一旦 BacklogItem 被提交,就会有一些通知机制(如事件驱动架构)。此后,Sprint 子域中应该有一些东西来处理此事件并决定是否需要撤消此提交(如果超过 30 个故事点)。此检查可以是 Sprint Aggregate 上的方法,也可以是域服务中的方法(SprintBacklogItemCommitService 或其他服务,不要害怕名称),无论哪种最适合。

由于每个 Sprint 一次只能修改一个,因此可以保持一致性。如果其中一个无法提交,则需要就此事件发出一个事件,并且有人将负责取消提交。

有一个替代方案,它将取决于应用程序的使用情况:如果 BacklogItemCommited 用例不经常执行,您可以仅针对此用例使用事务一次保存所有聚合。这将产生意外情况,但仅在执行 BacklogItemCommited 用例时发生,而不是在 BacklogItem 或 Sprint 上的每个操作上发生。

© www.soinside.com 2019 - 2024. All rights reserved.