在 DDD 整体中跨服务/模块时,在我的处理程序中调用调解器是不是正确
Posted
技术标签:
【中文标题】在 DDD 整体中跨服务/模块时,在我的处理程序中调用调解器是不是正确【英文标题】:Would calling a mediator be correct in my Handler when crossing services/modules in a DDD monolith在 DDD 整体中跨服务/模块时,在我的处理程序中调用调解器是否正确 【发布时间】:2020-06-01 00:03:31 【问题描述】:架构前言
在微服务中,这可能是符合干净架构的服务:
篮子服务
API 应用程序 [CQRS] 核心 基础设施目录服务
API 应用程序 [CQRS] 核心 基础设施但由于我将 DDD 应用于单体应用,我目前可以删除我的 Api 层并减少“项目”/模块。因此,每个模块(例如购物篮和目录)目前都包含 3 个项目:
应用 核心 基础设施两者都依赖于.Core
问题描述
我的应用程序有一个 BasketModule 和一个 CatalogModule。 使用 Mediator 从 CatalogModule(包含产品)获取信息是否正确:
public Task<BasketDTO> Handle(GetBasketByBuyerIdCommand request, CancellationToken cancellationToken)
BasketDTO result;
var basket = m_basketRepo.GetById(request.BuyerId);
if (basket == null)
result = new BasketDTO()
BuyerId = request.BuyerId,
Items = new List<BasketItem>()
;
return Task.FromResult(result);
//Could be automapper, but not now currently //ignore
var products = new List<DTO.Product>();
foreach (var item in basket.Items)
var product = m_mediator.Send(new GetProductByIdQuery(item.ProductId)).Result; //ignore the non-async. It's example code
products.Add(new DTO.Product()
Id = product.Id,
Price = product.Price,
Title = product.Title
);
result = new BasketDTO()
BuyerId = basket.BuyerId,
Items = basket.Items
.Select(dl => new DTO.BasketItem()
ProductId = dl.ProductId,
Quantity = dl.Quantity,
Product = products
.Where(cl => cl.Id == dl.ProductId)
.FirstOrDefault()
).ToList()
;
return Task.FromResult(result);
大概是下面这行:
var product = await m_mediator.Send(new GetProductByIdQuery(item.ProductId));
这样做是否正确?我不是在谈论示例代码的其余部分,而是特别是关于调用调解器以获取产品并在“Catalog.Application”上具有项目“Basket.Application”的依赖关系
【问题讨论】:
【参考方案1】:说实话,只有您知道您的问题的答案。从外观上看,尽管命名为“GetBasketByBuyerIdCommand”,但您似乎只是在代码中运行查询。所以这意味着你只在研究 CQRS 的“Q”,从这个角度来看,你正在做的事情很好。
在我看来,您的问题的答案在于您的架构的其余部分,尤其是您目前试图用它实现的目标。如果您希望您的 BasketModule 和 CatalogModule 在未来某个地方完全独立,那么现在采取的这种类型的选择可能会在未来产生很大的影响。
例如,如果您稍后希望将这两个模块分成两个不同的微服务,您将不得不想出一种不同的方式来执行您描述的查询。如何处理这件事本身就是一个全新的话题。
【讨论】:
赞成只是因为您注意到我将其命名为 Command 并且应该是 Query。我仍在检查答案以评估我下一步应该做什么。感谢您的关注:)【参考方案2】:中介的主要作用是将表示层与应用程序服务分离,并使用中间件进行一些默认处理,而不是在有界上下文之间进行通信。
因此,我希望每个有界上下文都有一个中介 :)
要集成两个 BC,您可以将 GetProductByIdQuery 接口添加到 Basket 域(或应用程序)层,并在 Basket/infra 中实现。
GetProductByIdQuery 的实现(被视为辅助适配器)可能会调用 Catalog 的 BC 的中介,并转换结果以保留无处不在的语言。
恕我直言,如果您决定拆分其中的某些部分,即只有辅助适配器实现会改为进行一些进程间通信,这将保持整体清洁并降低迁移成本。
PS:我对干净的架构不是很熟悉,但我认为它是 Hexagonal 的一个更有特色的版本..
【讨论】:
以上是关于在 DDD 整体中跨服务/模块时,在我的处理程序中调用调解器是不是正确的主要内容,如果未能解决你的问题,请参考以下文章
我的 JBehave 验收测试应该针对 DDD 应用程序中的哪一层?