CRUD in DDD

看了这个贴 http://stackoverflow.com/questions/1883107/cqrs-and-crud-screens
Greg在后面说"I may not really care why a name is changing in my domain where I ship products to people and only need that data to print mailing labels. "

确实, DDD中一般没有Hard Delete, 还有一些操作对于Domain没有明确的含义, 这些操作明显不应该放在Domain中,也没必要统统封装成Command
如果这样就会有一些问题,
1, CRUD放在哪儿呢? 或者说在哪里调用Repo的CRUD操作, 在client, application or .... ?
2, Event Sourcing 还能实施么?

我的观点:如果你的系统简单得只剩余CRUD,要么不用DDD,因为DDD适合复杂软件;当然我们可以认为CRUD也是一种业务,那也没有问题。

2013-04-19 13:17 "@banq
"的内容
我的观点:如果你的系统简单得只剩余CRUD,要么不用DDD,因为DDD适合复杂软件;当然我们可以认为CRUD也是一种业务,那也没有问题。 ...

这里的CRUD非指这四种操作, 更多是指那写琐碎的, 不能体现UL, 但是有必不可少的操作, 比如需要物理删除一条记录, 或修改一个输错的字段.
正是因为业务逻辑复杂, 才会有此疑惑, 那些看起来无关紧要的部分如果放入业务逻辑, 可能反而占据了大量精力.

我的做法是 Aggre对象的方法会发出事件,由event handle监听到后进行创建/更改/删除

2013-04-21 09:06 "@brighthas
"的内容
我的做法是 Aggre对象的方法会发出事件,由event handle监听到后进行创建/更改/删除 ...

event应该是" 已发生的事 ", 如果domain用event来让别人去做CRUD, 那岂不是成为command了?

2013-04-21 21:41 "@2102
"的内容
event应该是" 已发生的事 ", 如果domain用event来让别人去做CRUD, 那岂不是成为command了?
...

事件在CQRS DDD中即时过去时也可以是进行时,这个已经讨论过了。

2013-04-21 22:44 "@brighthas
"的内容
事件在CQRS DDD中即时过去时也可以是进行时,这个已经讨论过了。 ...

谁讨论后确定这样的?

目前我在项目中的做法是 认为事件是过去时的。
为什么这样做?
1、记录 一个 【游戏战役对象】 过程已经发生的所有事情,一来可以回溯,二来后期可以对数据进行数据挖掘。
2、【游戏战役对象】是保存在内存中,而不是数据库。
3、其他模块或者系统,可以选择接受event,做出各种逻辑,比如CRUD,发邮件等等。

--------------------------------------------------------------------
至于 进行时和过去时的差别,在于是采用谁作为参考对象。我的理解如下:
我选择 内存为参考对象,一旦内存中的领域对象发生改变,就可以发出一个 过去时的事件。

事件一定是表示已经发生事情;如果一个对象想通过事件去通知另一个对象做事情,那意味着这件要做的事情还没发生。那就不能用事件,而应该用command。我请求你做做什么,我就发一个request给你,或者command给你,然后你处理就行;所以,聚合根内,发出来的事件一定是告诉别人我发生了什么,而不能是请帮我做什么这样的事件;请帮我做什么实际上已经带有目的性,也就是说它实际上已经知道了谁会去处理该事情。如果这种情况你也用事件,虽然从技术角度来说勉强解耦了,但从语义上来说并没有解耦;聚合根之间的通信应该总有由一个第三方的对象来协调,如event handler。

另外,事实才包含已发生、未发生、以及正在发生的事情;

下面是摘录的一些哲学描述:

1* 世界是一切发生的事情。
1.1世界是事实的总体,而不是事物的总体。
1.11世界为诸事实所规定,为它们即是全部事实所规定。
1.12因为事实的总体规定那发生的事情,也规定那所有未发生的事情。
1.13在逻辑空间中的诸事实就是世界。
1.2世界分解为诸事实。
1.21每项事情可以发生或者不发生,其余的一切则仍保持原样。

2 发生的事情,即事实,就是诸事态的存在。
2.01事态是对象(事物)的结合。
2.011事物的本质在于能够成为事态的组成部分。
2.012逻辑中没有偶然的东西;如果一个事物能够出现在一个事态中,那么该事态的可能性必定已经预含于该事物之中。
2.0121如果一个事物本身能够独立存在,那么后来的适合于它的状况看来就是一种偶然的事情。

这样吧,event继承于message,是过去时,command继承于message,是进行时

message(消息)既可以是进行时也可以是过去时

2013-04-22 12:36 "@gameboyLV
"的内容
message(消息)既可以是进行时也可以是过去时 ...

我比较同意这个观点,打个比喻,如果消息是信封,事件是信的内容,Command也可以作为信的内容。

作战时,通讯员跑到连长面前,敬礼,报告:司令部命令,连长拿过信封,拆开,打开信件,命令内容是:攻上X山头。

面向对象编程的关键目标

2013-04-22 13:45 "@banq
"的内容
我比较同意这个观点,打个比喻,如果消息是信封,事件是信的内容,Command也可以作为信的内容。 ...

2013-04-22 12:36 "@gameboyLV
"的内容
这样吧,event继承于message,是过去时,command继承于message,是进行时

message(消息)既可以是进行时也可以是过去时 ...

窃以为不妥, 命令和事件有本质的区别:
命令是必须执行的, 而事件是可处理也可忽略的.

对内使用command, 对外使用event, 这样才符合内聚的要求.
也就是说, 二者没有交集, 故不需要抽象类.

来自上级的信封, 连长知道里面必然是命令.
而来自内部(队长?)的信封, 里面必然是事件.(队长不会去命令连长 :) )

EventSourcing的时候只关心当前对象内部状态的恢复, 而不需要关心命令别人做了什么, 所以只有Event需要被持久化.

2013-04-22 15:36 "@2102
"的内容
窃以为不妥, 命令和事件有本质的区别:
命令是必须执行的, 而事件是可处理也可忽略的.

对内使用command, 对外使用event, 这样才符合内聚的要求.
也就是说, 二者没有交集, 故不需要抽象类.

来自上级的信封, 连长知道里面 ...

对的,你的回复很正确我觉得。

不要为command, event设计基类,他们本质上是不同的东西。
你讲出了重点,就是command是必须执行的,可以理解为一个request,而event发出来后,只是表示某个对象发生了什么,别人完全可以忽略该event;

2013-04-22 15:36 "@2102
"的内容
窃以为不妥, 命令和事件有本质的区别:
命令是必须执行的, 而事件是可处理也可忽略的. ...

窃不敢苟同,我们不应该陷入命令和事件区分的死胡同。

有时命令发出本身也是一种事件,比如司令部发令枪响了等等。

至于强调事件是已经发生的事情,还是正在发生的,这都是与当前场景比较奥而言的,如果从EventSourcing这个角度,实际上将事件看成是一种记录的实体,也就是状态的代名词;而如果从EDA角度看,事件驱动表示正在发生的,这点Javascript的事件驱动编程经验者感受相当强烈。
http://www.jdon.com/44943

banq的说法也有一定道理!

举个例子,
ChangeNoteTitleCommand这是一个命令表示“要修改Note的Title的一个请求”

但这个请求一旦发出来,实际上就是一种事实了,既然是事实,就能转化为事件,如:
ChangeNoteTitleRequested,表示“修改Note的Title的请求已经被发出了”

所以,从这个例子可以看出,其实command也是一种event。只是这种event带有一定的请求性目的,这种event的响应者只有一个人,即一个特定的command handler;而我们通常说的event因为都是过去式,表示发生了什么,所以不带有请求性,而只带有通知性。

banq讲话比较抽象,让很多人很容易误会,呵呵。而且我觉得banq有时在说一个问题时,往往引入很多其他概念,然一般人抓不到重点,呵呵。不知道banq自己感觉到没?呵呵



[该贴被tangxuehua于2013-04-22 18:03修改过]