CQRS/ES 如何重新定义构建可扩展系统。
在过去的 15 年里,我一直在深入研究领域驱动设计 (DDD),每一步都在学习和改进。我一直很好奇,尤其是当你深入挖掘时,简单的客户请求会变得更加复杂。我特别感谢EventStorming这样的工具,它帮助揭示看似简单需求背后的真实流程和事件,不仅让我,而且让客户和领域专家都清楚一切。
大约 10 年前,我首次在业务应用程序中使用了命令查询职责分离 (CQRS) 和事件源 (ES)。这种方法让我大开眼界,尽管它确实带来了挑战。但是,对我来说,最大的改变之一是意识到 CQRS 如何自然地使数据单向流动。这种单向流动不仅仅是为了保持井然有序;它改变了我们构建、维护和扩展系统的方式。这意味着我们可以将更改数据的操作与读取数据的操作分开。这不仅消除了许多潜在的混乱;它还为我们提供了一种处理复杂系统的直接方法。
虽然我非常喜欢在项目中使用 CQRS/ES,但这并不是成功应用 DDD 的唯一方法。DDD 是一个拥有大量工具和方法的庞大领域,最好的工具和方法实际上取决于您正在从事的工作以及团队的技能水平。CQRS 非常适合我,尤其是在处理复杂系统时,将读写操作分开可以使一切更易于管理。每个项目都是独一无二的,在很多情况下,其他策略可能是更好的选择。
CQRS 的好处
但是什么是 CQRS?这是一个强大的概念。其核心是将写入数据(命令)和读取数据(查询)的任务分为两个不同的部分。这种分离旨在明确系统结构、界定职责并提高从系统读取数据的速度。
我注意到,由于读写存储的严格分离,CQRS 经常被视为一种性能优化策略。虽然提高性能确实是一个显著的优势,但它只是触及了好处的表面。
CQRS 提供的功能远不止这些。首先,这种方法为我们提供了一个干净、有条理的结构。这种组织结构延伸到领域关注的极佳垂直部分,这意味着我们可以专注于特定领域,而不会迷失在复杂的海洋中。
另一个巨大的优势是强制单向数据流动。这不仅仅是为了保持数据移动的整洁;它从根本上改变了我们设计和思考系统的方式。它确保我们的数据以可预测的模式移动,减少混乱和错误。
CQRS 还促使我们更多地关注行为而不仅仅是数据。这意味着我们在设计系统时会考虑现实世界的行为和后果,避免使用软件项目中常见的贫血领域模型。贫血领域模型就像没有肌肉的骨架——它可能拥有所有部分,但无法独立完成很多工作。CQRS 帮助我们避免这种情况,确保我们的模型具有丰富的行为和功能。
CQRS 中的关注点分离功能使我们能够轻松增强系统视图。由于读取模型是分开的,我们可以调整和改进它们,而无需触及应用程序的核心逻辑。这种灵活性对于不断发展的系统来说非常宝贵,可以满足新的需求或解决新的见解,而无需进行重大改革。
镜像数据库不是 CQRS
我看到一种趋势,即 CQRS 中的读写分离被解释为拥有两个具有相同数据模型的镜像数据库,并依靠复制进行同步。然而,这种方法可能错过了 CQRS 的真正意义。
反模式:镜像数据库不是 CQRS问题的核心在于,写入和读取使用相同的数据模型会导致耦合度过高。CQRS 的优势在于它允许独立性,允许写入端开发丰富的行为驱动模型,而读取端则针对查询进行优化。跨数据库镜像数据模型会将两端联系得太紧密,从而限制系统的灵活性以及两端根据需要进行演进的潜力。
此外,这种设置还存在将写入模型变成围绕数据库架构的薄逻辑层而不是健壮的域模型的风险。它使我们陷入以数据为中心的思维模式,业务逻辑并没有处于应有的位置 — 嵌入域本身。
重要的是要理解写入模型与读取模型有很大不同。否则,所有的灵活性和能力都会丧失。
使用 CQRS/ES 实现数据行为
对我来说,将 CQRS 与事件源相结合的一个重要好处是,它将焦点转移到行为上,而不仅仅是数据模型上,从设计上来说就是如此。这种观点至关重要,因为它使我们的开发工作与我们的软件旨在代表的现实世界流程和逻辑更加紧密地结合在一起。传统的开发实践往往过于强调数据的结构——如何存储、检索和修改数据。虽然这种方法很重要,但它也可能导致我们忽视生成和使用这些数据的实际行为和交互。相信我,我见过不止一次这种情况。当 CQRS 与 ES 结合使用时,会扭转这种关注点。它鼓励我们围绕推动变革的业务事件和行动来建模我们的系统,而不仅仅是这些变化影响的数据。
这意味着我们的代码以更具表现力的方式反映了业务逻辑。我们不是简单地在表中插入、更新或删除行,而是捕获有意义的业务事件,例如“下订单”、“用户创建”或“库存更新”。这使我们的模型更加丰富和有意义。它提高了我们随着时间的推移重新思考和改进系统的能力。
CQRS/ES:单向流,有意义的模型。
投影的力量
CQRS 模式最重要的方面之一是投影概念,它本质上是读取模型的基础。这种方法对我们在应用程序中处理数据的方式有着深远的影响,因为最重要的是,它使我们摆脱了与在写入端表示数据相关的限制。这种分离确保了重点仍然放在准确捕获行为和域事件上,而不会增加查询或显示数据的复杂性。
CQRS/ES 投影 - 以及单向数据流。读取端独立性提供了灵活性,可以根据各种需求定制数据投影。无论是构建数据以实现高效查询,还是针对特定视图进行优化,投影都可以根据您的需求进行设计。此功能旨在满足当今的需求,也可以轻松调整和扩展以满足未来的需求,而无需触及现有代码。
对于投影,无需修改现有结构或更改写入端的逻辑。相反,我们可以简单地创建一个新的、独立的模块,专门用于根据需要投影和分析数据。这种模块化和可扩展性是一个巨大的优势,使我们的系统能够有机地发展,而不会损害核心域逻辑的完整性。
CQRS/ES:从投影查看数据
结束语
CQRS 与事件源相结合,改变了我们思考和构建软件系统的方式。通过分离数据的写入和读取,我们获得了一个干净、有组织的结构,从而提高了性能和可扩展性。更重要的是,这种方法将我们的重点转移到行为和现实世界的行动上,确保我们的模型功能丰富,并与它们所代表的领域保持一致。投影还允许我们在不触及现有代码的情况下调整和扩展我们的系统,这突显了 CQRS/ES 的灵活性和稳健性。