这个人摸到点门,不过还是说得太乱了.

举一个最简单的例子,一个变量x的值不断变化,第一行是值,第二行是时间
x: 1,2,4,5,10,11,13,15
t: 1,2,3,4, 5, 6, 7, 8

可以定义这样一些事件:
A: x增加
B: x倍增
C: x超过9

当系统刚刚进入到t=3的时刻时,事件A,B发生了,这个是用现在时的时态来说的,可以对这个事件进行响应.

而如果在t=8的时刻看这个系统,同样可以说,在t=3的时刻,事件A和B发生了,但这个是过去时态,是已经发生过的事情

事件同样可以经历一段时间,比如定义事件D:
D: x从2增加到10
这个事件D经历了t=2,3,4,5四个时刻

1 事件是状态的变化模式
它同样是一个事实,但这个事实不可能成为原子事实,而只可能被规则所推导出来.所以,往数据库中插入一个事件的做法不可取,能被插入的只能是事实.

2 事件有现在进行时态和过去完成时态
对事件不同看法的上下文就是当前的时刻

3 事件不一定是某个时刻发生的,而可能经历一段时间.

4 动作会改变世界的状态,比如插入或修改一条事实,也就是改变数据.所以,都会有一个事件对应于某个动作,但事件和动作的性质是不一样的.

我认为考虑事件时不需要考虑时间因素,更不用关心它是某个时刻还是某个时间段发生。

我们只要关心:当我们在关心一个事件时,它一定是正在发生或已经发生的某个动作,这个动作可以是某个时刻的,也可以是跨一段时间的。

对于持久化,我认为只要是事件,就能持久化。因为不管是已经发生的还是正在发生的事件,我们总能确切的知道该事件的所有上下文信息,所以我们能对这些信息进行持久化(当然我们也只会持久化那些我们关心的那些信息)。

事件不是一个客观的存在,而是都是由我们人类想象出来的,我们认为会发生哪些事件取决于我们看待问题的角度。比如领域专家只会从领域的角度想象事件,如订单已提交;而程序员会从对象的角度来思考事件,如订单已被创建。所以,要不要定义事件完全取决于我们是否关心那个时刻或那个时间段。像Event Sourcing这样的模式,因为我们要用事件来重建聚合根,所以我们必须记录引起该聚合根变化的每一次改动,我们会把聚合根的每一次的状态修改都定义为相应的事件,然后持久化这些事件信息,被持久化的事件信息就是你说的事实。实际上严格意义上来说,持久化事件只是持久化了一半的事实,完整的事实包括:事件+与该事件相关的所有运算逻辑;

所以,我经常看到大家说领域事件(Domain Event),但我发现每个人对领域事件的理解都不同,实际定义出来的形式更是大不相同。这里的原因是,每个人定义事件的时候思考问题的出发点不同,每个人都是站在他所关心的角度上去定义事件而已!没有谁能说只有我定义的事件才是正确的,符合领域的,别人定义的事件是错误的!
[该贴被tangxuehua于2013-02-02 21:57修改过]

“事件”是解决一个”界“与另外一个”界“之间通讯问题的,也就是说当一个”界“与另外一个”界“需要通讯时才会有定义”事件“的必要,而不是把一个”界“所有的状态变化都弄成事件。要知道,”定义事件“在设计上是需要开销的(复杂度)。


希望大家在引入"事件”的设计时一定要反问自己,“在这里定义事件有价值吗?”

从我的实践看来,系统与系统之间通信,一般都是通过API调用,而不是用事件。

单个系统内部,像CQRS+Event Sourcing这样的架构,事件用来完整记录每个聚合根从创建到销毁的整个生命周期内的所有状态变化,所以事件一定非常多。要是你问我定义这么多事件是否有必要,这个答案要看你是否认为CQRS+Event Sourcing这样的架构有好处,如果你认为这种架构符合你的当前应用的需要,用对了地方,那定义这么多事件就很有意义。从我个人来说,我觉得在CQRS+EventSourcing这样的架构中,定义事件很有意义,因为我可以利用事件做到命令和查询分离,用事件来作为一种通知手段,告诉查询端当前领域模型内有什么事情发生,而查询端都是异步的方式响应事件,这样做可以大幅提高应用的整体可伸缩性。另外一点定义出完整事件的意义是我们可以利用EventSourcing模式,即事件溯源,我们可以通过事件溯源重建聚合根的状态。这种机制在内存模式的DDD中非常有价值,看一下LMAX架构就知道其好处了。

如果没有用CQRS+EventSourcing这样的架构,那定义出事件是否有必要?我没看出有什么太大必要,如果你说想让领域模型保持纯净性,所以可以用事件来解耦,这的确是一种方法,但实际上这只是一个技术实现问题。banq一直说的用事件也可以实现类似DCI的效果,banq的思路是,聚合根假如要保存自己,那为了确保它处于主动地位,聚合根会自己触发一个PleaseSaveMe类似这种含义的事件,通知外界保存自己。我不能说这种做法错误,我想还有很多其他正确且自然的做法,比如在经典DDD中,在应用层的某个context对当前已经执行了业务逻辑的某个聚合根做保存操作。实际上,我觉得聚合根仅仅是生活在内存中的一个对象而已,它完全不知道保存为何物,所以不应该发出PleaseSaveMe这样意图的事件,它的职责应该只是做他力所能及的事情,即只能做它所具有的信息相关的业务逻辑。这就是GRASP九大模式中的首要模式:信息专家模式。

说了这么多,我觉得主要就是回答flyzb所说的定义出该事件是否有意义?我主要是从“是否有意义”,“是否可以定义(即是否是它的职责)”这两个角度来思考。
[该贴被tangxuehua于2013-02-03 11:11修改过]

2013-02-02 22:24 "@flyzb"的内容
“事件”是解决一个”界“与另外一个”界“之间通讯问题的 ...

是的,事件是一种交互行为,而不是能力行为,交互与能力区别是:电话铃响这个事件实际包含两种行为,交互行为是外界有请求事件;电话本身有铃响能力,这个能力被外界事件触发了。

普通的请求响应其实也包含了这两种行为,请求是一种事件行为,能否响应是一种能力行为。


[该贴被banq于2013-02-03 11:14修改过]

2013-02-03 11:06 "@tangxuehua"的内容
利用事件做到命令和查询分离 ...


“命令和查询分离”是有适用范围的,不是什么情况下都可以使用的。
如果这种分离是异步的,那么在“业务逻辑只是单一查询”的情况下是可用的。如果在“业务逻辑是先读后写(其中写依赖于读)”的情况下,是无法使用这种分离的。

而在我遇到的大多数企业级业务逻辑开发中,第二种占大多数。如果要提高性能和伸缩性,我考虑更多地是怎么提高缓存命中率来加快读的速度。

2013-02-03 13:12 "@flyzb"的内容
如果在“业务逻辑是先读后写(其中写依赖于读)”的情况下,是无法使用这种分离的。 ...

如果是这种逻辑,那这个业务逻辑不能依赖于读库,业务逻辑总是不能依赖读库,业务逻辑这一端也可以查询,只是查询的对象总是通过事件溯源得到,这样得到的查询结果一定是最新的。

2013-01-30 23:39 "@clonalman"的内容
我一直认为事件就是一个实体,就象聚合根是一个实体一样。
有持久化的需求 ...

是的,这只是一个角度,事件或动词本身可以被看成“名词”,名可名嘛,持久化事件名称以后,可以进行事件追溯;但是事件还有另外一个含义,就是其对周围外部实施的影响,如果说,名词是被动,动词是主动,最明显的影响是事件一出,状态必改。

ES和DE的区别