event sourcing 不能被滥用

event sourcing 不能被滥用。我用single responsibility的例子来做个类比。
当一个类可能因为两个原因变化的时候,说明不符合单一职责原则。需要重构为两个类。
同理,如果应用中有两个方法调用,本质上是传递同一种消息,那么可以抽象出一个事件。
换种说法,只有当一个事件可能由两个以上的producer产生,或者由两个以上的consumer处理的时候,我们才认为有必要抽象出这个事件。

在物理学中,我们经常讲“场”的概念。电磁场,参照系,引力场等等。每个场有自己的规则。比如引力场中,地球和太阳的引力。不能认为太阳和地球之间存在一个“引力”的事件。
有一些方法调用,或者类之间的交互,实际上是它所在的“场”的规则。比如像转账的这样的操作,就是转账这个场景(context)的规则。目标账户,源账户,转账规则共同构成了转账场景。我们构建一个TransferMoneyContext,然后让context.run(),业务就完成了。TransferMoneyContext的run方法,应当懂得去找源账户,把钱按一定规则往目标账户去转。我狠狠的凝视着银行账户,只看到了规则,找不到事件的踪迹。

按照DCI的论文里的观点,他们认为数据结构是不容易变化的,业务方法和业务逻辑很容易变化。而好代码的标准就是,更好的隔离变化。注意,好代码的标准不是要解耦合。
DCI认为SOLID的核心是“开闭原则“,传统的OO原则使用继承,基于”李氏可替代原则“,”单一职责“,”借口隔离‘,“依赖反转”来达到“开闭原则”。
DCI批评了这种方法,提出了使用Data动态结合Role,来实现“开闭原则”。
因此,我不希望通过事件过分的解耦合。

我理解的好代码是,用最少的工作,最低的成本实现目前的需求。同时当需求变化时,需要的改动工作最少。我想这也是DDD,DCI,敏捷开发共同的目标。

作为一个对于代码量比对物价更敏感的程序员,减轻手腕的酸痛是我最关心的。任何增加手腕负担的设计都不是好设计。

写得很好,事件过于细节琐碎,难以管理,如果将事件置于场(Context)管理下可能还值得探索的,我把下面图又贴出来:

关于事件和场景的关系,其中场景我比较赞同楼主的定义,引力是一种引力场,而不是引力事件,但是是否会有这样情况:地球运动是否可看成是引力场下一个事件呢?

以转账为例,TransferMoneyContext的run方法,应当懂得去找源账户,把钱按一定规则往目标账户去转,我一开始也没看出事件,但是考虑到我是不是因为角度不同导致没有看见,结果我后来也就是现在又发现了,因为Run方法本身执行可能意味着隐式一个事件,Run需要用户在界面发出转账命令,触发转账事件,也就是TransferMoneyContext.run被执行。

我也思考了,为什么我之前也没看出呢?可能因为我只看到了规则这个名词,还有更多静态的代码,而没有从这些代码的运行行为这个角度再去考虑,就象我们设计一个船模,交付运行了却沉了,因为没有考虑其运行时的参数。

事件其实代表一种面向函数FP的思考方式,而DCI更是强调一种动态行为的思考方式,两者既然都是强调同一个方面是不是会排斥的?我觉得不是,比如可以认为DCI的“I”交互是需要事件触发的,它们可能是表达同一个概念,也就是同一条船上的,所以,事件并没有给DCI添乱,反而更加奠定了DCI铁三角的架构,这样我们不至于经常看到D数据和C场景,而忽视I,也就是事件。

对象的“方法”要成为真正“行为”,变得有作用,是需要“事件”给予能量的;而“事件”的能量来自用户的“命令”Command。

相关帖:魔法袋与豆豆
[该贴被banq于2012-11-27 09:34修改过]

事件的目的在于可异步,通俗的话就是“各顾各”。转账“各顾各”表现在哪里呢?就在A转B,C转D(理解通透B转C也行),虽然场景某些知识跟事件很像,但场景压根不是考虑这个,某些情况下场景只是事件的元素。

好代码,好设计因人而异,对于没有量化的判断,争论起来只会面红耳热。