简体   繁体   English

具有多个继承聚合根的 DDD + CQRS 模式

[英]DDD + CQRS pattern with multiple inherited Aggregate Roots

Disclaimer: I know that DDD/CQRS might not be a perfect choice for below use case, but it was working great so far for other tasks in the project and I want to stick with it for learning purposes (eg. learn the hard way where not to use it;).免责声明:我知道 DDD/CQRS 可能不是以下用例的完美选择,但到目前为止它在项目中的其他任务上工作得很好,我想出于学习目的坚持使用它(例如,学习困难的方法不要使用它;)。

Let's assume I'm building a Blogging Platform and have 3 types of posts: LifestylePost , RecipePost and ReviewPost .假设我正在构建一个博客平台并有 3 种类型的帖子: LifestylePostRecipePostReviewPost They have the same abstract base class PostBase which is an Aggregate Root and all of them share some properties like Author or implement methods like Publish , Delete etc. which change their Status and verify whether the state is valid.它们具有相同的抽象基础 class PostBase ,它是一个聚合根,它们都共享一些属性,如Author或实现方法,如PublishDelete等,这些方法改变它们的Status并验证 state 是否有效。 Each created post starts as a Draft which barely requires any validation, but switching to Published verifies nearly all properties.每个创建的帖子都以Draft开始,几乎不需要任何验证,但切换到已Published验证几乎所有属性。

Implementing commands/handlers like PublishPost or DeletePost was a breeze, but the problem starts when I'm thinking about CreatePost or UpdatePost .实现像PublishPostDeletePost这样的命令/处理程序是一件轻而易举的事,但是当我考虑CreatePostUpdatePost时问题就开始了。 These are some dilemmas I'm currently facing:这些是我目前面临的一些困境:

  1. Create/update commands/handlers for each post types or one for all为每个帖子类型或所有帖子类型创建/更新命令/处理程序

Having them separately for each post types gives me more control over the logic, allows to tailor each command model precisely, but makes my API more complex for the client.将它们分别用于每个帖子类型让我可以更好地控制逻辑,允许精确地定制每个命令 model,但让我的 API 对客户来说更加复杂。 With the second option I can resolve the post type by some discriminator in the command and check whether all necessary properties for that particular type were provided.使用第二个选项,我可以通过命令中的一些鉴别器解析帖子类型,并检查是否提供了该特定类型的所有必要属性。

  1. Create empty post draft first or already filled with the data首先创建空的帖子草稿或已经填充了数据

When a user creates a new post (draft with an initial state) I can already call the API and add an empty post to the database, which would then be updated or I can wait until user inputs any data and clicks save.当用户创建新帖子(具有初始状态的草稿)时,我已经可以调用 API 并向数据库添加一个空帖子,然后更新该帖子,或者我可以等到用户输入任何数据并单击保存。 It's basically a matter of the arguments in the constructors of the posts.这基本上是帖子构造函数中的 arguments 的问题。

  1. Handling post updates in general一般处理帖子更新

This is the point where I'm having the biggest issues now.这是我现在遇到最大问题的地方。 Since there are quite many properties that could or could not be changed by the user, it's hard to split them to particular methods inside the Aggregate Root different than just Update with huge amount of nullable arguments where null would mean that the property has not been provided by the client and therefore not changed.由于有相当多的属性可以由用户更改或不可以更改,因此很难将它们拆分为聚合根内的特定方法,而不仅仅是使用大量可为空的 arguments 进行Update ,其中 null 表示尚未提供该属性由客户提供,因此不会更改。 Also adding Status property here would mean that the proper method for validating the state would have to be resolved.此外,在此处添加Status属性意味着必须解决验证 state 的正确方法。 This solution somehow doesn't feel like a proper DDD design...这个解决方案在某种程度上不像是一个合适的 DDD 设计......

Which decisions would you make in each points and why?你会在每个点上做出哪些决定,为什么?

  1. Create/update commands/handlers for each post types or one for all为每个帖子类型或所有帖子类型创建/更新命令/处理程序

Depends on whether the difference in post types has influence over the API or not.取决于帖子类型的差异是否影响API。 If your clients have differentiated interactions with your API depending on the post type, then I would have specific commands for each type.如果您的客户根据帖子类型与您的 API 进行了不同的交互,那么我将为每种类型提供特定的命令。 If your API is post type agnostic, then this is internal business concerns.如果您的 API 与帖子类型无关,那么这是内部业务问题。 You should then ensure that domain implementation is sufficiently different from type to type, because polymorphic domain is a lot more work than a simple "category" property.然后,您应该确保域实现因类型而异,因为多态域比简单的“类别”属性要多得多。

  1. Create empty post draft first or already filled with the data首先创建空的帖子草稿或已经填充了数据

Depends on whether knowing a user has started working on a draft has any value for your system.取决于了解用户已经开始处理草稿对您的系统是否有任何价值。 If it's like a personal blog, probably not.如果它像个人博客,可能不是。 If you're writing software for a newspaper, then it could be insightful to anyone.如果您正在为报纸编写软件,那么它可能对任何人都具有洞察力。 Ask your domain experts.询问您的领域专家。

  1. Handling post updates in general一般处理帖子更新

This is an interface design question rather than a business logic one in my opinion.在我看来,这是一个界面设计问题,而不是业务逻辑问题。 If your users want to do a lot of small changes, you should consider providing PATCH routes in your API, with a standard like JsonPatch .如果你的用户想要做很多小的改变,你应该考虑在你的 API 中提供 PATCH 路由,使用像JsonPatch这样的标准。 Depending on your implementation technology, you could benefit from libraries that does the object patching for you, saving a lot of code writing.根据您的实施技术,您可以从为您进行 object 修补的库中受益,从而节省大量代码编写。

Is there really a difference in behaviour between the post types?帖子类型之间的行为真的有区别吗? Don't they all have Draft() , Publish() , Cancel() behaviours?他们不都有Draft()Publish()Cancel()行为吗?

Given that inheritance means X is a Y , then you're basically saying they are all the same.鉴于 inheritance 表示X is a Y ,那么您基本上是在说它们都是一样的。 This feels to me like a single Post aggregate with the possibility of a "PostType" value somewhere that might be part of an invariant (eg if you had a business rule that says "Review Posts cannot be published until a cooling-off period has elapsed).这对我来说就像一个单一的Post聚合,在某处可能有一个“PostType”值可能是不变量的一部分(例如,如果你有一个业务规则说“评论帖子在冷静期结束之前不能发布).

This would mean a single set of application services to invoke those methods (and validate the invariants they implement).这将意味着一组应用程序服务来调用这些方法(并验证它们实现的不变量)。

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

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