(Golang) 干净的架构 - 谁应该进行编排?

我试图了解以下两个选项中哪一个是正确的方法以及原因。

假设我们有GetHotelInfo(hotel_id)从 Web 到控制器调用的 API。

GetHotelInfo的逻辑是:

  1. 调用GetHotelPropertyData()(位置、设施……)

  2. 调用GetHotelPrice(hotel_id, dates…)

  3. 调用GetHotelReviews(hotel_id)

一旦所有结果返回,处理并合并数据并返回 1 个包含酒店所有相关数据的对象。

选项 1

https://img2.mukewang.com/64e302110001302206350377.jpg

  • 创建 3 个不同的存储库(HotelPropertyRepo、HotelPriceRepo、HotelReviewsRepo)

  • 创建将使用这 3 个存储库并返回最终结果的 GetHotelInfo 用例。

选项 2

https://img2.mukewang.com/64e3021e0001130d06410285.jpg

  • 创建 3 个不同的存储库(HotelPropertyRepo、HotelPriceRepo、HotelReviewsRepo)

  • 创建 3 个不同的用例(GetHotelPropertyDataUseCase、GetHotelPriceUseCase、GetHotelReviewsUseCase)

  • 创建 GetHotelInfoUseCase 来编排前 3 个用例。(它也可以是控制器,但这是另一个主题)

假设现在仅GetHotelInfo暴露在 Web 上,但也许将来我也会暴露一些内部请求。

如果 GetHotelInfo 的实际逻辑不是 3 个端点的组合而是 10 个端点的组合,答案会有所不同吗?


Smart猫小萌
浏览 100回答 3
3回答

PIPIONE

您可以在Manato KurodaGet()的“ Clean Architecture with GO ”中看到类似的方法(称为)马纳托指出:遵循非循环依赖原则(ADP),依赖关系只在循环中指向内,而不指向外,不存在循环。Controller 和 Presenter 依赖于用例输入端口和输出端口,它们被定义为接口,而不是特定的逻辑(细节)。由于依赖倒置原则(DIP),这是可能的(不知道外层的细节)。这就是为什么在示例存储库中manakuro/golang-clean-architecture,Manato 为用例层创建了三个目录:存储库,主持人:负责输出端口interactor:负责Input Port,拥有一组具体应用业务规则的方法,依赖于repository和presenter接口。您可以使用该示例来调整您的案例,GetHotelInfo首先在文件中声明hotel_interactor.go,并根据 中声明的特定业务方法hotel_repository以及 中定义的响应hotel_presenter

MYYA

预期交互器(用例类)调用其他交互器。因此,这两种方法都遵循清洁架构原则。但是,“也许在未来”这句话违背了良好的设计和架构实践。我们可以而且应该以最抽象的方式思考,以便我们可以支持重用。但始终保持事情简单并避免不必要的复杂性。如果 GetHotelInfo 的实际逻辑不是 3 个端点的组合而是 10 个端点的组合,答案会有所不同吗?不,会是一样的。然而,当您设计 API 时,如果您需要数十个端点的组合,您应该开始考虑放置 GraphQL 层,而不是增加项目的复杂性。

江户川乱折腾

清洁并不是一个明确定义的术语。相反,您应该致力于最大限度地减少变更(添加或删除服务)的影响。我所说的“影响”不仅指成本和时间因素,还指引入回归的风险(破坏系统中您不应该接触的不同部分)。为了最大限度地减少“变化的影响”,您可以将它们拆分为单独的服务/有界上下文,并仅允许通过事件进行交互。“控制器”将引发一个事件(在共享总线上),例如“酒店信息请求”,并且每个单独的服务(属性、价格和评论)将独立且异步地响应(可能在同一总线上),从而使控制器汇总结果并将其返回给客户端,这可以在一段时间后完成。如果您对结果聚合器进行适当的编码,则可以完全独立于其他功能添加新“功能”或删除现有功能。为了改进这一点,您可以将每个上下文的读取和写入功能分离到其自己的上下文中,每个上下文都响应适当的事件。这将允许您独立于读取功能来优化和扩展写入功能。我们称之为 CQRS。
打开App,查看更多内容
随时随地看视频慕课网APP