关于领域驱动设计的一些疑问

早在一年前就有听说过jdon,近期又对banq给出的几个例子结合框架(jdonframework)源码读了一下,对于jdon的核心思想->领域驱动建模(Domain Driven Design)有些粗浅的理解。我个人的认识是:
1.领域,即业务模型,如banq给过的两个例子:比赛、机器人。这里的业务模型又包括业务对象、对象行为、对象状态。
2.驱动,即事件驱动。这里我将业务对象的行为理解为事件,也就是业务对象的行为(或动作)操作定义为事件操作!
以上理解,不对之处,还望各位走过、路过的大大们不吝拍砖(指正)!不胜感谢!
额?。。。不好意思,可能说的不是很清楚!
我的疑问:
1.看了几个例子,感觉DDD的思想代码里面诠释的很清楚了,不过貌似里面对jdonframework的应用好像很少(不知道是不是我理解有误)。感觉和别的框架很大差异,不是很清楚jdonframework的定位是干什么的?(像经典的hibernate、struts、spring等,还有快速开发框架springside等都有明确的定位!或者说它们给出的范例更多、更全面!)仅仅只是推广DDD设计思想吗?(希望大大们能够不吝说明下!非常感谢!)

[该贴被Awaken于2014-01-02 19:21修改过]

>这里我将业务对象的行为理解为事件,也就是业务对象的行为(或动作)操作定义为事件操作!

你的疑问可能和这段理解有关,对象的行为由事件触发,但是不代表两者是同一个概念。

如果你区分了对象的行为和事件,那么就会思考事件到底是什么,其实在传统技术架构比如SSH中,我们的对象行为是被用户的请求触发的,用户的请求提交给Struts,然后通过Struts 的Action提交到Spring的服务,调用服务的一个方法行为。

这个思维方式是一种请求/响应思维,而我们现在要以事件替代请求/响应(request/response),这就是EDA最大不同。

因为思维方式不同,那么肯定有不同的框架,Jdonframework就定位在事件角度。

上面流程就变成:用户发出一个命令command,被富领域模型的行为接受处理,在这里会有多个命令操作同一个模型的同一个状态的问题,一般要引入堵塞锁,Jdonframework通过Disruptor的队列实现某个时刻只有一个线程调用模型的行为进而修改状态,非堵塞无锁。

第二点,当模型中的状态被修改以后,会有一个事件触发,称为领域事件,实现EventSourcing,关于DDD和ES的关系见:http://www.jdon.com/46041

除了对业务的思考方式不同,技术特点也不同:
比如在一个典型SSH应用案例中,用户界面中的用户请求(在浏览器中,REST客户端或其他地方)发送到web层进行解析,然后分发到中间件服务组件,通过它的高速缓存然后下推到数据库。如果这些层中任何一个层都不参与以下操作:阻塞调用数据库,依靠共享的易变状态,使用昂贵的同步操作进行调用,那么整个请求处理响应的流水线就不会停顿,用户就不会将遭受延迟通过增加和减少的可扩展性。

An application must be reactive from top to bottom
一个应用必须从顶层到底部都是reactive的。
http://www.jdon.com/45811#23143632

Jdon框架提供了整个技术堆栈都是可异步和高并发的。

[该贴被banq于2014-01-02 20:00修改过]

感谢banq大大的不吝指正和解释!
嗯,对于您刚对事件和行为的回复,我可不可以这样理解:
(举传统的例子)
>“......在传统技术架构比如SSH中,我们的对象行为是被用户的请求触发的,用户的请求提交给Struts,然后通过Struts 的Action提交到Spring的服务,调用服务的一个方法行为。”
上面说的“用户请求”即是事件,通俗点讲就是:用户在页面点击某个按钮或链接(点击是行为!),触发请求提交给后台.....(这里请求是事件!)
不过,我感觉行为和事件有点难以区分(可能习惯性思维),像上面:用户在页面点击某个按钮或链接(点击是行为!),触发请求提交给后台.....(这里请求是事件!).....,后台控制层调用action层,action调用service服务层处理方法(这里又是一个行为)....
(行为和事件)它们之间的界限貌似不是很清楚,如果不注意的话。

请求 行为和事件都是有区别的。

请求和响应是一对,谈到请求就要有响应,请求不能单独存在,就象谈到服务就有客户端一样,两者是配对的模式。

问题来了,因为请求和响应是一起的,所以谈到请求就必要有响应,而实际中有时请求只需要有一个http 200的响应就可以了,这时响应就没有意义,就剩余请求了,这个请求就蜕变成事件了。变成事件的好处是,原来请求必有响应其实是同步,而没有响应的请求其实是异步,异步并发概念可以引入了。

请求(事件)在多层之间传递时,身份其实有改变的,在进入聚合根实体模型之前是命令(有时也称为事件 比如UI的javascript点击按钮也称为事件),改变实体对象状态后是领域事件,也就是在领域中发生的事件,不是UI发生的事件。

行为是对象的能力,打个比喻,如果把行为看成是炸药的引子,那么事件就是点燃引子的火种。行为是在我们设计类时根据业务特点设计好的,而事件是在运行时才产生,事件类似交互的行为,而普通行为是对象职责行为,按照单一职责SOLID等等设计的。

行为是静态的,事件是动态的。

在事件驱动场景下,一个用户发出命令要修改聚合根实体模型的状态,这个命令是通过守护状态的行为实施的,打个比喻,状态是宝贝,守护行为是警卫,大盗是通过警卫才能取得宝贝。在事件驱动情况下,这里我们引入单写原则,同一个时间只有一个线程修改状态,虽然锁也能达到这个目的,但是我们这里没有用锁,而是如何让Java以光的速度跨线程通信中的Railway算法或RingBuffer算法,而传统请求/响应模型,这里引入的是 ACID事务,比如 JTA(Spring or EJB session bean) 或者使用HHibernate/JPA的乐观锁rOptimistic lock(Hibernate/JPA)。两者比较见:http://www.jdon.com/performance/singlewriter.html


[该贴被banq于2014-01-02 20:48修改过]

嗯!您的解释很形象!感谢!
额,不过这里吐槽一下,感觉一下子从以前的思维方式很难转变过来。。。直接的感官就是DDD设计的有些东西好难理解!(纯粹个人观点,我不知道别人有没有相同的感觉!)这样就对接受这种设计方式很不适应,或者感觉很难上手!希望banq大大不要介意!
嗯,这里还有几个问题:
1.既然架构设计方式都变了,那么以前的那种mvc的分层式结构还能用吗?如果不能用了,现在怎么办?(因为我发现在jdon官方给的例子里面好像是没有的?)
2.ES事件溯源,感觉有点像workflow工作流,能向前、能后退....。这样,ES好像都是保存在缓存中的,那么当这种以事件为核心的架构,保存的事件数据会不会很多?另外,保存在缓存中会不会有丢失的危险?(我的认识缓存之所以应用广泛,保存在内存中便于快速读取是一个很大的优点。可能认识有误!)

2014-01-02 20:56 "@Awaken"的内容
直接的感官就是DDD设计的有些东西好难理解! ...

这很正常,我觉得大部分是受现有技术的误导,为什么认为是被误导呢,因为在Node.js中这种行为事件驱动的方式很自然(http://www.jdon.com/46024),或者在面向函数编程中就很自然。

修改内存中数值,然后将触发修改行为的事件作为日志保存到日志文件中,MongoDB等NoSQL内部机制都是这样,可能我们更多知道memcached的内存读,很少知道NoSQL这种内存写的原理。

谈到这里,你可能发现Node.js + MongoDB其实和Jdonframework的殊途同归。这也是为什么看好Node.js的原因所在。

恩!我有点明白您意思了!
面向函数式的编程,我也有做过,JavaScript应该算吧!这门语言我想大多数人都应该接触过。这里,我又有一个疑问了,也是一直以来想的一个问题 :
敏捷开发是怎么一回事儿?或者说敏捷应该包含哪些方面?
感觉函数式的编程有个缺点,就是阅读代码不像Java这类语言那样轻松,编写代码也有点儿。这里我并不是说面向对象好,或者面向函数就坏!只是觉得面向对象能够大行其道,必有它的原因!我们更应该理性的认真剖析这些东西畅销的原因!
我觉得敏捷开发应该包含这样两个方面:
1.架构设计方面
架构设计要灵活:
一要底层组件支持足够强大、便于拓展;
二要达到一定的性能指标(当然,各方面平衡的情况下,性能越高越好!)。
2.代码开发方面
代码开发要简捷:
一开发代码、配置要尽量简单,但不是“零配置”。我觉得,项目开发不是一个人的事儿,公司招的人也不是只要个会复制、粘贴的工人。这样,纯粹是杀鸡取卵!(呵呵,可能有点儿偏激!)
二要规范编码,能够让同行清晰看懂代码所要达到的目的。
就敏捷这一点,不知道大大们能否不吝赐教,扔扔“板砖”!非常感谢!

站主把http请求/响应中的响应忽略掉,然后http请求当做异步的事件来实现事件驱动?

请问模型的变化怎么刷新到UI?Ajax轮询还是基于长连接(WebSocket?),说点实在的吧

关于楼上二位统一回答如下:

1.敏捷可参考:http://www.jdon.com/agile.html


2.关于请求/响应中如何返回客户端问题,当我们转移到EDA思维时,关键是UI界面已经也不是传统UI了,而是一种响应式的UI,传统UI是一种表单几十个字段,不管先后主次都罗列平铺在界面上,用户提交这种大表单后,当然希望后台返回一个出错,出错在哪里的响应。

但是如果在移动界面下,你不可能这样做,我们在手机上看视频时,视频界面操作界面是隐身的,当我们需要时,点触屏幕,发出命令或事件,屏幕响应,会浮现出控制界面,然后你点触“停止播放”或“加快”等等按钮。这就是原本将空间上并排罗列的元素变换成在时间上的根据事件先后显示。

所以,用户每次输入的是很少数据,输完一段,按下一步,通过流程上安排,如果必须同时输入很多,我们也是通过AJAX对这些数据逐条验证,确保用户按提交保存按钮时,除非技术原因,业务上出错基本排除。而技术上原因,可以从http码上反映,可以查查http码大全。
见:任务驱动的UI

JS讲究事件驱动,AJAX,甚至单一应用,如Angular,js只在一个网址下实现各种应用,没有我们通常提交表单后显示另外一个页面的URL,Java程序员一般喜欢主导这个响应结果页面,而面对Angular.js这样客户端MVC,后端Java不再主导前端,而是平等的对话。

我现在很有体会为什么Paypal将后台换成javascript,让JS前端来主导后端,可能效果更好些。

具有复杂业务逻辑的核心业务系统才适合领域驱动设计,简单的系统或者大数据应用使用事务脚本反而更合适。DDD不是银弹,现实中,一切要从实际出发(团队成功素质、历史原因等)只有适合自己项目的架构才是好的架构。