domain event 一定是过去式的event吗

在Domain Events – Salvation一文中, 作者udidahan并没有用domain event去解耦所谓的请求查询需求. 而是通过关联了一个Customer聚合根去解决了查询的问题.

这里我有一个关于domain event 的疑问, 所谓的domain event 是否应该一定是过去式的, 比如CustomerBecamePreferred, CustomerStatusChanged这种.
如果是这样的话, 那么那种需要请求repository或者是查询, 聚合根自己又无法做到, 必须依赖外部服务, 那么如何解耦聚合根和外部服务, 注意我这里讲的不是那种过去式的domain event. udidahan最终的解决方案只是引入了一个customer聚合根来解决这个问题, 那是否所有的情况都可以引用其他聚合根来解决呢? 后者domain event就不是对这种需求的解决方案.

@banq 你的"domain event 救世主"文章里并没有很明确的说明我这个疑问, 希望能得到你的解答, 谢谢!

2012-09-19 09:58 "@haojie77"的内容
在Domain Events – Salvation一文中, 作者udidahan并没有用domain event去解耦所谓的请求查询需求. 而是通过关联了一个Customer聚合根去解决了查询的问题. ...

CQRS 中, Command 简单的说是对Aggre的操作,然后Aggre产生事件,事件会自动保存到EventStore DB 中,而DDD CRS 的Repository仓储可以只有一个方法 findById,也可以有很多,我倾向于只有这一个方法。

而, CQRS 中 Q - query , 访问的数据不是 CRS DDD 的EventStore DB数据,而是独立出来的。

@brighthas 我觉得你都没正面回答我的问题啊,呵呵

2012-09-19 09:58 "@haojie77"的内容
作者udidahan并没有用domain event去解耦所谓的请求查询需求. 而是通过关联了一个Customer聚合根去解决了查询的问题 ...

如果我没有理解错的话,这应该是一种CQRS架构,也就是Domain Events只是对修改等写入命令有效,而如果是读取查询,可以直接委托一个聚合根去操作仓储。

对于修改写入命令,有命令发生就有事件发生,如上面brighthas所说。

我对你说的过去式Event可能还不是很理解,Event应该是真正发生的,如果是对过去Event感兴趣,那么通过ES查询事件数据库即可了解。

"过去式Event" 我想表达的是domain event 的命名是不是总是过去式的,如CustomerBecamePreferredEvent, CustomerStatusChangedEvent, 有没有可能出现不是过去式命名的domainevent, 这里和是不是ES会有关系吗?
[该贴被haojie77于2012-09-19 11:01修改过]
[该贴被haojie77于2012-09-19 11:01修改过]

2012-09-19 10:57 "@haojie77"的内容
CustomerBecamePreferredEvent, CustomerStatusChangedEvent ...

如果是指命名,我跟喜欢用onEvent之类,而不是ed,事件是正在发生,响应的都是正在发生事件,如果使用ed,反而是一种状态命名,被某个事件搞过的意思。

那么还有一个疑问 这些OnEvent的响应对象可以是哪些? 领域内的其他聚合根, 服务, 或者是外部邮件服务之类的都可以吗?

这里的说法即领域事件是过去式的, 请参考.或者大家说的domain event都不是一个概念?
http://codebetter.com/gregyoung/2010/04/11/what-is-a-domain-event/

There has been much confusion of late over the definition of what a Domain Event is. I was writing some stuff that will go into both the course manual and the book and figured that it might be timely to put it up on the blog as well.

An event is something that has happened in the past.

All events should be represented as verbs in the past tense such as CustomerRelocated, CargoShipped, or InventoryLossageRecorded.

[该贴被haojie77于2012-09-19 11:34修改过]
[该贴被haojie77于2012-09-19 12:34修改过]

2012-09-19 11:28 "@haojie77"的内容
这里的说法即领域事件是过去式的, 请参考.或者大家说的domain event都不是一个概念 ...

gregyoung的这篇文章我没有看过,只是对它的CQRS架构有过研究,关于事件的定义,我是将其定义为一种交互行为,这种交互行为类似DCI中I,是角色在某个场景下发生的。

如果从这个角度理解,你前面的问题可以回答了,OnEvent相当于交互行为的被调用者,但是注意交互行为或者说事件是涉及两个对象以上,或者说两个聚合根以上,如果这种行为只是维护聚合根内部行为,称为对象内行为,是用来保证实体内部状态的一致性或数据完整性的。从行为内外这个角度,然后将事件定义为对外调用其他聚合根或外部服务 或组件。

我刚刚看完gregyoung这篇文章,他是为了说明Command和Event的区别,其实一般来讲UI发出的是Command,而事件是领域内部的,这比较容易区分。他所说的事件是为了追溯而记录的事件,当记录时,这个事件已经过去式,但是我不同意他认为领域响应Command产生的事件也是过去式了,有些为了记录而扭曲领域的概念。

问题就出在,他的意识中可能认为事件不是一个领域概念,而是一个架构概念,如果认识到事件不只是架构概念,领域专家也能理解事件的定义,发生在两个对象以上的交互称为事件,比如某地发生什么事件,表面上看只是某个地方一个对象,实际上还有“你”,因为你知晓了,表达出来了,实际上你接受了那个对象发生的行为,所以用语言表达发生事件了。

以上只是个人理解。请讨论。
[该贴被banq于2012-09-19 16:11修改过]

在greg的帖子后面有长篇和其他人关于domainevent的争论. 其中他有这么一段话 "In many cases you will actually end up with a pair of objects, the first a SOM style “Transaction Object” in the domain the second a “Domain Event” that the domain publishes to anyone subscribing to it. The second concept is a “Notification of an Occurence” not a modeling of the occurrence. I will make this point clearer in my original text. This goes to Nuno’s comment as well though I put up a comment on the DDD list. Its not that the Domain Event replaces the SOM transaction object, they are different things with different goals."
我对他的理解是 真正的DDD中的domainevent是统一语言的一部分, 就是为了起到通知发生了什么的作用. 这里引入了SOM, 我是觉得这个SOM transaction object 是banq您所指的"发生在两个对象以上的交互称为事件", 所以我一直困惑到底什么是DDD书中说的domainevent. 目前我更倾向于greg的看法, 他们是两个为了不同目的不同的概念.

2012-09-19 16:31 "@haojie77"的内容
domainevent是统一语言的一部分, 就是为了起到通知发生了什么的作用. 这里引入了SOM, 我是觉得这个SOM transaction object 是banq您所指的"发生在两个对象以上的交互称为事件 ...

其实我个人觉得这两个也许是一回事,这只要从是否涉及两个以上对象这个角度理解即可,Notification of an Occurence 这个通知当然是涉及到它和你。如果你不知晓,怎么知道它发生了事件呢。

我们常说,某地发生大事件了,好像只涉及那个地方,实际上这是一种广播式的通知,只要你知道发生大事件了,就是变成通知的接收者。

事件概念还是遵循现实生活中原本概念,这样才能统一领域和架构,架构无论多抽象多技术,它也是某个东西吧,需要交互吧,当然也有发生事件,那么它凭什么要发出事件呢?当然依据它反映的业务,这样做到死死的一对一,才会拷贝不走样。

我觉得这和系统的架构有关,比如实体保存的时候需要验证数据的正确性,这就是一个BeforeEnitySave事件,如果采用同步模式处理的话,domain event就发生在操作之前。

2012-10-02 09:34 "@gameboyLV"的内容
我觉得这和系统的架构有关,比如实体保存的时候需要验证数据的正确性,这就是一个BeforeEnitySave事件,如果采用同步模式处理的话,domain event就发生在操作之前。 ...

这样会不会造成事件太多了。

我认为每一个事件都包含三个子事件(事件处理前、事件处理、事件处理后),这三个事件是顺序执行的。
比如:当客户提款成功后发短信提醒,
事件:客户提款
事件处理前:判断是否有足够的余额
事件处理: 扣款
事件处理后:发短信提醒客户。


[该贴被liuchengr于2012-10-12 10:52修改过]

2012-09-19 10:18 "@banq"的内容
如果我没有理解错的话,这应该是一种CQRS架构,也就是Domain Events只是对修改等写入命令有效,而如果是读取查询,可以直接委托一个聚合根去操作仓储。

对于修改写入命令,有命令发生就有事件发生,如上面brighthas所说。
...

如果Domain Events只对修改、写入等命令有效的话,那么Domain Event就是只有一个触发动作,应该是没有返回值的。那么一些需要有返回值的命令,或者说根本就是查询命令的需求怎么处理?还是需要引入服务么?
[该贴被lswweb于2012-10-16 10:25修改过]

不需要,对于Query命令可使用同步模式,发出命令后等待命令处理程序处理,处理完毕后将处理结果保存在命令中,此时程序继续执行就能获得处理结果了

也可以使用嵌套命令,比如:
事件:客户提款(异步命令)
事件处理前:判断是否有足够的余额(同步命令)
事件处理: 扣款(同步命令)
事件处理后:发短信提醒客户。(异步命令)

用户点击界面提款按钮,触发异步命令(客户提款),命令处理程序接到请求后立即启动子命令同步模式(判断是否有足够的余额),处理完毕后再启动子命令同步模式(扣款),处理完毕后再启动子命令异步模式(发短信提醒客户)同时将提款结果写入命令(客户提款)。

2012-10-16 11:30 "@gameboyLV"的内容
事件:客户提款(异步命令)
事件处理前:判断是否有足够的余额(同步命令)
事件处理: 扣款(同步命令)
事件处理后:发短信提醒客户。(异步命令) ...

这种契约设计Design by Contact的嵌套事件很符合BDD模板:Given-When-Then,见这个讨论
[该贴被banq于2012-10-17 09:17修改过]