阅读 model/aggregate 简化的 DDD/CQS 模式中的代码组织,其中需要从其他域读取模型
Read model/aggregate code organization in simplified DDD/CQS pattern where read model from other domain is needed
首先,关于“简化的 DDD/CQS 模式”,我引用了 https://github.com/dotnet-architecture/eShopOnContainers 示例 dotnet 应用程序(这不是“严格的”DDD/CQRS)。但是我不是 dotnet 开发人员,我的问题与一般设计模式/代码组织有关。
我自己的案例如下:
我有 “会议”域,带有“会议”根聚合和“conference_edition”聚合。 RDBMS 语言会议中有许多版本。在这个域中,与外界的所有“通信”都是通过根聚合“会议”完成的。因此有 Conference.create()、Conference.addDraftEdition()、Conference.publishEdition() 等用例
我还有 “预订”域,它管理特定会议版本的预订(人们预订会议版本的门票)。
我的问题与“会议”服务(域?)的读取模型/聚合有关。此应用程序的 CMS 需要以下会议读取模型(为简单起见,json 中的示例):
{
"name": "My conference name",
"editions": [
{
// name, startDate, endDate can be directly read from "conference" domain aggregate
"name": "My conference 2021",
"startDate": "...",
"endDate": "...",
// following data come from "booking" domain
"completedBookingsCount": 20,
"pendingBookingsCount": 10,
"canceledBookingsCount": 2
},
...
]
}
我的问题是如何“制作”这个读取模型(如在简化的 DDD 示例 eShopOnContainers 中,我假设允许查询直接查询域聚合):
- 我可以通过处理来自“预订”服务的 BookingCreated、BookingCompleted 和 BookingCanceled 集成事件来制作额外的(域聚合之外的)读取聚合并更新它,以在“会议”服务读取模型中保留每个会议版本的统计信息,然后只是将其与“会议”和“版本”合计一起阅读。在这种情况下,我应该如何组织关于额外读取聚合的代码?我的意思是它仍然是聚合的,所以它应该“拥有”它自己的域,并带有诸如“increaseCompletedEventsForConferenceEdition”等命令?或者我应该在没有所有域限制的情况下尽可能简单,例如:
class BookingCanceledIntegrationEventHandler {
handle (BookingCanceledIntegrationEvent event) {
editionStatisticsRepository.increaseCanceledBookingsCount(event.editionId);
if (event.prevBookingStatus == 'pending') {
editionStatisticsRepository.decreasePendingBookingsCount(event.editionId);
} else if (event.prevBookingStatus == 'completed') {
editionStatisticsRepository.decreaseCompletedBookingsCount(event.editionId);
}
}
}
或者我应该在 api 网关端处理这个读取模型“shaping”?我的意思是查询两个服务“会议”和“预订”并在 api 网关端加入数据以组成所需的读取模型?
或者我应该将版本统计信息作为一种 ValueObject 添加到“版本”聚合中?然而 AFAIK ValueObjects 必须是不可变的,而且将这些数据(版本统计)放入“会议”域感觉是错误的......
如何should/could根据DDD/CQS模式进行组织?
第一个和第二个都合理。它们之间的选择将在很大程度上取决于您希望将业务逻辑传播到基础架构中的程度。
由于会议和预订域似乎是不同的限界上下文,因此只有在预订处于特定状态时才允许对会议版本进行某些更改时,第三种选择才是真正合理的。
首先,关于“简化的 DDD/CQS 模式”,我引用了 https://github.com/dotnet-architecture/eShopOnContainers 示例 dotnet 应用程序(这不是“严格的”DDD/CQRS)。但是我不是 dotnet 开发人员,我的问题与一般设计模式/代码组织有关。
我自己的案例如下: 我有 “会议”域,带有“会议”根聚合和“conference_edition”聚合。 RDBMS 语言会议中有许多版本。在这个域中,与外界的所有“通信”都是通过根聚合“会议”完成的。因此有 Conference.create()、Conference.addDraftEdition()、Conference.publishEdition() 等用例
我还有 “预订”域,它管理特定会议版本的预订(人们预订会议版本的门票)。
我的问题与“会议”服务(域?)的读取模型/聚合有关。此应用程序的 CMS 需要以下会议读取模型(为简单起见,json 中的示例):
{
"name": "My conference name",
"editions": [
{
// name, startDate, endDate can be directly read from "conference" domain aggregate
"name": "My conference 2021",
"startDate": "...",
"endDate": "...",
// following data come from "booking" domain
"completedBookingsCount": 20,
"pendingBookingsCount": 10,
"canceledBookingsCount": 2
},
...
]
}
我的问题是如何“制作”这个读取模型(如在简化的 DDD 示例 eShopOnContainers 中,我假设允许查询直接查询域聚合):
- 我可以通过处理来自“预订”服务的 BookingCreated、BookingCompleted 和 BookingCanceled 集成事件来制作额外的(域聚合之外的)读取聚合并更新它,以在“会议”服务读取模型中保留每个会议版本的统计信息,然后只是将其与“会议”和“版本”合计一起阅读。在这种情况下,我应该如何组织关于额外读取聚合的代码?我的意思是它仍然是聚合的,所以它应该“拥有”它自己的域,并带有诸如“increaseCompletedEventsForConferenceEdition”等命令?或者我应该在没有所有域限制的情况下尽可能简单,例如:
class BookingCanceledIntegrationEventHandler {
handle (BookingCanceledIntegrationEvent event) {
editionStatisticsRepository.increaseCanceledBookingsCount(event.editionId);
if (event.prevBookingStatus == 'pending') {
editionStatisticsRepository.decreasePendingBookingsCount(event.editionId);
} else if (event.prevBookingStatus == 'completed') {
editionStatisticsRepository.decreaseCompletedBookingsCount(event.editionId);
}
}
}
或者我应该在 api 网关端处理这个读取模型“shaping”?我的意思是查询两个服务“会议”和“预订”并在 api 网关端加入数据以组成所需的读取模型?
或者我应该将版本统计信息作为一种 ValueObject 添加到“版本”聚合中?然而 AFAIK ValueObjects 必须是不可变的,而且将这些数据(版本统计)放入“会议”域感觉是错误的......
如何should/could根据DDD/CQS模式进行组织?
第一个和第二个都合理。它们之间的选择将在很大程度上取决于您希望将业务逻辑传播到基础架构中的程度。
由于会议和预订域似乎是不同的限界上下文,因此只有在预订处于特定状态时才允许对会议版本进行某些更改时,第三种选择才是真正合理的。