0008 - Server: Adopt CQRS

ID:ADR-0008

状态:

进行中

发表于:

2022-07-15

背景和问题陈述​

在 Bitwarden Server 中,我们目前使用 <<Entity>>Service 模式来作用于我们的实体。这些类最终成为了涉及实体的所有操作的垃圾场:导致臃肿耦合。有两个事实帮助我们确定了当前的设计:

  • 我们使用实体模式来表示存储在数据库中的数据,并使用 Dapper 或实体框架自动绑定这些实体类。

  • 我们使用基于构造函数的依赖注入来将依赖项传递给对象。

上述两个事实意味着,如果不接收所有必要的状态作为方法参数,我们的实体就无法运行,这与我们典型的 DI 模式背道而驰。

考虑的方案​

  • <<Entity>>Services -- 上面讨论过了。

  • 查询和命令 -- 从根本上来说,我们的问题是 <<Entity>>Service 名称完全封装了您可以对该实体执行的任何操作,并且排除了不同实体之间的任何代码重用。CQRS 模式根据对实体采取的操作创建类。这就自然而然地限制了类的范围,并在两个实体需要实现相同的命令行为时允许重复使用。https://docs.microsoft.com/en-us/azure/architecture/patterns/cqrs

  • 基于功能的小型服务 -- 这种设计会将 <<Entity>>Service 分解为 <<Feature>>Service,但最终会遇到同样的问题。随着功能的增加,该服务将变得臃肿,并与其他服务紧密耦合。

决策结果​

选择的方案:查询和命令

对于现任者来说,命令似乎是更好的决定。我们获得了代码重用并限制了类的范围。此外,我们还拥有一条迭代路径,可以通过队列工作实现完整的 CQRS 管道。

查询基本上已经通过存储库和/或服务完成,但需要进行一些明显的重组。

过渡计划​

随着时间的推移,我们将逐渐过渡到 CQRS 模式。如果开发人员正在进行使用或影响服务方法的更改,他们应该考虑是否可以将其提取到查询/命令中,并将其作为技术债务包含在他们的工作中。

当前的领域服务规模庞大且相互依赖,一次性将它们全部分解可能不太现实。重构「更深一层」并保留其他方法是可以接受的。这可能会导致新的查询/命令仍然在某种程度上与其他服务方法耦合。在过渡阶段,这种情况是可以接受的,但随着时间的推移,这些相互依赖关系应该被移除。

最后更新于