领域驱动设计之实践与反思

领域驱动设计之实践与反思

一、引言

前两三年,在这里我先后写过三个帖子,分别阐述了对三个问题的思考。
1)什么是程序?结论是:程序=数据结构+算法+设计模式。
2)什么是领域模型?结论是:人对领域的认知,即其心智模型。
3) 如何描述领域模型?结果是提出一套建模原语:模型、结构特征、行为特征和场景。

这些帖子都曾引起了一些争论或批评,之后我也在不断实践和反省,今天我决定把最近一两年实践的经验,加以总结,在此欢迎各位的讨论和质疑。

二、正文



首先,对上面这个图进行解释。
1、业务模型 = 业务对象 + 业务规则。
2、业务场景:在业务场景中,业务对象在业务规则的约束或指导下,呈现依赖于场景的行为特征和结构特征。
2.1)行为特征:比如监听请求事件、反序列化操作、请求参数校验、抛出异常等等,主要描述业务对象在特定的业务场景下的行为。
2.2)结构特征,比如获取事件处理结果、序列化操作、响应数据格式、业务对象状态显化等等,主要是描述业务对象在特定的业务场景下的结构。
3、接口层:接口层向上为业务场景提供服务,向下使用数据库提供的服务。领域模型通过接口层与外界交互。
4、REST API: 如果说接口层是业务模型与Web服务内部其它部分的交界处;那么REST API则是Web服务与外界的交界处,REST API描述如何开放Web服务给Web应用。REST API调用,使得应用端进行“表述性状态的转移”,服务端进行“业务场景的切换”。

接着,描述这个图的用法,这也是我目前使用的设计与实现的方式。
1)从面向应用或用户代理的API开始(粗粒度的REST API,HATEOAS);
2)接着是场景设计,包括结构特征和行为特征,一个REST API可以表示一个或多个类似的场景;
3) 根据场景,设计业务对象和业务规则(关注点:如何保证其在场景过程的可用性)
4)根据场景,设计数据表结构(关注点:如何场保证对场景结果的持久性)
5)接口层的设计,last but not least, 考虑在业务场景、业务模型(业务对象和业务规则)、业务数据(表结构)之间,如何有效地将信息流(数据流和控制流)进行传递或转移。

注:步骤3和4,设计的先后的顺序没有关系,事实上两者可灵活交替设计都无妨。因为两者的关注点是有差别的,但又相互补充。业务数据的设计追求持久性和无冗余性,而业务模型的设计着眼于可用性和直观性。

三、反思

1、关于ORM
如何将表的关联(one-to-one, one-to-many, many-to-one, many-to-many)映射到对象上,如何将对象的继承映射到表(single table、joined、table per class),这种费脑子的事情且不说。ORM的性能也是大大的问题,比如当我们只要记录的某几个属性的数据,且不需要级联的数据,ORM却不分青红皂白,把所有数据都返回给我们。
JPA是ORM的集大成者,巅峰之作,也并没有从根本解决上对象和关系的天然阻抗。当我看到业务对象填满了各式各样的annotation,总觉得该是哪里出错了。
ORM真的是对程序员智力的极大浪费。不管正向设计(从对象到表),还是逆向设计(从表到对象),都是错误的方向,这条路不适合再走下去了。
事实上,在数据的访问上,我们需要的,仅仅是一个小小的库, 帮助我们完成连接的管理和结果集数据的自动提取而已。
在我的设计中,接口层可以直接读写取数据库,如果业务场景需要的话,也可以使用异步的方式进行读写。

2、关于MVC和DCI范式
在经典J2EE三层架构,MVC一般在表现层应用,jsp为视图,servlet为控制器,java bean为模型。jsp是in-out的servlet,是服务端的脚本,把数据的展示,客户端该干的活都干了,真是越俎代庖呀。Ajax的出现,这一问题得以缓解, 服务端只要给客户端数据即可。jsp等服务端的渲染技术,该进博物馆,退出历史舞台了。
MVC在Web架构中为什么会被这样误用呢? 事实上,MVC在桌面软件或客户端应用的构建上非常非常好用。我猜测,J2EE架构的最初设计者,并没有认真考核其是否适合构建Web服务。
那么DCI适合构建Web服务吗?恐怕也不太适合,其适用于指导业务场景的设计与实现,而Web服务的整体架构,还是REST风格比较合适。

3、Web服务不是Database应用
在jdon上可能存在这样一个误区,老是想把数据库给屏蔽了。ORM这条路已经行不通了,现在开始换另一条路NoSQL。可是诸君可见?所谓的NoSQL, 却追求着SQL-style query interface。从使用上说,API style是给我们最直接的感受,至于底层是使用key-value方式还是relation的方式实现,对我们的影响到底有多大呢?
事实上,一味地追求屏蔽数据库,极有可能走向另一个极端:我们所构建的Web服务不过是一个Database的应用。
我想说的是,不要像ORM那样试图去屏蔽数据库,记住Web服务的真正使命: 为Web应用提供服务,其它东西任何都要在其之下;与其浪费精力去屏蔽数据库,不如将其视为构建Web服务的一部分,发挥其最擅长的能力;而将更多地精力花在如何给Web应用提供更友好的API的设计上。

2013-03-30 22:26 "@jdon007
"的内容
1)什么是程序?结论是:程序=数据结构+算法+设计模式。
2)什么是领域模型?结论是:人对领域的认知,即其心智模型。 ...

楼主这篇思考总结得挺好。

我在思考一个问题,既然 程序=数据结构+算法+设计模式,而领域模型虽然是人头脑中对业务认知的模型,那么体现在程序中哪个部分呢?

我认为领域模型体现在数据结构这部分,常常有人说,think your data,也就是说好好考虑你的业务。

领域模型通过数据结构表达了“是什么”的概念,而算法则是表达了“怎么做”,设计模型表达了如何将“是什么”(目标)和“怎么做”(路径)进行分离。

我认为:领域模型=逻辑+数据。或者可以认为“数据结构”中“结构”代表逻辑结构的意思。

谈到数据,有一个根本问题:数据的一致性,过去,我们使用关系数据库来表达带有一致性的数据逻辑结构,今天因为NoSQL带来对数据一致性认识的提升,Martin Fowler最近总结了有关数据一致性:Martin Fowler on Software Design in the 21st Century

数据的逻辑一致性(Logical Consistency)使用DDD聚合;数据的复制一致性(Replication Consistency)使用CAP定律

数据是最基础的元素,用数据来表达业务逻辑,也就是领域建模;数据作为值自身复制遵循CAP。

[该贴被banq于2013-04-10 17:20修改过]

2013-04-09 14:30 "@banq
"的内容
而领域模型虽然是人头脑中对业务认知的模型,那么体现在程序中哪个部分呢?
...

两三年前,这个问题我们讨论很久,这里就写点一些新的体会:

业务模型包括业务对象和业务规则,即程序中的数据结构和算法;业务场景即业务模型的使用,即程序中的模式。

数据结构和算法可以理解为阴和阳,或盾与矛,是为“体”,模式,可以理解为对立统一规律的应用,是为“用”。同样的,业务模型是“体”,业务场景是“用”。

上面的体会,可能过于务虚了。换一种可操作性更强的说法:

业务对象为词汇,业务规则为语法;业务场景为语境,结构和行为特征为语用。

领域模型的建立过程,即领域语言的构造过程,提炼出领域语言的词汇和语法;然后根据不同语境,运用这些词汇和语法,即语用。

相对于词汇或语法,语境和语用同样重要,因为“用法即意义”,缺失“语境与语用”的“词汇或语法”是没有多少意义的。当然,之所以没有多少意义,是因为:无之以为用。

至于数据的一致性,最近重看一本书,里头的提到一个问题:为什么延迟完整性检查是没有意义的?现在,还没有想清楚,等想清楚了,再上来讨论。


[该贴被jdon007于2013-04-17 22:05修改过]