我正在为一项新服务创建高级设计。服务的复杂性需要使用 DDD(我认为)。所以我做了常规的事情并创建了域服务、聚合、存储库等。我的存储库封装了数据源。所以一个查询可以在缓存中查找一个对象,在数据库中查找失败,失败创建一个REST
调用外部服务以获取所需信息。这是相当标准的。现在我的同事提出的论点是,以这种方式抽象数据源是危险的,因为使用存储库的开发人员将不知道执行 api 所需的时间,因此无法计算任何 api 的执行时间。上面写着。如果他知道他的调用会导致调用,他可能会想要以不同的方式设置他的组件的行为REST
。他们建议我移动REST
在存储库之外调用,甚至可能是缓存策略。我可以理解他们的观点,但存储库模式背后的整个想法正是隐藏此类信息,而不是让每个组件都处理缓存策略和数据访问。我的问题是,是否有解决这个问题的模式或模型?
3 回答
他们建议我将 REST 调用移到存储库之外
那么您将没有存储库。存储库意味着我们不知道持久性细节,并不是说我们不知道存在持久性。每次我们使用存储库时,无论其实现如何(从内存列表到 REST 调用),我们都期望“缓慢”,因为众所周知,持久性通常是瓶颈。
将使用某个存储库实现(如基于 REST)的人会知道它将处理延迟和瞬态错误。只有IRepository
依赖的服务仍然知道它处理持久性。
关于缓存策略,您可以有一些服务级别(更通用)缓存和存储库级别(特定于持久性)缓存。这些可能应该是实现细节。
现在我的同事提出的论点是,以这种方式抽象数据源是危险的,因为使用存储库的开发人员将不知道执行 api 所需的时间,因此无法计算任何 api 的执行时间。上面写着。如果他知道他的调用会导致 REST 调用,他可能会想要以不同的方式设置他的组件的行为。
这是浪费时间试图使你的生活复杂化。抽象的全部意义在于隐藏肮脏的细节。他们的建议基本上是:让用户了解一些实现细节,以便用户可以将其代码与其耦合。
关键是,开发人员应该知道他们正在使用的 api。如果一个组件正在使用外部服务(db、web 服务),这应该是已知的。一旦你知道有数据要获取,你就知道你必须等待它。
如果你走 DDD 路线,那么你就有了有界上下文 (BC)。使模型依赖于另一个 BC 是一个非常糟糕的主意。每个 BC 都应该发布领域事件,每个感兴趣的 BC 应该订阅并基于这些事件保留自己的模型。这意味着查询将是“本地的”,但您仍然会遇到数据库。
存储库模式旨在减少与持久层的耦合。在我看来,我不会冒险让存储库如此充满责任感。
您可以使用反腐败层来应对外部服务的变化,并使用代理来隐藏与缓存相关的问题。
然后在应用层我将编写回退策略。
我认为这完全取决于您认为获取/回退策略属于何处,在服务层或基础设施层(后者对我来说听起来更合法)。
它也可以是两者的混合——服务被传递一系列有序的存储库,以便在发生故障时一个接一个地使用。一系列 Repos 的构建可以放在 Infrastructure 层或其他地方。一个地方的后备逻辑,另一个地方的后备配置。
作为旁注,异步似乎是一种向用户发出信号可能很慢并且如果您等待它会阻塞的好方法。比将所有内容隐藏在一个普通的、不起眼的存储库名称后面,也比在你的类型 IMO 中添加一些具有威胁性的“这可能很慢”前缀更好。