Domain driven design 不';DDD和CQRS/ES打破了DDD的持久性不可知性?

Domain driven design 不';DDD和CQRS/ES打破了DDD的持久性不可知性?,domain-driven-design,cqrs,event-sourcing,Domain Driven Design,Cqrs,Event Sourcing,DDD中的域模型应该是持久性不可知的 CQRS命令我为我的阅读模型中不想拥有的一切触发事件。(顺便说一下,将我的模型分为写入模型和至少一个读取模型) ES指示我为所有改变状态的事件触发事件,并且我的聚合根必须处理事件本身 这对我来说似乎不是很不可知论 那么,在这种持久性技术不会对域模型造成严重影响的情况下,DDD和CQRS/ES如何结合呢 读模型也在DDD域模型中吗?还是在它之外 CQRS/ES事件是否与DDD域事件相同 编辑: 我从答案中得出以下结论: 是的,对于ORM,域模型objecs的实

DDD中的域模型应该是持久性不可知的

CQRS命令我为我的阅读模型中不想拥有的一切触发事件。(顺便说一下,将我的模型分为写入模型和至少一个读取模型)

ES指示我为所有改变状态的事件触发事件,并且我的聚合根必须处理事件本身

这对我来说似乎不是很不可知论

那么,在这种持久性技术不会对域模型造成严重影响的情况下,DDD和CQRS/ES如何结合呢

读模型也在DDD域模型中吗?还是在它之外

CQRS/ES事件是否与DDD域事件相同

编辑:

我从答案中得出以下结论:

是的,对于ORM,域模型objecs的实现将不同于使用ES的实现。 这个问题是错误的。首先编写域模型对象,然后决定如何持久化(更多类似于=>ES的事件,更多类似于=>ORM的数据,…)


但我怀疑,如果您事先没有做出这个决定,您是否能够使用ES(不会对域对象进行大的添加/更改),并且在没有事先决定的情况下使用ORM会造成很大的痛苦。:-)

你问题中的许多前提都是非常二进制/黑白的。我不认为DDD、CQR或事件源有那么多规定性——有很多可能的解释和实现

也就是说,只有一个前提让我感到困扰(我的):

ES命令我为所有改变状态和状态的事件触发事件 我的聚合根必须处理事件本身

通常ARs会发出事件——它们不会处理它们

在任何情况下,CQR和ES都可以实现为完全不依赖持久性(通常是)。事件以流的形式存储,可以存储在关系数据库、NoSQL数据库、文件系统、内存等中。事件的存储通常在应用程序的边界实现(我认为这是基础设施),而域模型不知道它们的流是如何存储的

类似地,读取模型可以存储在任何可想象的存储介质中。您可以有10个不同的读取模型和投影,每个模型和投影存储在不同的数据库和不同的格式中。投影只处理/读取事件流,并且以其他方式与域完全解耦


它不会得到比这更多的持久性不可知论。

命令

归根结底,CQRS意味着你应该把读写分开

通常,命令到达系统并由某种函数处理,然后该函数返回由该命令产生的零、一或多个事件:

handle : cmd:Command -> Event list
现在您有了一个事件列表。你所要做的就是把它们坚持到某个地方。要执行此操作的函数可能如下所示:

persist : evt:Event -> unit
query : target:'a -> events:Event list -> Result
然而,这种持久化功能纯粹是基础设施问题。客户端通常只会看到一个函数,该函数将命令作为输入,并且不返回任何内容:

attempt : cmd:Command -> unit
其余的(
handle
,后跟
persist
)是异步处理的,因此客户端永远看不到这些函数

查询

给定事件列表,您可以重播它们,以便将它们聚合到所需的结果中。这样的函数基本上如下所示:

persist : evt:Event -> unit
query : target:'a -> events:Event list -> Result
给定事件列表和要查找的目标(例如ID),此函数可以将事件折叠为结果

坚持无知

这会迫使您使用特定类型的持久性吗

这些函数都不是根据任何特定的持久性技术定义的。您可以使用

  • 内存中列表
  • 演员
  • 活动商店
  • 档案
  • 斑点
  • 甚至是数据库
  • 等等
从概念上讲,它确实迫使您从事件的角度考虑持久性,但这与使用ORMs的方法没有什么不同,后者迫使您从实体和关系的角度考虑持久性


这里的要点是,很容易将CQRS+ES体系结构与大多数实现细节分离。这通常是不够的。

不确定这有多正统,但我拥有的一个当前事件源实体模型做了类似的事情,这可能说明了区别。(C#示例)


我认为您仍然可以通过使用卫星POCO将域与持久性机制分离。然后,您可以围绕该POCO实现特定的持久性机制,并让您的域将其用作快照/memento/state。

事件通常不特定于任何持久性介质。它们通常是POCO/DTO。事件源本身确实会影响聚合根类,但这不是持久性问题。读取模型通常不是域的一部分。它确实会影响ARs本身的实现——AR要么来自事件流,要么来自关系模型(或NoSQL存储等)。我想这就是他要问的。但依我看,这并不是一个持久性不可知论的问题。当然,事件的持久性可以通过几种方式实现。当我计划使用CQRS/ES时,这会影响我如何实现我的域模型对象,这让我很烦恼。如果不使用CQRS/ES,让我们说使用一些ORM,我将编写我的域模型对象,而不触发那么多事件,也没有任何机制来执行它们(或者让它们从外部执行)机制。因此,持久化机制的选择对域模型对象的实现有很大的影响。当然,如果您已经决定使用事件源,那么不用说,您将通过一个
var ev = new LoggedInEvent();
user.When(ev);

if(user.IsLoggedIn) . . . .