OOD vs SOA

在Yahoo的SOA讨论组一直持续着OO面向对象和SOA之间的讨论,涉及领域模型domain model, 消息格式message format 和服务设计考量等方面。

随着MDD/DDD不断深入和扩散,特别是在.NET领域的深入人心,曾经以SOA发起为荣耀的Java阵营有些固步自封,反而对领域建模DDD有排除作用,问题倒不是出在Hibernate ORM这些技术实现层面,而是在战略层面,因为JavaEE已经有各个厂商联合推出的SOA战略。

如今DDD火热,SOA阵营的人不得不正视与领域模型的融合,这其中发生了各种新旧观念的碰撞,InfoQ今天专门发表文章对这一大辩论进行总结,原文如下:

InfoQ: OOD vs SOA Approach to SOA Domain Modeling

鉴于InfoQ中国可能对该文章翻译(需要客观观点看原文或等中文翻译),下面结合我个人DDD和SOA两方面经验,从我角度看看两者的讨论。

首先要搞清楚SOA和DDD是有区别的,SOA是以功能为划分边界,而DDD是以类为划分边界,将功能封装在类中作为方法。我个人更愿意把这两种都认为是最高意义上OO面向对象,就像现在面向函数语言Scala等也是以函数功能为划分。

初学者总是把面向函数或以功能划分和面向过程混同起来,两者本质区别就是有无边界划分。面向过程是很多功能模块混同在一起,一锅浆糊,而面向函数是以功能功能方法进行细分,松耦合解耦。

但正因为这个否定之否定,有点绕的概念,致使很多初学者使用SOA是以面向过程思维来使用,结合数据库SQL语言,我见过一个大型的SOA系统,其Web服务的定义实际就是数据表操作定义,SOA方法内部功能核心实际就是复杂一点的插入 删除 查询的SQL语句。

回头看看他们的讨论:
面向服务的建模技术(service oriented modeling ),比如具体到:面向领域的服务建模( DOSOM(Domain oriented service modeling) )是分解业务服务(SOA)的第一步,DDD是SOA的实现途径,通过基于业务功能结果基础上的领域划分,是迈向SOA的第一步。

一旦业务合约能够定义下来(由需求专家),OOD是实现服务实现的好方式,在SOA中分析需求不同我们在Jdon提倡的用例 四色原型 然后DDD等先后方法,它是首先定义业务合同business contract,是一种合约设计(Design by Contract),比如世界电信联盟NGOSS BOSS等都是这样SOA思路。

我曾经花不少时间研究NGOSS,实际上它和SOA一样,只不过是一个行业的SOA,同样存在SOA的缺点,只重视战略,战术指导不够,怎么实现都很含糊,结果很多电信BOSS系统都是基于关系数据库的SQL语句实现,出现我上面提到服务的方法实际就是数据库SQL语句的奇怪现象,导致系统难以维护和拓展,BUG不断,这时DDD正好可以弥补这样的缺憾。

当我们SOA中的服务是由富领域模型分解实现以后,带来的问题就是网络间传输富模型很浪费,那么大的有方法的富领域对象被序列化传输是性能杀手,现在一般使用只有setter/getter的贫血模型,实际是数据表的翻拍品,使用领域模型后,需要最小化服务之间的信息交换,可以使用一种主数据管理技术(MDM Master Data managerment)通过最小化的核心模型来实现消息。MDM我个人认为就是富领域模型的另外一种称谓。

具体谈到了Mortgage Industry Standards Maintenance Organization (MISMO)如何简化实体结构。MISMO适合作为相同行业中不同伙伴之间通讯的标准格式,对内部来说,核心领域模型使用是比较适合,因为通讯场景很少变化,也不必跨业务领域跨不同公司需要进行分享。在典型的企业内部需求中,灵活性和可维护性是必须的,而不是与其他企业通讯交换数据。

对于领域模型和SOA如何结合,我过去在Jdon帖子中也提出,SOA的服务内部委托领域模型的方法实现,SOA的服务对外是一个协定接口,打开SOA服务具体实现再看,你找不到核心功能实现代码,因为被分解到领域模型的方法中实现了,这点可以从Jivejdon的案例中可见一斑,这也是该讨论中有人分享他们的经验:Domain data is the classes that encapsulate information needed to implement services.This uses the classic object/relational mapping.
领域模型是用类来封装原本需要在服务中实现的信息数据,然后用经典的ORM映射。对于后面一句我也不敢沟通,如果说领域模型是SOA服务的分解实现,ORM则是领域模型的分解实现,有时我们不一定用ORM,用NoSQL也可以啊。这样说,会让很多初学者感觉绕了一圈还是落实到数据库,只不过中间加了多个环节,反而复杂,有脱裤子放屁嫌疑。其实虽然没多了环节,主角核心不一样了,现在主角核心是领域模型,不是数据表了。

讨论中David Tildesley 提到使用color modelling也就是jdon经常谈的四色建模,有颜色的建模技术,四色原型,结合原型领域形态(ADS)archetype domain shape 等,可以导向以组件为核心的建模方向,它认为传统的OO是以类为划分边界,有违SOA初衷。他认为每个业务组件都有其核心实体(四色原型中绿色或粉红色),他们由黄色的角色解耦。


从SOA和DDD定位来看,SOA更注重联系,外在关系,而DDD更注重内视,这是两种根本文化,就像有的人很注重人际关系;而有的人注重内修,学这个学那个,提高自己能力。前者在人多大企业公务员有好处,后者在私企或外企可以见长,当然如果两者兼具就更好,可惜能做得都好的人不多见。

我在下面另外帖子里给出:四色UML = SOA + DDD,当我们用彩色UML color UML分析需求以后,以后实现之路到底是以MI活动组件为核心架构,还是以PPT等静态组件为核心架构,是两种道路选择,当然,现在DCI好像正在模糊两者边界,静观其变:
http://www.jdon.com/jivejdon/thread/40577#23133002
[该贴被banq于2011-04-06 17:28修改过]

其实个人觉得,Role是Entity的内部划分,Role的Mixin后是实体,转角色就是一个边界思维。

从这个案例我得出一个个人结论:

高级程序员或架构师至少掌握两种类型语言才合格:一种以类为划分边界的语言,如java C;还有一种是以功能或函数为划分边界的语言,如SOA Scala javascript等,这样才能明白什么是真正面向对象。其他语言也基本可以划在这两个边界内。

这两个划分依据,实际就是产生对象的类和其中的方法,一个类包括属性和方法,我们通常把方法嵌入在类中,通过类创建对象,通过使用对象才能访问其内部的方法,这是Java C语言特点;而SOA和面向函数语言则是直接以方法创建对象,去除了外面的类的封装,这种方式可以说是以纯技术眼光来看待事物,适合在一些纯技术平台,比如Javascript与事件驱动,这些都是以技术论技术。

而通常以类封装划定边界的基本是模仿现实世界建模用,现实世界存在各种实体数据,这些实体用类来代表比较自然。

当然,现在Java C之类面向类的语言中,也可以加入面向函数或事件驱动架构,这实际是Java + SOA或Java +EDA的一个本质。
相关帖子:
http://www.jdon.com/jivejdon/thread/39834

InfoQ中文译本:
SOA领域建模,用OOD还是SOA方法?
[该贴被banq于2011-04-08 15:11修改过]

2011年04月06日 17:17 "@banq"的内容
从SOA和DDD定位来看,SOA更注重联系,外在关系,而DDD更注重内视,这是两种根本文化 ...

嗯,完全赞同。DDD注重神,而SOA注重行,两者不矛盾,在我看来是完全统一的。不过传统的SOA比较粗粒度,而我更喜欢细粒度的Rest。目前我正尝试用DDD+Rest的模式来搭建一些企业业务中的基础服务。

2011年04月09日 22:42 "@flyzb"的内容
DDD注重神,而SOA注重行,两者不矛盾,在我看来是完全统一的。不过传统的SOA比较粗粒度,而我更喜欢细粒度的REST。 ...

本质上也属于动静结合:
动:SOA服务 事件 REST 语言方法/函数 SQL
静:数据表中数据 内存中数据(类实体) 其他资源数据。

一个基本架构需要由动静结合,比如如果你发明一种语言,或一种框架,或一种软件生产方式,至少需要一个动一个静的方式。

当然,更多是多个动静结合,给人有些复杂,比如:
动组合:REST+服务+语言方法函数+SQL;再加静:数据表中数据 。

这么复杂是有原因的:将现实世界中实体切分为动的方法和静的数据,这种切割有时是很残忍的,静的数据用数据表数据表达,动的方法就只能用SQL语句,因为操作数据表数据只能用SQL语句,而SQL语句不能直接运行,必须用Java等语法函数来执行它,这就又多了一个动词。

如果我们反过来想想,不把实体残忍用动静切割,也不用过去的数据库,直接把现实世界中的对象作为类实体搬到内存中,是不是会简单些?比如:
REST + 内存中类实体 + 事件

REST用来实现外部联系,内存中类实体实现内部动静功能,比如实体内方法实现动功能,通过事件主动驱动外部,REST是被动接受外部。

数据表数据消灭了,SQL动词也就没有了。一切变得简单。

当然现在通用简单办法是:就只用数据库,比如只用REST+关系数据库,或只用REST+NoSQL数据库,也很简单。


2011年04月10日 12:42 "@banq"的内容
数据表数据消灭了,SQL动词也就没有了。一切变得简单。 ...

其实,现在很多的与数据库相关的系统,尽管用的是JAVA,到头来都不是在使用OO,而是以面向过程思维用JAVA来,调用数据库而已,都是挂羊头卖狗肉。把OO误导得一塌糊涂,纵观网上,比比皆是。

以对象为模型的系统,我认为是应该存在于内存的(若果扩展到硬盘的话,是一种虚拟内存的做法)。一旦把对象打散为数据,那么我们操作的永远是数据而不是对象,可以看看现在的教程都是修改数据库的数据,而不是修改对象,这教坏了多少想OO的程序员呢。在OO中使用数据库,对初学OO危险的,很容易被误导,必须要了解数据库不能决定任何领域模型,或者OO中最好不要存在数据库这一概念(不能理清其地位是非常危险的)。

用hibernate的OO用法是正向工程,看看网上还剩下多少正向工程的资料。“反向正用”也可,不过新手不懂这东西,于是又误导了——数据库表成为了模型。把保存到数据库看成一种“额外的”风险回避方式,对他们来说可能已经很难了。

非常同意banq,要么面向数据库(REST+数据库),要么面向对象(REST+DDD),混合的话,只会复杂而已。

2011年04月11日 11:39 "@SpeedVan"的内容
用hibernate的OO用法是正向工程,看看网上还剩下多少正向工程的资料 ...

非常赞同SpeedVan。我就是一个正向工程的坚持者。当我用.net时,我可以花半年的时间用微软DSL写一个类图设计工具可以正向生成ORM框架和数据库。现在我用hibernate,我仍然找了一个hiberObject,可以正向生成hibernate。这个在我的团队开发管理中非常重要的。

关于SOA的竞争焦点还将是更细分的行业标准,以及如何将业务、数据资产进行更细分地“解构”,像这种以SaaS为战略的SOA,已经有一些比较成熟产品,比如IBM的WPF项目(框架)。