讨论旧系统如何改造成面向OO的?

论坛里一直在讨论如何OO,
如何建模,
如何处理各种情景,那么,当我们面对旧系统,又有什么好办法处理这些问题?

当所有的类都是由关系数据库导出,不是使用组合而是添加了一个又一个字段进行关联.Hibernate成了另一种SQL语句,
这种系统的改造,有没有好的模式可以借鉴?

数据库和对象有着天然阻抗mismatch,是两个不同方向,一个是向南,一个是向北,不可能将完全相左的两个东西整合在一起,或者说水和火难以相容,想让一个以火为主的系统,转向一个以水为主的系统,除非掌握乾坤大挪移,否则没有办法。

我在另外一个帖子:什么是OO思想回帖写道:
OO思想简言之,我们谈的 想的 编的 做的 都是围绕一个个对象 言简意赅,但是做起来很难,实际中我们谈的 想的 编的 做的 都是围绕一个个“数据表”。 这实际就是以什么为中心的问题中心位置的改变带动整个软件业的革命,就象过去国家以阶级斗争为中心转变到以经济建设为中心一样,不可小觑。

所以,要设计一个OO系统,从开始就要OO很重要,是方向问题,方向走错了,就是南辕北辙。所以,我一直反对那些数据库为主导的教育 培训和理论;而实际上这是目前国内软件主导思想。

一旦数据库系统成型,个人认为是没有办法的,只能走组件化设计方向;可参考javascript/AJAX做法,也就是搞一些粒度大一点的模块板块重用,但是这条路实在很难很难。



[该贴被banq于2008-03-29 11:23修改过]

我现在碰到的就是一个使用了Hibernate但却是完全面向数据库设计的一个系统.Action中包含了大量的判断逻辑,Service中拼凑HQL语句,Dao有名无实.
而现在又需要让这个项目有更强的扩展性.
因此,头疼.

>Action中包含了大量的判断逻辑,Service中拼凑HQL语句,Dao有名无实.
典型的面向数据库编程的系统,OO系统应该是:Action只有关于界面显示相关的逻辑,几乎没有业务甚至和数据表相关的代码;Service中不应该有HQL语句,HQL的逻辑组合应该在Domain领域层中实现;由于数据库恶魔从Dao层逃了出来,四处扩散,当然它的老巢就空无一人,Dao也就有名无实了。

这个系统如果重新开始做,应该是这样过程:
1.借助Evans DDD来分析需求,提炼中Domain Model。
2.细化Model和各种组合变种模型,以及他们之间的关系。
3.实现Domain层的Model代码,将业务逻辑在Domain实现。
4.编写Dao持久化Domain Model
5.编写界面Action,提供Domain Model的界面操作。

现在系统已经成型了,由于数据库就象艾滋病菌一样散落在软件的各个部位,要实现完全清除是不可能的,但是不完全清除数据库影子,你的代码中随处可见各种静止的表字段,至于这些字段涉及哪些业务背景和逻辑,是很难一眼就看穿的,所以,你修改这些字段或扩展它们都小心翼翼,因为你不知道这些字段背后隐藏什么操作,有可能你踩上一颗地雷,你维护工作成功了,其他功能出问题了,也就是说:你的系统就很难适应需求变化,就很难扩展新功能,。所以,基本可以肯定你这个系统已经到了艾滋病晚期,无药可救,最多就延长他的寿命。

从这里可以看出,软件方向如果选择错误,就如人的基因有问题,花再多的钱也无法挽救这个软件,硬件倒是可以花钱买到更好的,钱不是万能的,这点同样适合软件。

最近看到新闻说测试工程师是一个热门专业,很难找到人,其实这是一个伪命题,带有欺骗性的,因为软件系统做烂了,走错了方向,就象我上面讲的,维护和扩展A功能成功了,结果B功能因为你修改出错了,从外行项目主管来看,好像这些都是测试的问题,为什么这个软件送到客户之前不进行全部测试一下呢?但是测试工程师抱怨:我怎么可能知道B功能和A功能有关呢?我不可能每次修改,我都要把所有大大小小功能过去两年做的工作在几天内再做完啊。项目主管肯定认为是这个测试工程师在狡辩,不尽质,没有把好最后关口,决定去找高高手来。

看到这里,经常到J道的人可能已经明白,测试工程师只是项目软件设计失败的替罪羊,业界在疯狂呼喊测试工程师,说明他们的设计问题更加严重。

相关贴:HQL的讨论:
http://www.jdon.com/jivejdon/thread/33438.html

EJBQL DSL
http://www.jdon.com/jivejdon/thread/33658.html
[该贴被admin于2008-03-31 19:01修改过]

非常同意banq老师的意见,而现在这个项目,我的处理方式是这样的:

前提:
1.不可能重做.经过评估,公司承受不起三个月重新开发这套系统的代价.
2.不可能封闭需求将系统重构


内容:
因此,我在处理的过程就是要非常小心,因为整个系统的设计很难跟上需求的变化,并且没有单元测试,所以我采用了下面的一些办法:

1.新添加的功能模块,完全使用新的设计思想来做
2.在复杂度不太高的情况下,尽量孤立原有系统的模块,并且也不调用原系统的方式(是尽量不),而是尽量将新的模块重写
3.每一个新版本发布的时候,都考虑在下一个版本中,重写原系统的一个小模块,争取如果有机会,就将系统慢慢调整出来
4.加强单元测试,强制所有可能出问题的地方使用单元测试.
5.与需求部门对着干,争取出时间来对系统进行一小步一小步地更新.

因为这个项目是公司一个比较重要的项目,并且将有一个长期的需求变化过程,因此我想把问题和压力放在最前面.

关于Evans DDD的思维方式,只用在新模块的开发上,而对旧模块的兼容问题,在风险和成本上考虑一个平衡.

暂时我考虑不出更合适的办法,只找到上面说的几个办法.还请banq老师评估一下,是不是还有更合适的思路.

这是一个比较可行的方式,新的用新的方式做,老的再慢慢改,但是实际中,新的不调用老的接口功能几乎是不可能的,这就形成新老系统对接口的依赖。

因为老的系统接口设计都可能是错误的,所以,必须解藕对老系统接口依赖,可以在新老系统之间引入JMS,这样可以实现两者最大程度耦合,实现新系统脱离老系统可完全运行,然后,逐步停止老系统的一些功能,直至全部退休。

banq老师说的对,现在就是发现新系统不调用老系统基本上是不可能的,而我现在的做法是,在时间合适的时候,适当加班重做老系统的部分功能,也可以说,同一个功能,可能有两套代码实现了这方面的功能.也可以说是在慢慢用新方式替代老的方式.

JMS的方式考虑过,但限于开发团队的问题,还有交流,协调的问题,感觉如果引入可能会引入一些问题.因此现在项目中暂时没有引入这方面的技术.

这几天试着在一些最小的模块上进行了这样的开发,发现也引入了一些问题:
一方面是,新模块即使是使用一些方式重写老模块的代码供新模块来调用,但底层数据库却在老模块中包含了大量的业务逻辑,因此很难将这方面抽出来.
另一方面是,现有的系统是正常使用中的系统,我需要迭代地发布新功能.因此,导至软件的使用人员需要适应一些新的东西.

同时,就像banq老师说的,老系统基本上没有接口,就算提供了一些接口,却基本上是错误的.因此,处理这方面现在的确挺困难.暂时还没有比较折中的方案.

有一个小问题,如果我有一些业务对象,都是会员,分别为普能会员,商业会员等等.这些业务对象都是独立的,或者说属性都是不同的.
现在,发现这些对象都需要下面一些东西:注册时间,状态,留言数量等等.那么,是另外建一个类,然后让这些会员的业务对象把这个另外建的类组合进去更好呢,还是抽出一个父类更好呢?

>注册时间,状态,留言数量
这些不属于会员核心属性,是会员的一些业务状态,属于值对象。

现在项目组在对系统进行重构,而更明确地说,就是先将最小的模块进行重写.

是啊 重写也许是一种最好的方式。

最近TSS的一篇 什么时候使用嵌入式对象数据库
When to use an Embedded ODBMS
http://www.theserverside.com/tt/articles/article.tss?l=EmbeddedODBMS

其中也提到面向对象OO和关系数据库是两个方向,是两个不同的世界观。
The reasons why are fairly fundamental in nature, and are summed up in a phrase that has been orbiting the database world for well over a decade: "the object-relational impedance mismatch." Borrowing terminology from the electronics world, this phrase highlights the significant differences between systems built along object-oriented lines, and those built along relational lines. It is not too far off the mark to say that the two paradigms - object-oriented and relational - are two very different world-views.

In an object-oriented system, data lives inside objects. In a relational database, data lives inside rows within tables

所谓嵌入对象数据库,就是在Java/.NET的应用中运行数据库,将数据库作为程序的一个附属持久特性。


到目前为止,系统新添加的所有模块都使用了新的开发模式,并且把过去的一些不太核心的模块都全部重写.
对象与关系的阻抗关系是肯定无法解决了,似乎就是重做!(当然前提是有必要的情况上)

我公司的旧系统是delphi的基于二层的,现在要改成java实现,原系统有很多的视图、存储过程。做过这方面改造的请说明一下如何改造的。

正巧了,去年下半年,我参与了一个FoxPro的项目,用DotNet改造成Web的,没有需求,全靠看FoxPro代码,在Web上还要求界面和操作习惯也类似于原来FoxPro的程序。
那个过程,真的痛苦。
当时,我们使用的方案就是用DotNet大量使用存储过程来解决问题。

JNI不知道能不能胜任。我曾经做过一小块,但也就那一点,不知道在更大的范围应用,性能、结构方面有什么问题。
现在开发的粒度越来越大了,有服务可用当然最好了。