我应该汇总哪些数据

What data should I keep in aggregates

我正在学习 CQRS 和事件溯源架构(with nestjs),我对聚合有点困惑。

我遵循这里解释的那种架构:https://danielwhittaker.me/2020/02/20/cqrs-step-step-guide-flow-typical-application/

如果我理解的很好,聚合根就是我的“写模型”。它使用将提交给事件总线的事件进行自我更新,我使用事件历史记录(或缓存)获取其当前状态。

因为我从来没有真正读取聚合根中的数据(只有接受或不接受下一个命令所需的数据),而且我不持久化它(事件是),我真的需要保留所有我的数据汇总?

我不确定我是否清楚,所以让我们看一个简化的例子:

我的购物网站有一个 CreateProduct 命令,还有一个 ProductCreated 事件。我使用事件的内容为某些查询创建视图,例如 GetProductByCategorySearchProduct、...

这里是命令:

class CreateProduct {
  public name: string;
  public description?: string;
  // ...
}

我跳过 commandHandler。如果我理解得很好,我的聚合根应该是这样的:

class ProductAggregateRoot extends AggregateRoot {
   public id: string;
   private name: string;
   private description?: string;
   
   create(data: { name: string, description?: string }) {
     if (! data.name) {
        throw Error('Name is required');
     }
     this.apply(new ProductCreated(uuid(), data));
   }
   
   onProductCreated(event: ProductCreated) {
     this.id = event.id;
     this.name = event.name;
     this.description = event.description;
   }
}

我可以这样做吗:

class ProductAggregateRoot extends AggregateRoot {
   public id: string
   
   create(data: { name: string, description?: string }) {
     if (! data.name) {
        throw Error('Name is required');
     }
     this.apply(new ProductCreated(uuid(), data));
   }
   
   onProductCreated(event: ProductCreated) {
     this.id = event.id;
   }
}

因为我从不在命令端使用 namedescription?在查询端创建视图对我很有用。

这让我感到困惑,因为它似乎与域相去甚远(产品不仅仅是一个 id)。但我不明白将这些数据保存在这里的意义。如果我改变主意,我可以稍后添加它并从历史中重建我的聚合根。

我不太了解 nestjs,但在事件溯源应用程序的一般实现中,绝对可以只使用您需要的字段来满足您的业务规则。所以在这种情况下,由于没有涉及名称或描述的规则,因此当您处理其他命令(可能是 DeleteProduct 或类似命令)时,它们不需要具体化到聚合根 class。

当您应用下一个命令时,您的应用程序应该再次从事件历史记录中具体化聚合根,因此是的如果需要,您可以稍后添加字段。

您可以在此处 (https://serialized.io/java/working-with-aggregates/) 查看序列化 Java 客户端的示例,其中 OrderPlaced 事件包含未读入瞬态的 amount处理命令时的订单聚合。