项目架构出了问题

现在项目出现了个很大的问题,由于经验不足,想请教各位

这个项目的架构(其实不能算是架构),是按一个开源的电子商务示例来组织代码的,分了几个层:

common
domain(领域对象)
persistence(dao层)
service(业务逻辑层)
web(前台web项目)
admin(后台web项目)


现在存在的一些问题:

1,service层现在已经非常的庞大,一个类四五千代码,不好管理,而且这里没有很好的抽象,没有

面向接口编程。比如一个OrderService(单例类),把全部的有关订单的操作放在里面,OrderService

组合了一大把dao.

2, 程序发布流程混乱,如果业务简单,功能模块少的情况,这种分层没多大问题。但现在几乎所有有

关电子商务的业务都来了,该架构已经完全不能满足当前的需求,而且束缚了系统的进度,我们现在

把所有的后台管理模块都放在里admin的web项目里,各个模块是完全独立的,最终发布时只能等到最

后完成的模块,才能整体发布。最早完成的模块只能拖。我感觉这很有问题


3,persistence(dao层)的接口定义感觉上是业务接口,如果以后我把Service也抽象出接口的话,这

里感觉会重复。


我的一些想法:

每个独立的模块都是一个解决方案:比如订单模块(包括独立的订单Web项目),商品模块(包括独立

的订单Web项目),基础模块(数据访问层)是这些项目解决方案共享的。这样每个模块都能独立发布
但这么多的web项目,又如何当做一个网站来访问。

以上问题,不知各位有何高招?期待....



[该贴被admin于2009-04-20 08:51修改过]

以下不是针对楼主,有感而发:
这是典型的东施效颦,只学习表面,没有学习皮毛,核心是什么?就是领域建模Evans DDD

你们必须学习DDD,其中告诉你,业务逻辑主要是在领域对象中,服务只是一种管理作用,只是用户web层客户端访问领域模型的桥梁,MVC中controller也可以看成是应用服务,不要在服务中加入业务方法,造成过程编程,使模型成为贫血失血模型。

消灭Dao层,使用Repository来替代。

我想你了解一下Evans DDD,可能你上面的疑惑就会消失。

现在可以重构,将业务方法进行分类,属于服务的留在service,属于领域模型本身的,放入领域模型中。

考察是否需要将代码分布到多台机器部署,如果每个技术层次分布到不同的机器,这样发布的话原先的分层很适合,如果不需要,按概念对象发布模块更好,但重构原先的结构代价太大,不推荐。

服务名称是不是都是在行业术语里找到的提供给用户的操作,如果都能找得到,就不必担心服务太多,它本来就需要这么多,可以通过facade进行分类。

考察服务里有没有本身属于概念对象的职责,尽管实现的不是同一个对象,只要实现的是同一类的对象,也应该把这些操作提取到领域对象里。

考察规格,能够显式描述的都拿出来,配合仓储作业。

我觉的banq说的很对,很多时候,大多数人是在模仿别人的分层架构,真正核心的东西却没有掌握,可想而知结果跟“东施效颦”一样。

加入这个项目前,项目的代码架构早已搭建好了,开始的时候还感觉不到有什么问题,到现在问题越积越多。感觉有点举步维艰。DDD很久之前就接触过,看过不少资料,包括JiveJdon代码,触动很大,于是在同事间推广,但有人说“要脚踏实地,目前我们的开发模式是最流行可行的”。


DDD,要很强的面向对象功底,况且光一人很难在团队里实施,这个很难解决的。

如果现在重构确实代价很高。

其实我觉得出现这样的问题,一定是分析错了,分析错了那么即使重构也不能有很大的改观,除非换一种分析方案.小弟在下面将举例两种分析方案的不同,您可能有是曾相识的感觉.

就以Jdon论坛为例.A为客户,B为设计人员
第一种分析方案: 现有对象 ForumMessage.ForumMessageService
1A:我想发表消息Message以及删除Message
2B:这很简单,我们可以通过Service添加行或删除行来实现
3A:当Message已经被回复时,我们是不希望用户更改Message的,如果用户随意更改,那将会很混乱.而对于管理员我希望具有此功能.
4B:这个很简单,通过对Message增加判断是否被回复的属性,在进行修改时,只需要很简单的进行属性判断就可以实现您的期望.
5A:我还想知道最近发表的Message,以了解人们现在对什么话题最感兴趣.
6B:没问题,利用sql语句便可以办到.

最明显效果:
第3行所述的功能中,可以通过在service层进行判断是否是管理员和是否有回复进行解决.
第6行所述功能,可以通过在service中写查询最近消息的SQL语句进行解决.SQL语句可能有service层产生,也可能由特定的DAO接口产生.

第2种分析方案:现有对象ForumMessage,ForumMessageService
1A:我想发表消息Message以及删除Message
2B:这很简单,Service就具有这样的行为,它能够帮助我们解决。
3A:当Message已经被回复时,我们是不希望用户更改Message的,如果用户随意更改,那将会很混乱.而对于管理员我希望具有此功能.
4B:哦,您的会有多重的管理员吗?
5A:这就不太清楚了,我想以后会有吧.
6B:这样啊,我们引入一个叫Specifiaction的对象来解决这个问题.
7A:我还想知道最近发表的Message,以了解人们现在对什么话题最感兴趣.
8B:恩,我们通过引入一个叫SpecificMessageRecord,它知道人们现在对什么话题最感兴趣.

最明显效果:
第6行,发现需求可能会变更,引入一个规格来维护业务规则,当业务规则改变时,规格能够从容的面对.
第8行,以对象的风格来封装最近发表的Message,比用Service+sql语句来的更加内聚.

两者比较:
1方案已经遗漏了一些重要的业务规则,而这也业务规则通常是会变化的。2方案通过引入DDD中的规格检查便能轻松的面对变化,同时也将零散的业务规则用对象的方式进行封装。
1方案使用特定的SQL语句来解决最近消息记录,然而这样的方式使得模型表现效果不是很完善,客户的需求是根据特定的技术来解决的而不是领域,这会让我们付出一定的代价,当需求变更的时候. 但有时候使用这样的特定查询方式,往往又能达到效果.


需求变更设想:
A:我想知道最近发表的在一定的时间内消息回复量达到5时,进行置顶。还有在一天内Banq在此message进行3次回复时,想将此消息一红色效果显示,同时置顶;这样人们便能够轻松的找到并阅读人们最近最感兴趣的话题.
1方案应对措施:哇?嘿嘿,难不倒我,利用我在SQL语句的天分,能轻松解决此问题,您稍后.
2方案应对措施:SpecificMessageRecord能轻松的应对客户所提需求.

不同的分析方案得到了不同的领域模型,同时也对应着不同的解决方案,解决方案的不同,应对需求变化的能力也就不同.

小弟最近疲于找工作,深感求职难,几次面试都不成功(应届毕业生).闲暇之余思索面向对象的实施方式,以上分析难免片面或有所错误,望您指点一二、同时让小弟欣赏您的OO方案。

3,persistence(dao层)的接口定义感觉上是业务接口,

是否真的把DAO和SERVICE 分离开了.严格来说DAO应该只负责提供一个可以使用的领域对象,比如拿登陆来说 , dao的设计是 LoginUser getUser(String username)

service层应该是 String login (String username,String password)调用DAO的方法进行用户登录,不知道为什么刚才看楼主说你们DAO还会处理业务逻辑的,如果是这样的话,那每个DAO方法都有可能被固定的业务逻辑给定死,导致DAO代码的重复.

同时我觉得真对于不同的系统有些架构需要做一定的调整,不能千篇一律,对于复杂的业务逻辑可以通过找到共通点定义模组,把功能细分一下,如果每个都按照流程直接实现SERVICE代码量庞大是必然的.

曾经,尝试过用DDD来重构项目的产品模块,我的做法是Repository包装Dao,Repository接口完全是跟业务有关的,最后发现,单一个产品模块没法实施,还有订单模块,促销模块,这些其实组成了项目的领域核心,单独一个模块是不可能用DDD的,最终宣告失败。

正如书中所述,整个项目有个领域核心,难就难在怎么抓住这个核心。我们建模,其实就是在对系统本质规律的一种探索. 模型越是接近系统本质,那么系统再怎么变化,它也脱离不了本质.当然这是一种理想状态.


我觉得模型变化应该分为两个方面看:

第一,是模型与业务领域概念(实体),如Order,的吻合程度。当模型越接近业务领域本质,变化越少。

第二,是模型中包含的业务逻辑,如CheckOut,的变化。这类变化是不能避免的,是随着业务变化而变化。

因此,无论是哪种建模方式,一个重要目的是:当业务逻辑改变时,能快速响应该改变,并将对系统的影响减到最少。

楼主是不是可以考虑用portal? 两个月前,我们现在的项目重构到Liferay上面。虽然还有小的问题,但总体上说,各业务模块可以打包成一个war文件,单独部署,感觉方便了很多。

尝试从楼主的项目中发现问题:

团队没有遵循一个一致的架构,没有一个强力(不是强势)的项目控制监督的角色,做着做着,架构就散掉了。

前期需求分析,以及设计阶段并没有满足扩展的需要,说实话,可能由于经验所限,很多功能不可能未卜先知。这样做下来,随着需求的不断扩展,自然就破坏了原有的架构。这在很多实际的开发中是经常遇到的问题。

我们要明确,架构是可以不断调整的,但这种调整必须建立在高效的代码之上的。那如何产生高效的代码,是当前的重中之重。

我觉得对这样一个团队最务实的不是未卜先知做出精巧的架构设计,而是反躬自省的进行代码重构,让新的功能在可控的没有坏味道的代码上继续扩展。建议不定期的进行代码复审,重构代码,以及架构。

总体来说,我个人觉得你们的问题在于团队开发过程的控制与管理。架构设计需要经验积累,对于团队开发,问题取决于短板,我们最务实的就是对短板所涉及到代码进行不间断的维护,使之有利于扩展的需要。这种频繁的重构与整合,也是一种渐渐统一认识,消除分歧,沉淀架构的过程。

其实,说来说去,我是表达出了极限开发的一些基本要求。

将service看成业务层是完全错误观点,service只是业务层对外的一个接口,就象人的皮肤与外界接触一样,但是人有内脏大脑更多更重要的业务核心。

现在很多人学习Java,不是从OO设计基础开始,而是直接从框架开始,结果就造成了本末倒置,再好的框架也是搞出面向过程编程,把service当作过程功能类来写。

过去大家是把Jsp当成过程功能类写,后来有了MVC,大家就在Controller中写入大量代码,把控制器当作过程功能类写;后来有了多层架构的框架EJB,大家就把无态Bean当作过程功能类来写,业务都在会话Bean中;后来有了所谓EJB颠覆者Spring,大家又把service类当作过程化业务功能类来写。

这些轨迹都可以从jdon一系列帖子看出,你说程序员号称是聪明的人,为什么老是在范同样的错误?问题的根结在哪里?

很显然,每个程序员软件知识结构缺少一个重要一环,OO基础知识,没有这个基础,再聪明的人拿了最先进的技术,也是误用,这个就是证明。

我在Jdon已经婆口苦心唠叨那么多年,甚至喊出数据库已死,OO为王,J2SE不是基础,算法数据结构不是基础,OO才是基础,但是很多人置若罔闻,甚至反感,真是值得每个人反思啊,大家说我图什么啊?实在看不惯每年相同愚蠢不断重演。

http://www.jdon.com/jivejdon/thread/35989.html

to:youway
我们目前的情况,正如你所说,架构一直没有根据后面的业务进行重构

to:banq

经历过的项目都是这样的,其实很多人都想OO,一是环境所致,二是能力所致

服务service的作用,如图ddd中防腐层,服务只是与客户端打交道的一个皮肤,防腐层,SOA本质也是如此,SOA不能用来实现业务逻辑的。



[该贴被banq于2009-04-20 15:53修改过]


可惜banq大哥的苦心,这么多年一直在做普及ddd的工作
其实这场智能ui(ddd里所批判的反模式)vs OO的大战已经不是开始一天两天了
个人觉得应该强调一点:软件的核心是模型,也就是一个一个相互关联,高度聚合的java对象网通过这张网来处理信息流入流出,把核心信息处理的责任既不下放给数据库,也不上放给应用层,牢牢地把责任留在这张对象网上面,这才是面向对象

本人也觉得现在很多SSH是只学习表面,没有学习皮毛,把DAO与service乱用,说搞分层,结果每个层都有可能会用到业务逻辑,把service用来封装业务,结果搞得不伦不类!

banq老师提倡的是软件架构,如同盖房子,要重视设计一样!
算法就像是房子里面的一个组成部分,比如直接的土石堆砌,和混凝土浇注,可以看成不同的实现,但是如果一栋楼的设计出了问题,哪怕你耗巨资全部都用钢铁搭建,这栋楼也会很容易塌陷的!!!看看网上说的那些国外失败的大桥设计和用料吧!!!
banq老师,俺们支持你!!!!
当然,有了稳固的设计和高效的算法,会让我们的系统变得更好!!!