重新设计已有系统的架构,看下可否行得通

项目目前描述:
1.项目基本没做什么架构设计
2.为了达到快速开发,达到定期交付的目的,项目采用目前最最流行的s2sh框架,基本分层为:表现层+业务层(业务都写在service),连DAO层都省了,用HIBERNATE里的模板包装成一个通用的dao搞定。
3.直接用持久化对象作为传输对象在表现层与业务层之间传递
4.模块没有划分,很多耦合在一起,重复代码一大堆
5.项目是已经交付了,现在是维护期,有用户提的新需求及BUG,现在已经感觉越来越难维护了,而且项目还会有二期、三期,并且接下来会有各种与其他系统的整合需求提出。

针对目前的情况,我已经跟项目经理提出过这种情况(项目经理也没什么经验,纯理论型的),要我这边整理一个架构文档,并且估计工作量,我是其中的一个开发人员,也没架构经验,没办法,没架构师,这事也只能落到我这边了,也请大家多多帮忙呀!依我之见,主要有以下几点需要调整:

1:引入DTO,持久层对象与DTO司其职,这样也可以达到解藕,DTO与持久对象还是有一些区别的。
2:原来service只是作为提供业务的服务对象,而不是在里面实现业务的地方。
3:把实现业务的地方单独出来一个领域层,注意:我这里说的这个层与实际的领域层是有区别的,这里的领域对象更多的是只有行为,没有属性,很多单元操作的业务会放到这里。因为这里持久层对象还是保持不变,也就是保持贫血状态。主要是出于工作量的考虑及开发人员对领域建模的水平考虑。
4:建立DAO层,把持久化任务从业务层解放出来。
5:划分粗模块,目前不考虑划分得很细,目前是的项目代码全是放一起的,打算划分成比较粗的几个工程,以jar包集成,我比较重视的是公共的模块,这个模块是每个地方都要用到的,比如用户管理等
6:迭代的重构方法,第一次迭代会先对公共模块下手(因为是公共的,所以很多地方有重复代码)。
7:用声明模式(在J道上看到的)解决到处拼SQL的问题
8:用AOP或过滤器链的方式解决数据权限的问题

暂时想到这些,不知是否可行?大家多多给锤锤

>1:引入DTO,持久层对象与DTO司其职,这样也可以达到解藕,DTO与持久对象还是有一些区别的。

复杂系统中是可以的,但是注意对象类型太多引起混乱,要注意把握精简原则。

>2:原来service只是作为提供业务的服务对象,而不是在里面实现业务的地方。

非常正确,这其实就是方向和路径的区别,What和How的区别分离。


>3:把实现业务的地方单独出来一个领域层,注意:我这里说的这个层与实际的领域层是有区别的,这里的领域对象更多的是只有行为,没有属性,很多单元操作的业务会放到这里。因为这里持久层对象还是保持不变,也就是保持贫血状态。

很好,关键技术就是行为和贫血的数据对象如何结合问题,建议引入DCI,通过引入场景,将Data和交互行为进行动态结合。


>4:建立DAO层,把持久化任务从业务层解放出来。

用仓储层替代DAO层,两种初步看差不多,但是仓储这个单词更业务一些。

>5:划分粗模块,目前不考虑划分得很细,目前是的项目代码全是放一起的,打算划分成比较粗的几个工程,以jar包集成,我比较重视的是公共的模块,这个模块是每个地方都要用到的,比如用户管理等

模块化是非常重要的。

>6:迭代的重构方法,第一次迭代会先对公共模块下手(因为是公共的,所以很多地方有重复代码)。

重构方法中第一步是合并重复代码,但也要注意公共模块重构的难度,它可能变成程序员的火锅杂烩了,而且容易牵一动百,影响系统稳定性。

2011年12月13日 09:24 "@banq"的内容
复杂系统中是可以的,但是注意对象类型太多引起混乱,要注意把握精简原则。 ...

您指的是粒度的粗细吧?一开始我也想到这个问题,比如用户和部门有两个持久化对象,那么是不是也应该有用户和部门两个DTO呢?如果划分成两个,也就是细粒度的划分,这样会导致DTO很多。我觉得划分DTO的学问也挺大的,好像也没看到有专门讨论DTO划分的帖子呀。我个人觉得应该这样划分,还是基于上面的例子,有两种情况的划分:
1:把用户跟部门组成一个DTO
2:用户跟部门单独一个DTO
DTO的划分我建议是粗粒度的,但是像上面的例子肯定行分成两个,因为部门是要进行单独维护的。刚闪过一个念头:是不是可以把聚合根内的组成一个DTO?

2011年12月13日 09:24 "@banq"的内容
很好,关键技术就是行为和贫血的数据对象如何结合问题,建议引入DCI,通过引入场景,将Data和交互行为进行动态结合。 ...

也就是说这种方式行得通,DCI的话有这方面的实例么?研究下先

2011年12月13日 11:09 "@chanball"的内容
DTO的划分我建议是粗粒度的,但是像上面的例子肯定行分成两个,因为部门是要进行单独维护的。刚闪过一个念头:是不是可以把聚合根内的组成一个DTO? ...

建议你参考CQRS + Event Sourcing架构,DTO只是限于查询读操作;写操作是Command 事件和状态,在 CQRS and Event Sourcing, An Alternative Architecture for DDD第一节就指出DTO granularity粒度问题;会有必要大量DTO。我特地标注在下图,下图是现有系统问题图;上图应该重构到的架构CQRS + ES的图。

参考这个帖子:http://www.jdon.com/jivejdon/thread/43486/5#23137891


[该贴被banq于2011-12-13 11:26修改过]



我有点不是很明白,sevice层不写逻辑代码的意思是什么,我现在把逻辑代码都后置到一个或者多个helper类,以便于多个service调用,这样好吗?

看完楼主的帖子后。。。我在想象你们以前的程序是咋弄的。。。

jsp + servlet + jdbc ?

2011年12月17日 11:43 "@lostalien"的内容
看完楼主的帖子后。。。我在想象你们以前的程序是咋弄的。。。

jsp + servlet + jdbc ? ...

你指的以前太广了,以前大家都这么弄,

2011年12月13日 09:24 "@banq"的内容
很好,关键技术就是行为和贫血的数据对象如何结合问题,建议引入DCI,通过引入场景,将Data和交互行为进行动态结合。 ...

DCI这方面的资料好像挺少的,大概这么理解:1.某个角色在某个场景下才会有某种行为,而不是与生俱来的,这时应该将这种行为抽象出来,在特定场景下才注入给角色(打个比方,比如人走路的行为不是一生下来就有的,当差不多到1岁的时候才会走路,所以到“差不多到1岁”这个场景时才把走路的行为注入给人)。2.某个角色与生俱来的行为应该作为该角色的一个行为(比如人一生下来就会睡觉)。

如果按照以上的理解,结合到当前项目的重构工作的话,因为已经确定目前的持久层对象还是保持不变,只是抽象出来一个具有行为的算是半领域对象吧,那么这里其实只是实现了DI而已,C已经被忽略了。上面的第2点也被忽略了,这种做法会不会有问题呢?呵呵,也有可能我对DCI的理解是有误的,希望不吝赐教呀。

另外关于注入的问题,我看一下机器人的例子,如下,以下我标注了一些疑问,希望解答:


public String hello(String id) {
Robot robot = robotRepository.find(id);
//将角色智能机器人IntelligentRole的行为注入到Robot数据对象中
  
//me?:这里我看不出混合有什么意义,直接用 IntelligentRole intelligentRobot = new IntelligentRobot()不也可以么?除非说混合后IntelligentRole的行为里可以直接使用robot(可以使用么?)
IntelligentRole intelligentRobot = (IntelligentRole) roleAssigner.assign(robot, new IntelligentRobot());
//得到一个混和robot将具有听 看 感觉等能力行为
return
"Hello, " + intelligentRobot.hear();
}

data是领域模型,以模型为主,行为是模型的行为,所以要吧把行为注射到模型中,而进行注射的场景就是context

2012年01月01日 15:05 "@banq"的内容
而进行注射的场景就是context ...

大概可以明白了,另一个问题是因为行为跟数据分离开了,但行为肯定是会用到data的,是以方法的参数提供给他么?

刚才我明明回了个帖子,怎么不见了,是被删了还是出bug了,我还道了新年快乐呢,没办法,再道一次:祝J道新年快乐!

2012年01月01日 17:50 "@chanball"的内容
行为肯定是会用到data的,是以方法的参数提供给他么?

刚才我明明回了个帖子,怎么不见了,是被删了还是出bug了,我还道了新年快乐呢,没办法,再道一次:祝J道新年快乐 ...

行为只和角色有关系,不应该用到data model,如果需要用到,也只有在注射后才会用到,用方法参数可以。

bug原因看了一下,发现你没启用浏览器缓存(可能是联通移动设备),致使被误认为爬虫了,呵呵,祝新年快乐。