2012-10-17 20:25 "@clonalman"的内容
实体间交互应该是同步直接发生,事件应该发生在不同场景下异步行为 ...

我是这样思考的,聚合体内部应该是同步,而聚合体之间应该用异步事件。

领域和领域之间使用事件,实际上是聚合体之间使用事件,基本上是一个聚合体(聚合根和其对象群)代表一个领域。

从结构上看,聚合边界是结构上的“场景”,而我们通常意义上的“场景”应该是行为发生的边界。

既然场景是一个行为概念,它大概不应该如同结构性概念一样存在属性等特征,按照契约设计原则,行为概念只有前置条件和后置条件,你可以将这两者等同于结构概念的属性。

题外话:本主题讨论的意义?


[该贴被banq于2012-10-18 13:10修改过]

2012-10-17 23:48 "@jdon007"的内容
此外,"Given-When-Then"和"Event-Context-State",似乎与"Input-Process-Output"的描述方式并无差异?只是以黑盒的方式描述系统或场景,对于要描述系统的可见性和可控性(白盒)似乎仍不够。 ...

我思考结果是这样:白盒是否应该就是领域模型呢?

场景-事件-状态 <==> 实体-聚合-领域

等式左边侧重行为,右边侧重结构,结构和行为衔接点通过实体的状态结合在一起。

实则这个等式也是函数语言和类型语言结合。也是逻辑上证明与类型的一种结合。

落实到日常开发交流中,需求人员只要向开发人员交待了这几个点,开发人员就能够迅速落地,希望这是一个接地气的大道至简的公式。

公式反过来也可以:
领域-聚合-实体 <==>状态-事件-场景

这比较符合类型为第一的思维,前者是函数为第一first class的思维。

我们通过本帖的讨论,将任何业务逻辑分解为上面这个公式,将业务逻辑真正接地,功效可见这个帖子:有个疑问困扰了很多年了~

与@clonalman 讨论业务建模:BoundedContext(有界上下文),DDD中的有界上下文根据我的观点可以初步看成等同于本帖的场景,这样用这套公式也可以涵括老外的DDD和DCI等等理论。

总结图如下:

[该贴被banq于2012-10-20 07:28修改过]

2012-10-19 10:43]banq"的内容
" border='0' loading='lazy' >

上图还应该体现服务的概念,Command、Event Bus、这些都带有技术特征,
模型应该是这样:
Command
V
V-----| V---------------------------|
服务->场景->聚合根(实体)->实体->事件(实体)
V
DB、Event Bus...

架构都通过服务过渡一下,两个闭环结构, 服务三个层次:基础设施服务、领域服务、应用服务
应用层与领域层调用都通过设施服务(持久化、消息机制等....)
应用层对领域层调用通过领域服务(业务请求)
领域层之间调用通过领域服务(业务处理)
应用层之间调用通过应用服务(不同调用粒度)

有点transaction script的味道

-
[该贴被clonalman于2012-10-20 08:59修改过]

2012-10-20 08:16 "@clonalman"的内容
服务->场景->聚合根(实体)->实体->事件(实体) ...

是否引入服务要值得商榷,服务其实也是一种DBC的contact实现,比如通常的服务合同,就是规定服务提供商和服务使用者客户之间的权利和义务。而我们这里已经引入了领域事件,有些重复。

所以,如果没有服务,调用顺序将是这样:
Uses发出Command -->MVC的Controller -->聚合根实体 -->场景 -->事件--->状态。

这样保证在OO结构下实现可管理的FP函数式编程。而如果使用服务,则可能相当于打开函数调用的潘多拉盒子,行为调用满天飞,回到过去面向过程的编程,也杜绝了事务脚本(Spring/EJB)的味道。

具体可见我这篇英文文章,中文就不想写了,有些罗嗦:http://www.dzone.com/links/cescontext_event_and_state.html

[该贴被banq于2012-10-20 09:39修改过]


用户点击UI上的某个元素触发command,command到达合适的场景后获取command的处理流程,流程的每一个节点均是事件。

现在command工作流开始运转,将节点事件依次发送给EventBus,EventBus将节点事件分配给合适的领域进行处理,处理完毕后EventBus根据各领域反馈的处理情况计算出command的处理结果。

工作流流转结束。

[该贴被gameboyLV于2012-10-21 14:00修改过]
[该贴被gameboyLV于2012-10-21 14:00修改过]

[该贴被gameboyLV于2012-10-21 14:01修改过]

2012-10-21 13:59 "@gameboyLV"的内容
工作流流转结束 ...

很受启发,今天看到SpringOne大会上文章:解耦应用的部署和可伸缩性Decomposing applications for deployability and scalability

这个PPT认为传统的服务+消息中间件模型Service/Message已经过去了,如第一图,因为将RabbitMQ消息broker引入服务之间的通讯,增大了复杂性,使用消息进行RPC远程调用更加复杂。

而现在的要求是服务的并行调用,如下面第二个图。这实际是我们讨论的Context/Event模型,已经成为趋势。

Service/Message model has gone, next big thing is Context/Event model
[该贴被banq于2012-10-23 21:32修改过]



2012-10-23 21:30 "@banq"的内容
Service/Message model has gone, next big thing is Context/Event model ...

由于Spring自身并没有向并发事件模型发展,PPT中谈及使用JDK的future task使用并发,最后推荐AKKA框架,提出Aspect+Actor模型(这实际也是JdonFramework的模型,使用disruptor模拟Actor),这个模型本质是一种事件驱动EDA模型。但是它的问题是走向了另外一种语言Scala。




2012-10-23 21:39 "@banq"的内容
但是它的问题是走向了另外一种语言Scala ...

既然函数式语言ERLang等并发性能如此之高,为什么不干脆直接使用呢?为什么要在Java中搞出Domain事件呢?

其实函数语言的优点也是其缺点,它的不可变性导致无法动态更改内存in-memory中聚合根状态,而在业务模型统一描述中,我们也讨论了业务现实本质是有态的。

关于函数语言ErLang等的问题见这个文章:Adventures in Concurrency的讨论部分timonk所说:

Summarizer(并行计算的汇总算法) isn’t primarily engineered for optimal throughput. Instead, its main goal is keeping lots of aggregations in memory in a compact form. As long as we can update those aggregations in a timely fashion, we’re set. As far as I can tell there are many reasons erlang isn’t suited to this kind of application.


Our in-memory aggregations(内存中的聚合) are many tens of GBs (when very tightly packed) and are the fundamental shared, mutable state of the application((共享可变的状态)). Some of the individual data structures are 10s or 100s of KBs and the copying overhead from ETS to process heaps would cripple us. The limited interface of ETS isn’t particularly helpful, either.

相关帖:
探险并发

当然函数语言Scala是个例外,因为其是一个OO-FP综合体,也支持传统类型对象,其案例代码见:
Scala的event-sourced和CQRS案例代码

其他相关主题:

传统持久化方式JPA/ORM面临CQRS/Event Sourcing的挑战,见:新编程范式:面向事件的数据库

[该贴被banq于2012-11-06 11:36修改过]