对领域驱动设计的初步认识(三)

10-10-19 flyzb
    首先声明,《领域驱动设计》对我来说只是一种建模技术,我讨论的前提是在面对企业多业务集成(如ERP、MES、HR、多项目、PDM、MRO)模式下的如何解决业务建模的问题。我提出的观点也许并不适合小项目甚至中型的单项目,因为技术架构和项目复杂度是相适应的。

    经过多年的企业实战,我对企业业务模型有了一定的认识,但关键是目前感觉还是技术滞后于业务的问题。我认为记住很多模式没有什么用处,带着问题在模式中寻找答案才是正确的使用方式,让那种解决方案的思想融入到你的模型当中,然后彻底地忘掉那些所谓的模式名词。

    上次我说“领域模型应该具有柔性”,这是我花了5年时间来打磨一个项目的过程中亲身感悟出来的。这让我意识到业务建模应该回归自然:一谈起来建模技术,就离不开国外提出的OO、EDA之类的东西,其实我们的老祖宗早就有了“摸脉”的说法,现在的SOA、ESB之类的东西是不是就像打造一个企业的“神经脉络”,而“OO”是不是就像“神经元”,它们之间的通讯就是靠生物电脉冲,这就是消息驱动。呵呵,当你在项目开发中感觉不自然的时候,那一定是你的模型出问题了,当然麻木除外。

    好了,回归正题。首先,谈一下“领域驱动建模”的入手问题。由于我针对的是大项目,所以我特别强调整体思考,进行自上而下的进行大的业务划分,先确定不同业务领域的边界。《领域驱动设计》一书中只是强调了业务的水平分割,然而在大项目里还有垂直分割,注意垂直分割不完全等同于包的划分。目前有一种非常错误的做法,就是一上来就开始对象建模,然后再进行归类划分模块;正确的做法应该是前期以确认领域边界功能为主,后期以确认领域内的对象模型为主。

    关于领域的切分,《领域驱动设计》没有过多谈及,其实方法就是不断对企业业务知识的学习和分析。当你对一个业务认识不清的时候,最好的办法就是不同企业环境下去分析这个业务,那这个业务的所有发展变化就清楚了,这就像那些生物学家总是喜欢通过长期的野外考查来学习知识。这个工作做好了,项目就成功了50%。

    领域的边界就是服务,也是对外提供服务的唯一入口(这点可能和banq不一致)。领域服务和领域对象模型是一个业务领域的2个不同侧面。领域服务强调是从外向内看,反映了“外部对业务领域的使用功能”;领域对象模型强调业务领域就像一个独立的具有一定自主能力的生命体,反映了“业务领域的内部运行机制”。

    领域对象模型的功能是不能对外暴露的,不然会造成外部对领域对象的耦合。我就亲身体验过域对象到处暴露而造成整个系统形成了一个领域对象相互关联的蜘蛛网,当项目小时无所谓,而一旦项目变大需要不同的部分独自发展而无法切割开来。另外一个原因是领域模型是不断变化的,比如“添加一个user对象”这个功能。一开始,就是业务很简单,认为放到User对象中就OK了;但是后来业务复杂了,“领导说了怎么随便创建用户呢,必须先审批”;最后业务更复杂了,“在不同的企业里这个审批的流程还不一样”。大家看一下,对于外部而言,如果一开始就调用的user域对象的方法就惨了,因为后来增加的业务应该是user与其他对象协作一起完成的,不能放在User内部,但是放在服务里就没问题了,外界只关心提供必要的创建user的信息就OK了,不关心内部怎实现的,怎么变化的,甚至于内部有没有User这个对象都没关系。注意服务里的addUser和User里的add方法是同时存在的,但侧重点不同。服务里的ADDUser是业务方法,而User的add方法仅仅是对象方法,前者调用后者。这就是封装,同时也支持了一定的柔性。这也是为什么在小项目里,有人觉得服务里写add,对象里写add没什么区别,甚至对象里写add更简单明了的原因了。

    什么样的对象适合作为聚合根的领域对象呢?一般而言,user在大多数情况下都不是领域对象,而customer可以是。因为user是泛指,除了在HR中user可以是领域对象。你可以想象一下,在一个企业里有好几个不同的单业务系统,都是基于领域驱动设计的;在这些不同的业务场景下,user都可以聚合根,这很正常,因为人可以干不同的事情。但如果把这些业务集成起来就有问题了。所以说作为聚合根的领域对象应该是业务场景类,而不应该是类似user的这样的类。当然,在小项目或者单项目是不存在这样的问题的。

    User作为另外一个域中的对象,在其他领域内如何引用呢?大家都知道,其实大多数业务应用中只需要一个仅仅包含UserId和UserName属性的对象就够了,显示足以。所以User在其他域里是值对象,但却不需要引用像rich domain中的那样的User.

    呵呵,这个帖子的观点也许有些不同,让讨论更猛烈些吧。

[该贴被flyzb于2010-10-19 09:03修改过]

         

8
xiaosanaiq
2010-10-19 11:19
哇塞。。太帅了。。呵呵。。

相当深刻啊。。

SpeedVan
2010-10-19 16:57

后面像道出了DCI的模型了,你可以去看看。至于文中水平分割,垂直分割···这么抽象?没听过这样的说法,数据库倒听过。事务有串行事务(同步,如流程),有并行事务(异步,如响应)。至于你所说的并行划分,是指寻找服务(找到业务就横着放着一起,关联时才联系起来)??

分层就分层,不分服务,只有分析设计领域时才,分析出服务。至于包划分,这些是人为的,根据状况设计的,目的是使项目更加清晰(你完全可以只有一个包,分析设计的逻辑仍然在里面的,但这样的项目不易读)。

xmuzyu
2010-10-19 19:27
呵呵,讨论越来越深入,不错。

下面说说我的理解:

我个人觉得如果仅仅按照<<领域驱动设计>>这本书上面讲的东西去领域建模会有点困难,为啥呢?首先一个复杂的业务系统,逻辑必然很复杂,那么逻辑放到哪里呢?领域模型实体对象?还是领域服务呢?领域驱动设计没有明确的告诉我们到底哪些逻辑放到实体对象里,哪些业务逻辑放到领域服务里,我倒是觉得结合四色原型的分析方法会更好,四色原型用一句话概括就是:一个具有某种描述(蓝色DES)的实体对象(绿色PPT),以某种角色(黄色)在某个时间段内(红色MI)对某个实体进行了某种操作(红色MI),最终产生了某种结果(绿色PPT),那么我目前的做法就是业务逻辑的操作是在角色里面,这种操作是角色所具有的(类似DCI中的场景),而具体如何做的是由红色MI模型去做的,而MI模型做的过程中又会和实体对象进行协作,这样就比较清晰一点.

PS:大家还有什么其它的想法,也分享下。

banq
2010-10-20 07:54
2010年10月19日 00:41 "flyzb"的内容
现在的SOA、ESB之类的东西是不是就像打造一个企业的“神经脉络”,而“OO”是不是就像“神经元”,它们之间的通讯就是靠生物电脉冲,这就是消息驱动 ...

非常厉害的比喻,这是只有宏观思维的人才会有这样形象描述。

楼主对服务和实体模型的区别描述也非常不错,为解决松耦合,DDD还提出专门的防腐层。

>这也是为什么在小项目里,有人觉得服务里写add,对象里写add没什么区别,甚至对象里写add更简单明了的原因了。

现在很多初学者会将业务逻辑写在服务中(他们甚至不会写两个add方法),User或Customer这样的实体模型都是贫血模型,只有setter/getter,没有其他业务方法如add等,这些都是典型的面向数据库编程思路。

[该贴被banq于2010-10-20 07:55修改过]

猜你喜欢
3Go 1 2 3 下一页