1.1 软件开发方法的演进
自从有了软件开发以来,消除重复、提高软件的重用性就一直是我们所追求的一个重要目标,本节将围绕这一主题,带大家重走一遍结构化(SA)、面向对象(OO)与设计模式(Design Pattern)、组件化(Component)、面向方面(AOP)直至面向服务(SOA)这条软件开发技术的发展之路。
20世纪60年代中期开始爆发了众所周知的软件危机。为了度过这一危机,1968、1969年连续召开的两次著名的NATO会议提出了软件工程这一术语,并在以后进行了不断的发展、完善。与此同时,软件研究人员也在不断探索新的软件开发方法,至今已形成8类软件开发方法。
1.1.1 结构化方法SP(Structured Programming)
1.Parnas方法
最早的软件开发方法是由D. Parnas在1972年提出的。由于当时软件在可维护性和可靠性方面存在着严重问题,因此Parnas提出的方法也是针对这两个问题的。他提出了以下两个原则。
● 信息隐蔽原则:在概要设计时列出将来可能发生变化的因素,并在模块划分时将这些因素放到个别模块的内部。这样,在将来由于这些因素变化而需修改软件时,只需修改这些个别的模块,其他模块不受影响。信息隐蔽技术不仅提高了软件的可维护性,而且也避免了错误的蔓延,提高了软件的可靠性。现在信息隐蔽原则已成为软件工程学中的一条重要原则;
● 错误防范原则:即在软件设计时应对可能发生的种种意外故障采取措施。软件是很脆弱的,很可能因为一个微小的错误而引发严重的事故,所以必须加强防范。如在分配使用设备前,应该取设备状态字,检查设备是否正常。此外,模块之间也要加强检查,防止错误蔓延。
Parnas对软件开发提出了深刻的见解,遗憾的是,他没有给出明确的工作流程,所以这一方法不能独立使用,只能作为其他方法的补充。
2.Yourdon方法
1978年,E.Yourdon和L.L.Constan-tine提出了结构化方法,即SASD方法,也可称为面向功能(Function-Oriented Programming)的软件开发方法或面向数据流的软件开发方法。1979年,Tom DeMarco对此方法作了进一步的完善。
Yourdon方法是20世纪80年代使用最广泛的软件开发方法。它首先用结构化分析(SA)对软件进行需求分析,然后用结构化设计(SD)方法进行总体设计,最后进行结构化编程(SP),如图1-1所示。
图1-1 结构化编程过程
这一方法不仅开发步骤明确,SA、SD、SP相辅相成、一气呵成,而且给出了两类典型的软件结构(变换型和事务型),便于参照,使软件开发的成功率大大提高,从而深受软件开发人员的青睐。
1.1.2 面向数据结构的软件开发方法DOP(Data-Oriented Programming)
1.Jackson方法
1975年,M.A.Jackson提出了一类至今仍广泛使用的软件开发方法。这一方法从目标系统的输入、输出数据结构入手,导出程序框架结构,再补充其他细节,就可得到完整的程序结构图。这一方法对输入、输出数据结构明确的中小型系统特别有效,如商业应用中的文件表格处理。该方法也可与其他方法结合,用于模块的详细设计。Jackson方法有时也称为面向数据结构的软件设计方法,如图1-2所示。
图1-2 面向数据结构的过程
2.Warnier方法
1974年,J.D.Warnier提出的软件开发方法与Jackson方法类似。差别有3点:一是它们使用的图形工具不同,分别使用Warnier图和Jackson图;另一个差别是使用的伪码不同;最主要的差别是在构造程序框架时,Warnier方法仅考虑输入数据结构,而Jackson方法不仅考虑输入数据结构,而且还考虑输出数据结构。
1.1.3 面向问题的分析法PAM(Problem Analysis Method)
问题分析法PAM(Problem Analysis Method)是20世纪80年代末由日立公司提出的一种软件开发方法。PAM方法希望能兼顾Yourdon方法、Jackson方法和自底向上的软件开发方法的优点,而避免它们的缺陷。
它的基本思想是:考虑到输入、输出数据结构,指导系统的分解,在系统分析指导下逐步综合。这一方法的具体步骤是:从输入、输出数据结构导出基本处理框;分析这些处理框之间的先后关系;按先后关系逐步综合处理框,直到画出整个系统的PAD图。从上述步骤中可以看出,这一方法在本质上是综合的自底向上的方法,但在逐步综合之前已进行了有目的的分解,这个目的就是充分考虑系统的输入、输出数据结构。
PAM方法的另一个优点是使用PAD图。这是一种二维树形结构图,是到目前为止最好的详细设计表示方法之一,远远优于N-S图和PDL语言。
这一方法在日本较为流行,软件开发的成功率也很高。由于在输入、输出数据结构与整个系统之间同样存在着鸿沟,这一方法仍只适用于中小型问题。
1.1.4 面向对象编程OOP(Object-Oriented Programming)
当前计算机业界最流行的几个单词就是分布式、并行和面向对象这几个术语。由此可以看到面向对象这个概念在当前计算机业界的地位。比如当前流行的两大面向对象,技术DCOM和CORBA就是例子。当然我们实际用到的还是面向对象的编程语言,比如Java、C++。不可否认,面向对象技术是软件技术的一次革命,在软件开发史上具有里程碑的意义。
下面我们就从面向对象的设计方法、语言、设计模式3个方面来了解面向对象的编程思想。
1.面向对象的设计方法
随着OOP(面向对象编程)向OOD(面向对象设计)和OOA(面向对象分析)的发展,最终形成了面向对象的软件开发方法OMT(Object Modelling Technique)。这是一种由自底向上和自顶向下相结合的方法,而且它以对象建模为基础,从而不仅考虑了输入、输出数据结构,实际上也包含了所有对象的数据结构。所以,OMT彻底实现了PAM没有完全实现的目标。不仅如此,OO技术在需求分析、可维护性和可靠性这3 个软件开发的关键环节和质量指标上也有了实质性的突破,彻底地解决了在这些方面存在的严重问题。
1)自底向上的归纳
OMT的第一步是从问题的陈述入手,构造系统模型。即从真实系统导出类的体系,其对象模型包括类的属性,与子类、父类的继承关系,以及类与类之间的关联。类是具有相似属性和行为的一组具体实例(客观对象)的抽象,父类是若干子类的归纳。因此,这是一种自底向上的归纳过程。在自底向上的归纳过程中,为使子类能更合理地继承父类的属性和行为,可能需要自顶向下的修改,从而使整个类体系更加合理。由于这种类体系的构造是从具体到抽象,再从抽象到具体的,符合人类的思维规律,因此能更快、更方便地完成任务。这与自顶向下的Yourdon方法构成鲜明的对照。在Yourdon方法中构造系统模型是最困难的一步,因为自顶向下的“顶”是一个空中楼阁,缺乏坚实的基础,而且功能分解有相当大的任意性,因此需要开发人员有丰富的软件开发经验。而在OMT中,这一工作可由一般开发人员较快地完成。在建立对象模型后,很容易在这一基础上再导出动态模型和功能模型,这3个模型一起构成要求解的系统模型。
2)自顶向下的分解
系统模型建立后的工作就是分解。与Yourdon方法按功能分解不同,在OMT中通常按服务(Service)来分解。服务是具有共同目标的相关功能的集合,如I/O处理、图形处理等。这一步的分解通常很明确,而这些子系统的进一步分解因有较具体的系统模型为依据,也相对容易。所以OMT也具有自顶向下方法的优点,即能有效地控制模块的复杂性,同时也避免了Yourdon方法中功能分解的困难和不确定性。
3)OMT的基础是对象模型
每个对象类由数据结构(属性)和操作(行为)组成,有关的所有数据结构(包括输入、输出数据结构)都成了软件开发的依据。因此Jackson方法和PAM方法中的输入、输出数据结构与整个系统之间的鸿沟在OMT中便不再存在。OMT不仅具有Jackson方法和PAM方法的优点,而且可以应用于大型系统。更重要的是,在Jackson方法和PAM方法中,当它们的出发点——输入、输出数据结构(即系统的边界)发生变化时,整个软件必须推倒重来。但在OMT中,系统边界的改变只是增加或减少一些对象而已,整个系统改动极小。
综上所述,面向对象系统采用了自底向上的归纳、自顶向下的分解的方法,它通过对对象模型的建立,能够真正满足用户的需求,而且系统的可维护性大大改善。当前业界关于面向对象建模的标准是UML(Unified Modeling Language)。
2.面向对象的语言发展
面向对象的发展是从Simula开始的,Smalltalk做了第一个相对完整的实现,而C++是第一个被广泛使用的面向对象语言。面向对象技术的出现是历史发展的必然,而它在未来还会继续发展。
1)Simula
面向对象技术最早是在编程语言Simula中提出的,其作者是Ole-Johan Dahl and Kristen Nygaard。Simula语言是两个语言的统称,即SimulaI和Simula 67(Simula 67是在1967年发布的)。Simula语言是公认的最早的面向对象语言,虽然它的实现并不是很完整,但这是语言发展史上的一个重要的里程碑。
2)Smalltalk
虽然Simula是第一个实现的面向对象语言,但第一个完整实现的面向对象语言一般公认为是Smalltalk语言。Smalltalk是一个支持面向对象、动态类型、类型反射的程序语言,是Alan Kay在Xerox Palo Alto Research Center(PARC)中发明的。Alan Kay设计的系统,Dan Ingalls实现的系统。实现的版本有很多,它们都是在20世纪70年代被开发出来的。第一个版本是Smalltalk-71,Alan Kay在设计的时候,借用了Simula的message passing思想。在Smalltak-76的版本中,加入了inheritance。在Smalltak-80中增加了meteclasses。这实现了一个思想:一切皆对象。Smalltak-80是第一个作为给PARC外界使用的版本,而现今流行的版本,也大多是这个版本的后续版本。
3)C++
在面向对象语言中,C++是第一个被广泛使用的面向对象语言。C++是一个从C语言演化过来的支持面向对象编程的程序语言。Bells实验室的Strustrup在1979年开始了这个跨时代的工作,最开始的版本叫C with Classes,1983年10月份的时候将其正式命名为C++。1990年5月,Borland C++发布了第一个版本,同年6月和11月,Templates和Exceptions被接受。1992年3月,MircorSoft C++发布了第一个版本。相比于Simula和Smalltalk,C++的成功从一定意义上归结于标准组织的建立,以及Borland公司和MicroSoft公司的广泛推广,从而成就了C++在面向对象编程语言中的重要位置。
4)其他版本
在C++之后,影响巨大的就是Java和C#语言了。这两个语言都引入了虚拟机的概念。从另一方面来说,它们也是更纯粹的面向对象语言。因为在C++语言中,没有类也是可以编程的。而在Java和C#语言中,则是不可以的。另外,Java和C#语言都支持丰富的MetaClasses,这使得一切皆对象的概念贯彻得越发深刻。不过,Java中的基础类型在这方面并没有做到也是一大遗憾。虽然如此,Java仍然是一个一直在学习的语言。
5)动态语言
面向对象发展到现今,又出现了一些重大的变革,这就是动态语言的出现。他们也都是支持面向对象技术的,最典型的动态语言有JavaScript、Python、Ruby等。它们的一个重大变化就是,将类的信息改变为动态的,并提出Ducking Type的概念。这在很大程度上提升了编程的生产力。
3.面向对象的设计模式
设计模式(Design Pattern)描述了软件设计过程中某一类常见问题的一般性的解决方案。面向对象设计模式描述了在面向对象设计过程中或特定场景下,类与相互通信的对象之间的常见的组织关系。
面向对象技术很好地解决了软件系统中角色划分的问题。借助于面向对象的分析、设计和技术实现,开发者可以将问题领域的“名词”转换成软件系统中的对象,使用设计模式规范对象间的关系,从而很自然地完成从问题到软件的转换。
1.1.5 面向界面的可视化开发方法
可视化开发是20世纪90年代软件界最大的热点之一。随着图形用户界面的兴起,用户界面在软件系统中所占的比例也越来越大,有的甚至高达60%~70%。产生这一问题的原因是图形界面元素的生成很不方便。
可视化开发就是在可视开发工具提供的图形用户界面上,通过操作界面元素,诸如菜单、按钮、对话框、编辑框、单选框、复选框、列表框和滚动条等,由可视开发工具自动生成应用软件。
这类应用软件的工作方式是事件驱动,即对每一事件,由系统产生相应的消息,再传递给相应的消息响应函数。这些消息响应函数是由可视开发工具在生成软件时自动装入的。
可视开发工具应提供两大类服务:
● 一类是生成图形用户界面及相关的消息响应函数。通常的方法是先生成基本窗口,并在它的外面以图标形式列出所有其他的界面元素,让开发人员挑选后放入窗口的指定位置。在逐一安排界面元素的同时,还可以用鼠标拖动,以使窗口的布局更趋合理;
● 另一类服务是为各种具体的子应用的各个常规执行步骤提供规范窗口,包括对话框、菜单、列表框、组合框、按钮和编辑框等,以供用户挑选。开发工具还应为所有的选择(事件)提供消息响应函数。
可视化开发是软件开发方式上的一场革命,它使软件开发从专业人员的手中解放了出来,对缓解20世纪80年代中后期爆发的应用软件危机有重大作用。
1.1.6 组件化编程CP(Component Programming)
软件组件市场/组件集成方式是一种社会化的软件开发方式,也是软件开发方式上的一次革命,它必将极大地提高软件开发的劳动生产率,并且应用软件开发周期将大大缩短,软件质量将更好,所需开发费用会进一步降低,软件维护也更容易。
最早的组件连接技术OLE 1.0(Object Linking an d Embedding)是Microsoft公司于1990年11月在COMDEX展览会上推出的。OLE 1.0规范发表于1990年12月,之后在1991年2月Microsoft公司推出了第一批支持OLE 1.0规范的应用程序,并在1993年5月发表了OLE 2.0。几个月后,第一批支持OLE 2.0的应用程序也问世了。
软件组件连接的另一个标准是1995年3月推出的OpenDoc。这是由IBM、Apple等公司组成的CI Labs集团使用的标准。由于OpenDoc的编程接口比OLE小,因此OpenDoc的应用程序能与OLE兼容。
第3个组件连接标准是对象管理集团OMG于1991年发表的CORBA(Common Object Reques t Broker Architecture),1994年OMG又发表了CORBA 2.0。
由于OLE 1.0、OLE 2.0的部分功能已放入Windows 3.1中(在推出OLE 2.0的同时,推出Windows 3.1的OLE 2.0),因此目前使用的组件连接开发技术大多基于OLE 2.0。
1.1.7 面向方面编程AOP(Aspect-Oriented Programming)
人们认识到,传统的程序经常表现出一些不能自然地适应单个程序模块或者几个紧密相关的程序模块的行为,例如日志记录、对上下文敏感的错误处理、性能优化,以及设计模式等,我们将这种行为称为“横切关注点(Cross Cutting Concern)”,因为它跨越了给定编程模型中的典型职责界限。如果使用过用于横切关注点的代码,就会知道缺乏模块性所带来的问题。因为横切行为的实现是分散的,开发人员即使发现这种行为也难以作逻辑思维、实现和更改。
因此,面向方面的编程(Aspect Oriented Programming,AOP)应运而生。AOP为开发者提供了一种描述横切关注点的机制,并能够自动将横切关注点织入到面向对象的软件系统中,从而实现横切关注点的模块化。通过划分 Aspect代码,横切关注点变得容易处理。开发者可以在编译时更改、插入或除去系统的Aspect,甚至重用系统的Aspect。
更重要的是,AOP可能对软件开发的过程造成根本性的影响。我们可以想象这样一种情况:OOP只用于表示对象之间的泛化—特化(generalization-specialization)关系(通过继承来表现),而对象之间的横向关联则完全用AOP来表现。这样,很多给对象之间横向关联增加灵活性的设计模式(例如Decorator、Role Object等)将不再必要。
综上所述,今后的软件开发将以OO技术为基础(指用它开发系统软件及软件开发环境),同时与可视化开发、软件组件连接、AOP 3种方式并驾齐驱,它们4个将一起形成软件界新一轮的热点技术。
1.1.8 面向服务架构SOA(Service-Oriented Architecture)
SOA的概念最初由Gartner公司提出,由于当时的技术水平和市场环境尚不具备真正实施SOA的条件,因此当时SOA并未引起人们的广泛关注。后来伴随着互联网的浪潮,越来越多的企业将业务转移到互联网领域,带动了电子商务的蓬勃发展。为了能够将公司的业务打包成独立的、具有很强伸缩性的基于互联网的服务,人们提出了Web服务的概念,这可以说是SOA的发端。
1.SOA的发展
Web服务开始流行以后,在互联网上迅速出现了大量的基于不同平台和语言开发的Web服务组件。为了能够有效地对这些为数众多的组件进行管理,人们迫切需要找到一种新的面向服务的分布式Web计算架构。该架构要能够使这些由不同组织开发的Web服务相互学习和交互,保障安全,以及兼顾复用性和可管理性。由此,人们重新找回了面向服务的架构(Service-Oriented Architecture,SOA),并赋予其时代的特征。需求推动技术进步,正是这种强烈的市场需求,使得SOA再次成为人们关注的焦点。回顾SOA的发展历程,我们将其大致分为了3个阶段,下面将分别介绍每个阶段的重要标准和规范。
1)孕育阶段
这一阶段以XML技术为标志,时间大致从上世纪90年代末到本世纪初。虽然这段时期很少提到SOA,但XML的出现无疑为SOA的兴起奠定了稳固的基石。
可扩展标记语言(Extensible Markup Language,XML)系W3C所创建,源自流行的标准通用标记语言(Standard Generalised Markup Language,SGML),它在上世纪60年代后期就已存在。这种广泛使用的元语言,允许组织定义文档的元数据,以实现企业内部和企业之间的电子数据交换。由于SGML比较复杂,实施成本很高,因此在很长时间里只用于大公司之间,这限制了它的推广和普及。
通过XML,开发人员摆脱了HTML语言的限制,可以将任何文档转换成XML格式,然后跨越互联网协议传输。借助XML转换语言(Extensible Stylesheet Language Transformation,XSLT),接受方可以很容易地解析和抽取XML的数据。这使得企业既能够将数据以一种统一的格式描述和交换,同时又不必负担像SGML那样高的成本。事实上,XML的实施成本几乎和HTML一样。
XML是SOA的基石。XML规定了服务之间及服务内部数据交换的格式和结构。XSD Schemas保障了消息数据的完整性和有效性,而XSLT使得不同的数据表达能够进行Schema映射而互相通信。
2)发轫之初
在2000年以后,人们普遍认识到基于公共—专有互联网之上的电子商务具有极大的发展潜力,因此需要创建一套全新的基于互联网的开放通信框架,以满足企业对电子商务中各分立系统之间通信的要求。于是,人们提出了Web服务的概念,希望通过将企业对外服务封装为基于统一标准的Web服务,以实现异构系统之间的简单交互。这一时期,出现了3个著名的Web服务标准和规范:
● 简单对象访问协议(Simple Object Access Protocal,SOAP);
● Web服务描述语言(Web Services Description Language,WSDL);
● 通用服务发现和集成协议(Universal Discovery Description and Integration,UUDI)。
这3个标准可谓Web服务三剑客,它们极大地推动了Web服务的普及和发展。在短短几年之间,互联网上出现了大量的Web服务,越来越多的网站和公司将其对外服务或业务接口封装成Web服务,有力地推动了电子商务和互联网的发展。Web服务已经成为互联网Web 2.0时代的一项重要特征。
3)成长阶段
从2005 年开始,SOA的推广和普及工作开始加速。不仅专家学者,几乎所有关心软件行业发展的人士都开始把目光投向SOA。一时间,SOA频频出现在各种技术媒体、新产品发布会和技术交流会上。
各大厂商也逐渐放弃成见,通过建立厂商间的协作组织共同努力制定中立的SOA标准。这一努力最重要的成果体现在3个重量级规范上:SCA/SDO/WS-Policy。SCA和SDO构成了SOA编程模型的基础,而WS-Policy则建立了SOA组件之间安全交互的规范。这3个规范的发布,标志着SOA进入了实施阶段。
从整体架构角度看,人们已经把关注点从简单的Web服务拓展到面向服务体系架构的各个方面,包括安全、业务流程和事务处理等。
2.SOA标准集
我们大体上可以把SOA标准分为XML标准集、Web服务标准集和SOA参考模型,下面将分别介绍。为叙述方便,将不再严格区分标准和规范,统一称做标准。
1)XML标准集
2001年10月,W3C发布了XML信息集(XML Information Set,XML Infoset)。
Infoset是一个抽象的数据模型,它兼容基于文本的XML 1.0,也是所有最新XML规范(XML Schema、XML Query和XSLT 2.0)的基础。由于Web服务架构是以XML Infoset为基础,而不是以某一特定的表现形式为基础的,所以使得该架构及其核心协议组件可与各种编码技术兼容。
除了基于纯文本的Infoset编码技术以外,Web服务架构还需要支持另外一种编码技术——即允许不透明的二进制数据与传统的基于文本的标记交织在一起。由于XML Infoset仅支持基于文本的XML,所以W3C于2005 年初又发布了XML二进制优化封装协议(XML-binary Optimized Packaging,XOP)。XOP格式使用MIME将原始二进制数据引入到XML 1.0文档中,而不采用base64编码,并通过其配套规范——SOAP消息(Transmission Optimization Method,MTOM)实现将二进制XOP格式绑定到SOAP上。XOP和MTOM是将原始二进制数据与基于文本的XML混合在一起的首选方法,它们取代了目前普遍遭到反对的SOAP with Attachments(SwA)和WS-Attachments/DIME。
2)Web服务标准集
经过几年的努力,Web服务标准集已经初具规模,内容涵盖了传输层、消息机制、编程模型、服务发现和描述、可靠性、事务处理、安全和管理等方面。尽管其中部分内容还处于规范级别,但由于受到广泛的关注和支持,成为正式标准只是时间上的问题。
3)SOA参考模型
SOA参考模型是由结构化信息标准促进组织制定和发布的。事实上,它并不是一个标准,而是SOA架构的一个抽象框架,它统一了SOA相关术语用法并且定义了这些术语的涵义,同时还明确定义了SOA各组件之间的关系。
SOA最关键的一个特性就是loosely coupled(松耦合),现在相信你应该能够明白为什么这点最为重要了。为了实现异构系统间的集成,服务只有具备了松耦合的特性才能彼此交互。对比我们之前提到的组件技术,它也提供了服务对象的元数据,但是这些元数据的描述是与具体的组件技术相关的,而调用组件中对象的技术也是依赖于某一特定平台的。为了获得松耦合的特性,我们采用了Web Service技术作为SOA的具体实现。其中WSDL用于描述服务的元数据,而SOAP则规定了如何调用服务并返回结果。这些规范都是符合特定标准的,而各个厂家也都将遵循这些标准。这在Java下往往会由EJB中的Session Bean实现,在.NET下可以利用企业服务中的ServicedComponent实现,而在各自的环境下都可以方便地将该对象升级为Web服务。如在JBuilder中可以使用某些菜单项方便地将一个Session Bean发布成一个Web Service,而COM+1.5也提供了SOAP Service的功能,利用它可以非常简单地将一个ServicedComponent以Web Service的形式发布。
由此,我们可以看出SOA较好地解决了应用系统间的重用问题。SOA是一套系统集成的解决方案,它与传统的分布式对象技术的主要区别在于它的松耦合性。