领域模型实践中的一手问题

最近公司在做一个项目,公司以前是做C/S的,目前在向Java方面转型,这个项目在技术BOSS的领导下用领域模型模式实现。
倒是请了些有Java开发经验的,技术是没有问题,但以前都用事务脚本,有很重的数据库驱动思想,所以对领域模型也不是很在行。
我们在摸索中也克服了一些障碍,但有些问题还没考虑清楚。今天贴出来希望大家指正和帮助。

业务知识:
报销病人按政策参保即可享受按比例报销待遇,每年缴费一次,第二年全年可享受。
管理中心负责本地区报销相关业务的管理,负责定点医院的审核、拨付垫付款,负责域外就医病人返回时的报销。
管理中心设置多个报销定点医院,域内定点医院与管理中心联网出院即报,医院垫付报销款,每月与中心结算一次。有些定点医院使用收费系统与本系统接口,有的定点医院没有收费系统,使用本系统提供的功能录入报销。域外医院不出院即报,病人自付,回中心报销。
管理中心可在下级设置办事处,负责更小地区的医院、参保人管理。
各级政府负责本地参保,使用登记系统维护档案。每年年底进行一次参保,中途不允许参保。

系统目标:
完成一个数据集中逻辑分离的经办机构管理系统。
最大考虑以省为单位部署系统,每个县(区)有一个经办机构,经办机构数最大可达100-200。

面对4类用户:
技术部门,系统部署在全省,本公司技术部门负责按需开通管理中心和系统全局的维护。必要时使用系统。
管理中心和下级办事处:负责本地区业务的管理、域外病人报销等。全天使用系统,每个中心10个用户。
定点医院:负责本院病人的出院报销、报销款垫付、每月与中心结算。每个医院用户不多,但医院很多。
政府:负责参保、维护参保档案。每年年底使用,短时间强度大。

根据使用用户、频度、强度不同,划分为5个系统,共用一个数据中心,除了中心业务系统其他的都可算是支撑系统,因为只有中心付费,但没有其他系统中心系统也运作不起来,所以要实现但要分清重点:
全局管理系统-技术部门使用。
中心业务系统-管理中心和下级办事处使用,可以分配权限。
定点医院系统-定点医院使用,关于报销逻辑、档案逻辑等在此,其他系统都是调用。
接口系统-医院收费系统和本系统的对接。
参保系统-政府使用。和中心业务系统的档案是复制关系,不能直接操作。

系统层级划分:
用户接口层。使用ExtJS组件,所有组件都做了封装优化,Ajax操作用了一些JQuery的东西。
facade层,即应用层application。负责联系用户接口层和领域层业务逻辑,有事务控制。一般一个用户接口层界面有一个facade对应。
领域层domain,分为Model、Service、Repository,这里我们有点分歧,但逻辑都在这个层次是一致的。我认为Model对应领域内的一个实体,Service对应一种关系到多个实体不能简单并入一个实体的实际业务,Repository是根对象与持久层交互的仓库。技术BOSS认为Serivice是一个小领域的整体包装,所有业务都在里面写,facade层就和这个Service交互。有些人认为用Dao就可以了,每个Model都有一个Dao,基类Dao里原来写好了基本方法,且用泛型直接就拿出了对应的模型,不用转换,如果用Repository好似还要自己转换类型,对这种理念也不熟悉。
基础设施层infrastructure,hibernate、iBatis、jdbc都应该会用到,好像可说的不多。

还没确定的:
已经决定分为多个系统,那代码复用怎么做?是整体设计domain,然后直接复制粘贴或build到其他系统吗?这样的话还有下面的问题要考虑:
先分层再分包?这样每个系统的facade层都直接依赖于domain层。
先分系统包再分层?这样每个系统包要对外提供一些服务。
还是两种混合?

考虑几天没有头绪啊,也没有经验,各位能否给点意见建议

首先划分子领域,也就是划分不同场景,比如进销存系统,从字面上看就可以划分三个子领域:采购 销售和仓库。

然后分别在每个子领域中开始进行核心建模,找出核心模型,可以使用四色原型进行需求分析,然后结合Evans DDD进行聚合边界划分。

其实方法很简单,就是切蛋糕,大切成小的,小的切成更小的。

至于你们老大说的:认为Serivice是一个小领域的整体包装,所有业务都在里面写。

这是不对的,Service不能写所有业务逻辑,一部分业务逻辑是由实体交互完成的。如果写所有业务逻辑,就是大家批判的贫血模型了。

里面在项目开始之时,不要将软件架构和领域建模混为一谈,这是两个不同的知识领域,软件架构是为领域建模服务的,业务需要什么样的架构就使用什么架构,而不是业务没有深入了解建模,就谈架构,那浪费时间精力。

你们需要对Evans DDD以及对象建模有背景知识,如果没有,就走数据库建模,事情很简单。

谢谢banq的解答。
我还有写问题要请教一下:
我们老大其实也是要充血模型,业务方法写在Model里。
对象建模我们还是能胜任的,老大也有10多年经验。
这个项目以后会长期升级和维护,用事务脚本以前也都有过教训。时间长了代码在那里谁都不敢动,业务逻辑离了当时编的那个人就不行,bug改了这个出那个。现在才有这么大决心向这条路走。

我们的不同是他是说一个子领域有一个Service类,这个类对上层暴露接口。应用层都是调这个Service,即使单Model完成的业务逻辑也要调Service。
Evans DDD我俩都看了,而我看后的理解是说Model和Service是并列的两种领域对象,只是有些涉及多个Model实在不好硬归入某个Model的业务逻辑会形成一个Service,Service对应着领域内的一个个实际业务。

按照我的逻辑,应用层访问领域层需要调Model就调Model,需要调Service就调Service,事务在应用层控制就行了。想不出还非要把领域层包装一下再对外暴露的意义在哪里。

说起封装很多人立刻想到的就是接口,但实际上需要封装的是变化。他的目标应该是在自己一层处理所需要面对的变化,对外提供协议化的输出结果。定义接口或者说封装的目标就是定义协议,协议的目标是稳定,无论是接口的名称、参数还是返回结果都应该是稳定的。

返回来看你们的实际场景,service的目标就应该是提供协议化的接口。至于model是不是需要被service再次封装还是要看他在你们的业务过程中是不是稳定的。

打个比方,我们就把当作是model吧,对于在中国大城市(某些边远地区另议)使用的电器设备来说220V的电压是不需要被封装的,任何一个插孔上都能保证这样的输出。这就是协议,一个在供电插孔和电器设备间定义的协议,是不可能改变的。但是美国的电压是110V,这是美国定义的协议,如果你把一个普通的美国电器拿到中国来用?那么好一个220V -> 110V的转换设备就必不可少了,这个设备实现的就是协议的转换,此时这个转换设备就成为了service

以此为例在现实的软件设计中model是不是需要被封装还是需要看你所处的实际业务环境,特别注意是你所处的业务环境,在这个特定的环境下这个特定的model有可能变化么?如果有那么就需要service,如果没有service就是累赘了。

所有的接口、封装,他们的本意是应对变化,如果对于本来就是不变的东西就不需要再来考虑这些问题了。
[该贴被IceQi于2009-09-26 08:36修改过]