(Golang)清洁架构 - 谁应该做编排?

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

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

GetHotelInfo 的逻辑是:

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

  2. 调用GetHotelPrice(hotel_id, dates…)

  3. 调用GetHotelReviews(hotel_id)

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

选项 1

http://img.mukewang.com/628b3a68000170b513950798.jpg

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

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

选项 2

http://img2.mukewang.com/628b3a740001071020330853.jpg

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

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

  • 创建将协调前 3 个用例的 GetHotelInfoUseCase。(它也可以是一个控制器,但这是一个不同的主题)

假设现在只GetHotelInfo向 Web 公开,但也许在将来,我也会公开一些内部请求。

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


阿晨1998
浏览 182回答 3
3回答

茅侃侃

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

白板的微信

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

桃花长相依

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

相关分类

Go