2012-08-31 18:34 "@clonalman"的内容
领域上“需要记录船经过的港口”与技术上Event Sourcing,刚好重叠而已
如果领域需求根本不许要记录船经过的港口,ShippingEvent根本就没有必要 ...

很好,下面我谈一下从个体推演到普遍的论证过程,你看逻辑是否严谨:

1.DDD强调统一语言,所谓统一语言,也就是统一需求人员和技术人员的用语,不能各用一套自己的定义,这样就会鸡同鸭讲,需求和技术脱节,导致软件实现错误需求,或者无法跟随需求变化而变化,这类似一种电视游戏:拷贝不走样,几个人通过动作模仿传递一个成语,结果到最后一个人得出的结论完全相反,这是反映信息在传播中的失真。所以,建议统一语言,能够让大家用同一种描述方式来谈论问题。

2.什么是统一语言?
统一语言有不同流派,比如最早的SOA的服务概念也是一种统一语言,所以,我们做系统项目时,总是有服务类,而在现实中也存在各种从服务角度描述的需求,比如加油站加油服务等等。

服务这个统一语言,需求人员能够理解;技术人员也能够理解,不就是一个无状态的功能类嘛。

同样,EventSource提出事件和服务一样,也是一种统一语言,虽然案例中是以货运为案例,但是只要有服务的地方就有事件,为什么这么推理呢?

从本站以前一直讨论的四色原型也就是彩色UML,它认为需求世界分为四种颜色,就像我们认为颜色是由三原色组成一样,这四色有角色 活动 和事情和描述。

其中活动这一分类可以对应到服务或者事件,活动发生,也就是事件发生,角色可以认为和场景Context有关。

好,下面再看看其他流派,比如BDD行为驱动开发,其Given When Then模板实际也是一种统一语言,它认为任何用例需求可以用这种模板去分解。所以,统一语言实际是一种方法论。

再看看DCI,它认为领域模型总是在一定场景下扮演角色,实施一定的行为(或发生什么事情),普通平民(领域模型)充当恐怖分子角色,实施爆炸事件。

从列举法来看,由ES/彩色UML或DCI等等都不约而同谈到活动事件,我由此统一总结为:场景(角色) 事件和状态为一个万能模板,是一种统一语言。

3.统一语言是横跨业务领域和技术架构
由于业务领域和技术架构是天然两个世界,所以,从技术架构内部无论寻找什么超酷的技术都无法和业务领域无缝结合,反之,我们也不可只从某个具体业务领域内部找一个和技术架构无缝衔接。

只有寻找一种凌驾于业务领域和技术架构的,类似神仙姐姐的统一语言,通过这个神仙桥梁,搭建起业务领域和技术架构无缝结合。

那么是否有必要使用CQRS和ES呢?那看你们团队善于掌握哪种统一语言,如果都熟悉服务,那么SOA也许合适,但是它也有缺陷,忽视领域模型的地位了。

如果熟悉事件,当然ES和CQRS是选择,而且事件是围绕DDD实体的,这和DDD比较接近。

如果熟悉场景角色,DCI是一种选择,这也是围绕DDD实体的。

当然,我个人是推崇结合DDD+DCI+ES/CQRS,包括Jdonfamework也是这样,因为DCI和ES虽然正交,但是不矛盾,DDD的实体充当DCI的数据模型,DCI的Context是角色扮演场所,角色实施的行为是事件,事件由角色在一定场景下发出。

以上只是我个人见解,批评指正。

[该贴被banq于2012-09-01 09:37修改过]

不知道是不是我对DDD理解有差异,当用DDD进行建模的时候,我一判断的标准是这个模型是否准确的描述现实,因为模式只要能反映实际,并把这个信息传递给技术即可,既于在技术上如何实现,使用哪一种技术来实现都不应该是DDD的考虑的范围。

DDD的模型是一个需求与技术妥协的结果,我担心会背离实际业务模型,DDD提供了一个统一描述业务的模型,我不认为少了一个角色(技术上也许很难实现),但不会因此而影响到技术人员对业务的理解了

统一语言应该是统一“需求”、“技术”或其他人在描述业务上的差异,
判断统一语言好坏标准应该是有没有能力描述并真实反映各种各样的复杂业务,应该具有一定的强制性;
(上述标准DDD、DCI、SOA那个更有优势?)

我们可能对"统一语言"的理解并不完全"统一",也是所有理解差异的思想根源。
[该贴被clonalman于2012-09-01 12:22修改过]

2012-09-01 10:49 "@clonalman"的内容
我们可能对"统一语言"的理解并不完全"统一",也是所有理解差异的思想根源。 ...

可能是吧,求同存异吧。呵呵。

打扰两位了。

领域对象的动作会产生事件,请问
1.这个“产生”,怎么体现?
2.“事件”是“被”产生的,那么如何来“复原”这个“事实”呢?


目前个人观点:

1. “产生”么, 直接点, 由领域对象的行为来返回“事件”,向外宣称该动作的“结果”--》既“事件”。

2. “复原”,这个就不好办了,得看领域边界外的对象如何识别,能够认知哪种“事件”--被“复原”后的事件。

补充:“复原事件(事实)”,我理解为 针对某“某事件”的描述。毕竟 “动作”产生“事件”,“事件”是结果,“动作”已经over了。


如有打扰,抱歉了.

事件不一定返回,像上面"船运跟踪服务"一样,可支持化作为一个记录供查询之用即可,如果业务复杂,有其他模块也关心这个事件,可以订阅发布(比如,到港之前需要先检查通关手续是否完成).....
从技术角度,记录是可以还原的,但要把所有相关连的对象都返原(如果有财务方面过帐就更麻烦了),领域的角度,不是所有的动作都能"买到后悔要的",大部分情况都不能...

2012-09-02 08:15 "@clonalman"的内容
事件不一定返回,像上面"船运跟踪服务"一样,可支持化作为一个记录供查询之用即可,如果业务复杂,有其他模块也关心这个事件,可以订阅发布(比如,到港之前需要先检查通关手续是否完成)..... ...


以下是个人观点:

“事件”可以不返回,可以借助“Bounded Context或Repository”来“命令”基层做后续任务,例如“持久化”。

But,“其他模块也关心这个事件,可以订阅发布”,这个要“落地”,怎么办,让领域对象去通知每个观察者或者注入listener来负责通知的任务么?! 个人感觉上已经把领域对象弄脏了。
当“被观察”的“动作”比较少的时候,还可以忍受。多了怎么办?

还是考虑“事件”的返回,让领域对象大声的喊出“动作后的结果”--“事件”(必要的时候,当然也可以不返回)。

领域对象喊出“事件”,应该还是比较自然的吧。

我这里是把“事件”放在 DCI 中 C 里,最终有 C 来向边界外发出event,至于谁感兴趣该事件,可以去监听(由领域服务来提供接入点)。


希望多指教!


目前一直在想怎么才能让DCI,DDD,Event 更自然的落地。
不希望用标签和注入(尤其是对Domain的注入,基层的注入是可以的)

在jdon潜水很长时间,学习到不少知识,尤其是思想方面,非常感激。

thx

你觉得发“事件”放在实体领域上很难理解,有这个可能就是,
这个方法根本就不应该属于实体,你可以选择把他放到“服务”上去

你可再看看前面的帖子。。。。

2012-09-02 12:40 "@clonalman"的内容
你觉得发“事件”放在实体领域上很难理解,有这个可能就是,
这个方法根本就不应该属于实体,你可以选择把他放到“服务”上去 ...


这个“发”,怎么理解呢?
由领域对象来驱动(可借助Repository)基层么?!

目前我的想法是:

Context内部{
Domain(可以某个角色)-(执行)->“动作”-(产生)->“事件”
}
其中Context“收集events”并最后向外发出“events”。

如何“收集”是个麻烦点,曾经考虑 代理,监听,动态修改类,但都感觉不太好,不够自然。

目前能想到的就是 return 出“事件”。

请多多指教, 可能最近思维卡壳了。

你的困惑,我之前也困惑过,不要去关心技术实现,
Repostory,只是告诉你对象从哪里来,到哪里去。

Bounded Context 和 Repository 都有一作用范围,
Bounded Context 可能会附带环境来得的一些属性,Repository没有任何属性。

不一定要领域对象“喊出”事件,
也可能是“喊出”服务,作用于领域对象,进而抛出事件。。。。

从实体出事件还是从服务出事件,都可以就看领域上是不是这样。。。
还有是否需要事件,是看领域上需不需要,不能什么情况都塞一个事件进去

这样发布订阅,这是技术架构问题,你可看看banq写的东西。

个人观点仅供参
[该贴被clonalman于2012-09-02 13:34修改过]

2012-09-02 13:08 "@clonalman"的内容
还有是否需要事件,是看领域上需不需要,不能什么情况都塞一个事件进去 ...

“塞”? “事件”进入领域对象么?!

“喊出” 意味着“动作”已经完成,“事件”被产生。

记得banq以前的文章里提到hold住“事件”,我现在的想法就是在必要的情况下“喊出”“事件”。

至于“事件”是怎么被处理的,领域范围内就不管了。
怎么hold“事件”的,看要求而定。

目前我的想法是:
Repository已经涉及到技术范畴,不在领域对象内考虑。
Context---场景,这个跟业务有关,有必要保留。


希望多多指点,让我早日走出困惑。

thx

2012-09-02 14:52 "@donglangjohn"的内容

记得banq以前的文章里提到hold住“事件”,我现在的想法就是在必要的情况下“喊出”“事件”。 ...

从前的贴子留言看,我跟Banq的观点是存在一定差异,
事件对我来说仅仅是一个实体而已,与领域内的实体没区别,
如果要说区别的,可能就是他被某些架构关注

hold住"事件"是什么意思?要达到什么目的?


2012-09-02 15:52 "@clonalman"的内容
hold住"事件"是什么意思?要达到什么目的? ...

hold住“事件”,我的理解是hold住“事实”,领域对象的动作可能对边界外的其他事物产生影响,至于怎么影响的,会有什么后果,领域对象就不管了。

hold住“事件”的目的,就是让领域对象如实的描述“动作”的结果。

至于“事件”是否会被架构关注,看要求而定,领域层根本不关心,也不需要知道架构的存在。

个人的观点,用“事件”来分离领域层和基层。两层之间如何交互,后面再想办法就是了。

2012-09-02 15:52 "@clonalman"的内容
事件对我来说仅仅是一个实体而已,与领域内的实体没区别 ...

事件如果是一个实体,变成事件的记录了(事件变成状态),并不能代表正在发生的事件,要模拟事件,只能模拟让其对应正发生的行为。

以前我也有这样经历,做个很长时间企业信息化,面对需求实际是各种人工表单,比如入库单 出库单,而入库 出库实际是一种事件动作,但是人工记录把它记录成了静止的表单数据,而如果以此来建模,整个系统其实不能真正反映库存实际运转模式,因为把所有动词都变成了名词。

以货运为案例,结合DCI和事件设计,大概如下:

public Class Ship{

@Inject
ShippingRole shippingRole;

.....
}


Ship是data model也就是领域模型 ,ShippingRole是角色,由角色ShippingRole发出各种装船事件 比如到达 卸货等事件。

有些DCI实现是将Ship注入到ShippingRole中,我个人认为对阅读代码理解不利,你要了解领域模型的所有功能,必须一个个找它被注入到了那些角色场景中,这和SOA下被服务类操作使用有什么区别呢?

将领域模型的所有可能扮演的角色陈列在领域模型的,而角色的行为都分离到角色中,这样有助于我们只要打开领域模型类的代码,大概知道这个模型实现哪些功能?

以上是从业务角色看实现的ShippingRole角色,那么从技术架构角度看,领域模型还有持久化自己等等,按照职责驱动开发方法,无论是业务要求或技术要求,这些都是领域模型应该干的事情,应该承担的职责,难道业务上干的事情在领域模型中,技术要要求干的就不让领域模型干了?


由此,我们从对象职责这个角度综合业务和技术要求,得出领域模型如下:

public Class Ship{

@Inject
LazyOperatorRole lazyOperatorRole;


@Inject
ShippingRole shippingRole;

.....
}

其中LazyOperatorRole角色负责对实体Ship的其他次要字段根据需要进行加载,或者根据需要进行数据库持久保存。

其实,这里LazyOperatorRole和ShippingRole是不是和DDD中强调的Bounded Context非常类似呢?因为谈到Context,总是相伴角色的,比如DCI中谈到Context,隐式地其实围绕角色Role。

我们在实体中通过引入符合一定BoundedContext的角色,将这些BoundedContext下发生的行为分离进入角色,由角色通过发送事件给外界,如果不使用事件发送,这些角色行为实现不管是业务行为还是技术行为,总是不可预期的,它们可能是技术和业务混合在一起调用,比如查个数据库,发邮件,关联一下字段等等,这些复杂行为反而会弄脏领域模型,而只有通过事件引入,才能分离领域模型和其生存的环境。

所以,事件的引入可能已经不只是对业务有好处(业务本身就有事件如shipping事件),而且对技术架构有好处(如存储事件),更主要保证领域模型不会被太多细节包括技术细节覆盖,突出显示其作为系统核心,其代表用户需求的中心地位。

既然事件是跨业务和技术的统一语言,都在两个界限内出现,为何我们不可以单独抽象出来,只事件角度来分析业务和技术呢?这样是不是一劳永逸一点,这样我们是不是还可以很好地切分系统中动词和名词。按照我个人经历,我们过去从名词角度分析业务和技术太久了,以至于导致很多系统不能如实反映需求,关键在于我们自己的视角不够全面。

以上只是个人观点,欢迎讨论。


[该贴被banq于2012-09-03 07:43修改过]

2012-09-03 07:16 "@banq"的内容
事件如果是一个实体,变成事件的记录了(事件变成状态),并不能代表正在发生的事件,要模拟事件,只能模拟让其对应正发生的行为。 ...

事件的发生与事件的执行可能不是同时,可能是事件发生,一年后才执行,执行者可能是定时器或某个人。。。。事件做为一个实体,是在领域中记录发生了一件事情,但这件事情的后果是这样的并不清楚,

2012-09-03 07:16 "@banq"的内容
入库单 出库单,而入库 出库实际是一种事件动作,但是人工记录把它记录成了静止的表单数据,而如果以此来建模,整个系统其实不能真正反映库存实际运转模式,因为把所有动词都变成了名词。 ...

我不认为入库、出库就是一个事件动作,从领域上理解,它本质在进行货物移动,只是把货物搬出仓库或搬入仓库,模型只要能反映这一点即可。如果其他业务过程对这个搬出搬入仓库感兴趣,可以在搬出搬入发出一个货物移动的事件,通知一下。

这个事件在领域中可能是什么一个过程,比如"入库":可能会出现这样的情况,老总告诉仓库,供应商A的后入库完后告诉我一下;当供应商A的货到达、检验、入库、上架完,想起老总交带要通知他一下,仓库可能会打电话、直接到老总办公室告诉他这件事情,老总有可能通知财务先别给供应商A打货款

仓库打电话、直接到老总办公室通知老总,这个就可以抽象为入库移动事件

个人理解