开源中国

我们不支持 IE 10 及以下版本浏览器

It appears you’re using an unsupported browser

为了获得更好的浏览体验,我们强烈建议您使用较新版本的 Chrome、 Firefox、 Safari 等,或者升级到最新版本的IE浏览器。 如果您使用的是 IE 11 或以上版本,请关闭“兼容性视图”。
CQRS-简单的架构设计 - 技术翻译 - 开源中国社区

CQRS-简单的架构设计 【已翻译100%】

标签: <无>
不死的达芬奇 推荐于 2周前 (共 17 段, 翻译完成于 08-08) 评论 4
收藏  
31
推荐标签: 待读

有人说:“CQRS很难!”

是吗? 好吧,我也曾这样认为! 但,当我开始使用 CQRS 编写我的第一个软件时,它很快就不攻自破。更为重要的是,我认为从长远来看,以这种方式维护软件更加容易。

我开始思考:为何人们在一开始时认为它是多么困难难和复杂? 我有一个理论:它包含规则! 进入拥有规则的世界总是不舒服的,我们需要适应这些规则。在这篇文章中,我想证明在这种情况下,这些规则是非常易于理解的。

Tocy
 翻译得不错哦!

在通往 CQRS 的路上…

从根本上来说,我们可以将 CQRS 视为对软件架构命令查询分离规则的实现。在使用此方法的工作中,我注意到在最简单的 CQS 实现与真正成熟的 CQRS 之间有几个步骤。我想那些步骤可以顺利地引入我之前已经提到的规则。

虽然第一步没有实现我对 CQRS 的定义(但是有时候这么称呼的),但是他们还可以为你的软件引入一些真正的价值。每个步骤都引入一些有趣的想法,可以有助于构建或清理你的代码库/架构。

通常,我们的旅程从这里开始:

琪花亿草
 翻译得不错哦!

我们可能都知道,这是一个典型的 N-层架构。如果我们想在这添加一些 CQS,我们可以“简单地”将业务逻辑层分离为命令和查询:

如果你还在使用老式代码库,这可能是最难的一步,就像从意大利面式代码中阅读分离出副作用一样不简单。同时这个步骤可能也是最有好处的一个;它会给你一个副作用执行的位置的概述。

等一下!你正在讨论 CQS,CQRS ,但是你还没有定义到底什么是命令或查询!

没错。我们开始定义它们吧!在这里,我会给你我个人、直观的对命令和查询的定义。它并不全面,而且在实现之前必须加以深化。

琪花亿草
 翻译得不错哦!

命令——首先,触发命令是唯一改变系统状态的方法。命令负责引起所有的对系统的改变。如果没有命令,系统状态保持不变!命令不应该返回任何值。我使用两个类来实现它:Command 和 CommandHandler 。Command 只是一个普通的对象,CommandHandler 将它用于表示某些操作的输入值(参数)。我认为命令是简单地调用领域模型中的特定操作(不一定是每个命令都有的操作)。

查询——同样的,查询是一个读操作。它读取系统的状态,过滤,聚总,以及转换数据,并将其转化为最有用的格式。它可以执行多次,而且不会影响系统的状态。我之前是使用一个有一些 Execute(…) 函数的类来实现它,但是现在我认为分离成 Query 和 QueryHandler/QueryExecutor 可能会更有用。

琪花亿草
 翻译得不错哦!

回到示意图,我需要澄清一些事情;我已经隐秘地做了一个补充修改,模型改为领域模型。由于我认为模型是一组数据容器,而领域模型包括了业务规则中本质复杂性。因为我们对这里的体系架构感兴趣,这个修改不会直接影响我们的进一步考虑。但是值得一提的是,尽管命令负责改变系统的状态,本质复杂性应该放到领域模型。

好的,现在我们可以添加新的命令或者编写新的查询。短时间内,很明显,适用于写的领域模型并不一定适合读。从某种特殊模型中更容易读取数据,这并不是一个重大的发现:

琪花亿草
 翻译得不错哦!

我们可以引入分离模型,由 ORM 映射并构建查询,但是在某些情况下,特别是当 ORM 引入开销时,它将对简化结构有所帮助。

我认为这个特殊的改变应当被好好地考虑!

现在的问题是我们仍然有仅在逻辑层级上分离的读和写模型,因为他们共享公共数据库。这就意味着我们已经分离了读模型,但最有可能是被一些 DB 视图给虚拟化了,物化视图的情况下更好。如果我们的系统没有性能问题,并且我们记住在写模型改变的时候更新查询,那这个方案是可行的。

kevinlinkai
 翻译得不错哦!

下一步是引入完全分离的数据模型:

在我看来,这是第一个符合 Greg Young 提出的原始想法的模型,现在我们称它为 CQRS 。但是它仍然有问题!我之后再写。

kevinlinkai
 翻译得不错哦!

CQRS != 事件溯源

事件溯源是与 CQRS 一起提出的一个概念,通常被标识为 CQRS 的一部分。ES(Event Sourcing)的概念很简单:我们的领域生成的事件表示系统中的每一个更改。如果我们从系统开始记录每一个事件,而且从最初状态开始重现,我们会得到系统的当前状态。它与银行账户的事务相似;我们可以从空账户开始,重现每一个单独的事务,然后(有希望地)得到当前的余款。因此,如果我们已经存储了所有的事件,我们能得到系统的当前状态。

虽然 ES 是存储系统的状态的一种很好的方法,但是 CQRS 并不一定需要它。对于 CQRS ,领域模型实际上如何存储并不重要,而且这只是一个选项。

琪花亿草
 翻译得不错哦!

读模型和写模型

当我们阅读 CQRS 时,分离模型的概念似乎非常清晰和直接,但在实现过程中似乎并不清楚。写模型的责任是什么?我是否应该将所有数据放入我的读取模型中?嗯,这得看情况!

写模型

我喜欢把我的写作模型看作是系统的核心。这是我的领域模型,它做业务决策,它很重要。它做出业务决策的事实在这里是至关重要的,因为它定义了这个模型的主要职责:它代表系统的真实状态,可以用来做出有价值的决策的状态。这种模式是唯一的真理来源。

如果你想了解更多关于设计领域模型的知识,我推荐你阅读领域驱动设计技术哲学。

ZICK_ZEON
 翻译得不错哦!

读模型

在我第一次尝试 CQRS 时,我使用了 WRITE 模型来构建查询……它是 OK 的(或者至少是有效的)。过了一段时间,我们到达了项目中需要花费大量时间进行查询的地方。为什么?因为我们是程序员,优化是我们的第二天性。我们将模型设计为规范化,因此我们的读取端受到连接的影响。我们被迫预先计算一些报告的数据以保持快速。这很有趣,因为实际上我们引入了缓存。在我看来,这是读取模型的最佳定义:它是一个合法的缓存。由于我们必须发布项目,而非功能性的需求没有得到满足,因此,缓存是通过设计来实现的。

标签读取模型可以建议它存储在一个数据库中,仅此而已。实际上读取模型可能非常复杂,你可以使用图形数据库来存储社会连接,使用 RDBMS 来存储财务数据。这是一个多语言持久性很自然的地方。

ZICK_ZEON
 翻译得不错哦!
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们
评论(4)
Ctrl/CMD+Enter

每一篇讲 CQRS 的文章都会先讲清楚 WHAT is Command and WHAT is Query?然后总是会想起大学学习 Windows MVC 编程的时候那些 command 和 call 之类的控件的区别。。。
看来很多CQRS,从来没有看到过物理W/R分离时的数据一致性好方案,ES也没有看到具体的干活,谁tms说CORS+ES+RW分离实现容易,我保证不打死你
给个直接的落地方案:1.增删改业务系统和查询系统分别布署。2.两个系统共用库表。3业务系统用的业务实体只含业务必须字段,查询系统用的实体是在业务实体的基础上增加了更多冗余字段,然后映射到和业务实体同一张表。4.命令引发的增删改service操作只会操作业务字段变更,查询系统收到异步消息或定时扫描去按各种查询场景需要,补足冗余字段甚至建立新的查询实体。好处:业务系统不再考虑冗余字段的维护,最小化操作,简化维护和扩展的业务复杂度。查询需求对业务代码无侵入性,不必在创建或修改逻辑同时附带多余操作,异步补全查询所需的字段和实体的值,有点像在维护物化视图。通来查询实体来跨模块或跨微服务,保护了业务实体的有效边界。麻烦:多维护一套service用于处理查询需求。异步会导致的轻微数据不同步,不过因为是同库同表,所以只是部分字段不同步,可以自行用各种手段弥补。
看上去好麻烦, 和微服务比有啥优势??,
顶部