领域驱动设计概念和与 CQRS 的关系

Domain driven design concepts and relation with CQRS

我最近开始熟悉 DDD 概念和 CQRS,我意识到 CQRS 中最重要的概念之一是负载均衡、NServiceBus 等之外的 DDD,但我很好奇我们是否可以单独使用 DDD 概念而不使用它在 CQRS 复杂性中用于开发和创建我们的项目。 据我所知,这是一种通过将实现与不断发展的联系起来来满足复杂需求的软件开发方法 model.I 需要知道单独使用 DDD 或与 CQRS 一起使用的项目规模应该有多大。

简短的回答是:可以。

CQRS 作为一种架构风格出现在 DDD 之后。它基于 Command-Query Separation (CQS)

作为一种模式,CQRS 可用于优化您的应用程序。如果您需要同时从多个 聚合 向用户显示大量数据,您可能需要进行大量数据库查询才能获取这些数据。这可能会变得低效。以下是您可以选择的一些选项(当然不是完整列表):

  • 选项 1:妥协你 域模型 以满足该需求并使其更适合阅读。

  • 选项 2: 像 CQRS 那样将两者完全分开。保留一个很好的代表您的领域的写入模型,同时拥有一个代表您希望如何向用户显示数据的读取模型。

  • 选项 3 设计您的用户 Interface/Front 结束不要同时显示所有数据。例如,以电话中 UI 的工作方式为例。由于它们的屏幕较小,CPU 速度较慢,RAM 较少,而且最重要的是:电池一直没电,因此它们通常会显示一小部分数据,然后您可以导航以查看更多数据。一个接一个地提出请求,而不是提出一个巨大的请求并在一个屏幕上显示所有内容。您可以将其与具有丰富菜单的桌面应用程序进行对比,当您打开它们时会向您显示很多内容。

这确实引入了您可能不想管理的额外复杂性,因此您可以根据您的组织选择 13 选项(让人们以这种方式设计 UI 可能很棘手,因此您可以选择 1 作为折衷方案)。

根据我的经验,除非您开发的应用程序将处理来自大量用户的数据(比如 200 000 甚至可能没问题),否则您可以跳过 CQRS。如果您以后遇到这个问题,您可以随时重构它。拥有一个不错的 域模型 可以更轻松地在以后引入 CQRS。

如果你还没有读过DDD book,我强烈推荐它。

Here is a great article for CQRS。它讨论了大多数人如何认为您必须使用单独的数据库来使从写入端到读取端的传播异步。

两个模型有一个数据库并使传播同步是非常好的。如果您使用事务数据库以避免最终一致性,您甚至可以在同一事务中更新读取模型。这将降低复杂性,但如果您的写入端也有很重的负载,则可能会引入额外的延迟。如果是这种情况,您可以使用异步最终一致的解决方案并处理由此产生的后果。

进行一些初步分析,看看 CQRS 是否会带来任何价值。如果确实从它开始。如果没有,请从没有它开始。如果您是 DDD 和 CQRS 的新手,最好不要在同一个应用程序中同时使用它们,因为您可能会引入意想不到的复杂性并让自己陷入困境。从 DDD 开始,获得经验,然后您可以尝试 CQRS。

作为@expandable 回答的补充:

CQRS、聚合、事件溯源等只是工具。经验表明它们在 DDD 项目中运行良好。使用这些工具并不意味着你做 DDD。

DDD 是关于通过开发人员和领域专家之间的对话提炼出一种无处不在的语言。在这些讨论中,您会注意到某些词根据上下文具有不同的含义。

例如,您可以考虑在线零售商店(如亚马逊)的产品生命周期。在与领域专家讨论后,您可能会发现根据购买的生命周期,产品具有不同的含义。对于零售环境,产品是关于价格和描述的,而在运输环境中,重要的是目的地地址以及产品的尺寸和重量。

这是使用两种语言的线索,您可能必须为每种语言(零售和运输)创建有界上下文。有界上下文表示使用一种语言的领域区域。当语言中单词的含义开始发生变化时,就会出现上下文边界。

开发人员和领域专家讨论后确定的限界上下文需要与代码库保持一致。对于此示例,您可能会创建一个用于零售的包裹和另一个用于运输的包裹。有界上下文的实现通常是相互分离的。例如,每个限界上下文都有自己的产品 class 和不同的属性。

每个 bounded 都可以有自己的体系结构:CQRS、Event Sourcing、Hexagonal 等,具体取决于需要。但是,您应该注意您选择的体系结构与限界上下文的域保持一致。例如,如果您的域本身不是基于事件的,您可能不会使用事件溯源。

我认为在许多在线资源中将这些原则(DDD、CQRS、事件溯源)联系在一起,对 DDD 本身带来的弊大于利。你的问题就是一个很好的例子,很多人认为 DDD = CQRS + ES(有时 + 微服务)。

DDD在本质上与CQRS和ES无关,只是一种设计"framework",而CQRS和ES是实现模式。换句话说,当你戴上 DDD 帽子时,你根本不应该考虑 CQRS 或 ES,因为你是在设计软件,而不是实现它。

为什么 CQRS 非常适合 DDD 设计?答案是,它不是 :)。这是事件源系统的一个很好的实现模式,事实证明,当您按照 DDD 原则设计它时(主要是当您找到好的限界上下文和适当的聚合根时),您可以轻松地创建一个好的事件源系统。

所以连接点只是在CQRS和ES之间。 CQRS 术语的作者 Greg Young 创造了它作为对事件溯源架构模式的介绍。如果没有某种 CQRS,很难创建 ES 系统。但是根本不需要 DDD。当然,三者配合得很好。

关于您认为 DDD 是 CQRS 中的主要概念之一的想法,我认为您是错误的。

许多在线资源将 CQRS 解释为 CQS 类固醇,这完全是误导。 CQRS中的核心概念是segregation系统的readwrite部分,一分为二——完全分离的应用程序。 Write 部分不应该知道 read 部分,而 read 知道每个细节写入部分(包括任何private/hidden数据)。 DDD与它无关。正如我之前所说,CQRS 使 ES 受益于 DDD。

回答你关于体重秤的问题:视情况而定。更大的系统更有可能从 CQRS 中受益,因为会有更多的功能、更多的视图以及更多希望以不同方式查看系统的用户。我认为这更多取决于用户的数量和类型,而不是软件的规模。 CQRS 使您能够非常轻松地为同一数据创建不同的视图,这是大型软件将从中受益的主要因素。

关于DDD和项目规模。这里没有相关性。当您的软件是 CRUD 类型时,根本不要使用 DDD。领域设计适用于具有复杂领域的软件。

I am curious if we can use DDD concept alone without using it in CQRS complexity for developing and creating our project.

是的 - 这些想法的年表说明了这一点。

Addison-Wesley 于 2003 年 8 月出版了创造​​ "domain driven design" 的埃文斯书。

Greg Young 在 QCon SF 2007 上发表了 Scaling Domain Driven Design。这些想法在标签 DDDD ("distributed domain driven design") 下进行了讨论。 CQRS 标签出现于 2009 年。

您可以查看 2008 年首次发布的 cargo shipping example,以获取仅使用单个模型来支持命令和查询的域模型示例。