一个童话故事
从前有一位优秀的软件工程师,他的客户都确切地知道自己的需求。这位优秀的软件工程师努力地工作,并设计了一个完美的系统,这个系统能够解决客户当前和以后的所有问题。当这个完美的系统经过设计、实现和最终部署之后,客户都感到非常高兴。系统的维护工程师无需做任何工作就能让这个完美的系统很好地运行,客户和系统维护工程师从此以后一直快乐地生活着。
为什么现实生活不能像这个童话故事一样呢?
难道是因为没有优秀的工程师吗?难道是客户没有真正了解他们自己的需求吗?或者是因为根本就不存在完美的系统呢?
也许上面所说的都有一点道理,但真正的原因恐怕在于多年以前由Manny Lehman和LesBelady所总结的软件发展的基本规律。这些基本规律中最重要的两点是:
持续变化规律。在一个真实的应用环境中使用的程序,一定是不断被改变的,否则那个应用环境本身就会变得越来越没有用处。
复杂性不断增长的规律。当一个程序不断地发展,它会变得越来越复杂,并需要消耗额外的资源来保持并简化它自己的结构。
换句话说,如果我们认为自己能够了解所有的需求,并能构建完美的系统, 那么就是在自己骗自己。我们所能够做到的最好情况是构建一个有用的系统,并且能够运行足够长的时间,直到需要它做新的工作为止。
本书内容
本书的起因在于充分认识到这样一个事实--软件工程最有意义和最具挑战性的一面不是建立一个新的软件系统,而是重构既有系统。
从1996年11月到1999年12月,我们参加了一个名为FAMOOS的欧洲工业研究项目 (ESPRIT项目21975--掌握面向对象软件发展的基于框架的方法研究,Framework-based Approach forMastering Object-Oriented Software Evolution)。合作伙伴包括Nokia(芬兰)、Daimler-Benz(德国)、Sema Group(西班牙)、Forschungszentrum lnformatik Karlsruhe(德国)和伯尔尼大学(瑞士)。Nokia和Daimler-Benz都是面向对象技术的早期应用者,他们期望从这项研究中获益。目前,他们正面临遗留系统中的许多典型问题:有许多大型的和极有价值的面向对象软件系统,但这些系统很难适应不断变化的需求。FAMOOS项目的目标就是开发新的工具和技术,使这些面向对象的遗留系统恢复生机,从而能够持续发挥作用并更好地适应未来需求的变化。
在项目一开始,我们的思路是将这些大型的、面向对象的应用转换成框架--也就是通用的应用,从而能够使用大量不同的编程技术进行简单的重新配置。但我们很快发现,这件事说起来容易做起来难。尽管这个基本的研究思路听起来不错,但我们却很难决定应该转换遗留系统中的哪一部分以及到底如何转换。实际上,一开始光是理解遗留系统就不是一件很容易的事,更不用说发现其中的错误了(如果有的话)。
我们从这个项目中学到了许多东西。我们首先学到的是,遗留系统的代码并非都是不好的,遗留系统之所以有问题只是因为在原有系统设计和部署之后需求已发生了许多变化。软件系统经常被多次修改以适应变化的需求,系统忍受着设计漂移--初始的体系结构和设计不可能了解未来的所有需求变化,这就导致了不可能对系统进行更多的改进。这一点就像Lehman和Belady所总结的软件发展规律所描述的那样。
研究中最使我们吃惊的是,尽管我们研究的每一个案例都是因为不同原因需要进行软件再工程,例如不再与原系统匹配、需求扩大、移植到新的环境等原因,但所有这些系统所出现的实际问题却都惊人的相似。这就启发我们,可能采用一些简单的技术就能够很好地解决许多相似的问题。
我们发现几乎所有的软件再工程活动都必须从某种反向工程开始,因为你无法信任原有文档(如果你碰巧有一些文档的话)。基本上,你会分析源代码,运行系统,采访用户和开发者,以建立遗留系统的模型。那么你必须确定,要进一步开发并修正系统,存在的障碍在哪里。这是再工程的关键。如果你有足够的先见之明,并且了解所有你今天所知道的新需求,这将帮助你将遗留系统转化为你即将建立的新系统。因为你不可能重建所有的系统,所以必须忽略细枝末节,仅仅再工程最重要的部分。
在FAMOOS项目之后,我们又参加了许多其他软件再工程项目,并将FAMOOS的研究成果进一步加以验证和优化。
本书中总结了我们所掌握的研究成果,希望它能够帮助那些需要对面向对象系统进行软件再工程的人们。我们并不认为我们能够给出解决所有问题的答案,但是我们确实阐明了一系列简单有效的技术,这些技术必将给大家带来很好的帮助。为什么使用模式
模式是一个重复的基调,一个不断重复出现的事件或者程序结构。设计模式是一种通用的解决方案,用来解决重复的设计问题[Gamm95]。由于这些设计问题从来都不是一模一样的--仅仅是非常类似,因此相应的解决方案就不是一段程序,而是能够传达最佳实践的文档。
近年来模式不断在文献中出现,它被用来归档那些解决许多不同问题的最佳实践。尽管许多问题和解决方案都可以通过模式来表述,但如果只应用于简单问题就有点大材小用了。模式作为一种文档描述形式是非常有用和有意义的,它要解决的问题常常是设计上的许多必然的矛盾影响因素,而相应的解决方案则描述了这些必然因素间的权衡。举例来说,很多著名的设计模式都是以增加设计的复杂性为代价来提高系统运行的灵活性。
本书阐述了一系列用来对遗留系统进行软件再工程和反向工程的模式。这些模式都不能盲目地使用。每一个模式解决一些矛盾影响因素,也涉及到某些权衡。理解这些权衡考虑是成功使用模式的基础。因此,模式形式看起来是记录我们最佳实践的最自然的方式,这些最佳实践是我们通过再工程项目所认识到的。
. 一种模式语言是一组相关模式,这些模式可以结合使用以解决一系列复杂问题。我们发现将一些模式组合起来形成模式簇很有用。因此我们是按照模式簇(一个较小的模式语言集合)来组织本书章节的。
我们并不认为本书的模式簇在任何情况下都是"完备的",我们也不认为本书的模式覆盖了软件再工程的所有方面,我们当然也不会认为本书阐述了面向对象软件再工程的系统化方法。我们在本书中所要表达的,仅仅是我们曾遇到和曾采用过的一些最佳实践,这些实践展示出非常有意思的协同作用。这种很强的协同作用不仅包括在每一种模式簇中,而且还包括各个模式簇间以各种重要方式相互关联。因此,书中的每一章都不但包含一个模式图谱--模式图谱阐述了如何将模式作为一种"语言"来实现某种功能,而且每个模式还列出并解释了怎样与其他模式结合或组合,无论这些模式是否在同一个模式簇里。
本书的读者对象
本书主要是献给那些需要实现面向对象系统软件再工程的实践者们。如果从一个极端的观点来看,可以说每一个软件项目都是一个软件再工程项目。因此本书面向的读者群是非常广大的。
我们认为,对任何哪怕只有少许面向对象开发经验的读者来说,本书中的大部分模式都应该是比较熟悉的,本书的目的是阐述实践它们的细节。