作者:Roy Thomas Fielding
译者:李锟
论文摘要
Web(万维网,英文全称World Wide Web,简称Web)的成功,很大程度上是因为其软件架构的设计满足了拥有互联网规模(Internet-scale)的分布式超媒体系统的需求。在过去10年间,通过对定义Web架构的规范所做的一系列修改,Web以迭代的方式不断地发展着。为了识别出Web需要改善的那些方面,并且避免对其进行不必要的修改,需要一种现代的Web架构模型,用来指导Web的设计、定义和部署。
软件架构方面的研究探索的是如何以最佳的方式划分一个系统、如何标识组件、组件之间如何通信、信息如何表达、系统中的元素如何独立地进化,以及上述所有内容如何使用形式化的和非形式化的符号加以描述。我所做工作的动机是希望理解和评估基于网络应用软件的架构设计(the architectural design of network-based application software),通过有原则地使用架构约束,从而从架构中获得所期待的功能、性能和社交三方面的属性。一种架构风格是一组已命名的、相互协作的架构约束。
这篇论文定义了一个框架,它致力于通过架构风格来理解软件架构,它还展示了如何使用架构风格来指导基于网络应用的架构设计。本文对基于网络应用的架构风格做了一番调查,根据不同的架构风格在为分布式超媒体(distributed hypermedia)设计的架构中产生的架构属性,来对这些架构风格进行分类。然后我介绍了REST(表述性状态移交,英文全称Representational State Transfer,简称REST)架构风格,并且描述了如何使用REST来指导现代Web架构的设计和开发。
REST强调组件交互的可伸缩性、接口的通用性、组件的独立部署、以及用来减少交互延迟、增强安全性、封装遗留系统的中间组件(intermediary components)。我描述了指导REST的软件工程原则和为支持这些原则而选择的交互约束,并将它们与其他架构风格的约束进行了对比。最后,我描述了从把REST应用于HTTP(超文本移交协议)和URI(统一资源标识符)两个规范,并进一步将这两个规范部署到Web客户端和服务器软件的过程中学习到的经验教训。
绪论
抱歉……您说的难道是“屠宰刀”?——摘自《建筑师讽刺剧》(The Architects Sketch)
正如Perry和Wolf的预言,软件架构成为了20世纪90年代软件工程研究的焦点。由于现代软件系统的复杂性,更加有必要强调组件化的系统,其实现被划分为独立的组件,这些组件通过相互通信来执行想要完成的任务。软件架构方面的研究探索的是如何以最佳的方式划分一个系统、如何标识组件、组件之间如何通信、信息如何表达、组成系统的元素如何独立地进化,以及上述所有内容如何使用形式化的和非形式化的符号加以描述。
一个优秀的架构并非是靠凭空想象得到的。每一个架构级的设计决策,都应该是根据被设计系统的功能、行为和社交三方面的需求而作出的。这是一个基本的设计原则,既适用于软件架构领域,同样也适用于传统的建筑架构领域。“形式追随功能”的指导方针来自于从数百年失败的建筑项目中获得的经验,但是它却常常被软件从业者们所忽视。上面引用的那句滑稽搞笑的话来自于Monty Python系列讽刺剧,这句话表达的是当一位建筑师在面对设计一个城市住宅区的目标时,头脑里所抱有的荒诞想法。他想要使用所有现代屠宰场的组成部分来完成这个设计!这也许是他所构思过的最棒的屠宰场,但是对于预期的居民来说却谈不上舒适,因为他们将不得不战战兢兢地行穿行在安装着旋转式屠宰刀的走廊中。
《建筑师讽刺剧》里的夸张说法也许看似荒唐可笑,但是考虑到我们是如此频繁地看到软件项目一开始就采用最新最时髦的架构设计,到了后来却发现满足系统的需求实际上并不需要这样一种架构。design-by-buzzword(按照时髦的词汇来做设计)是一种常见的现象。至少在软件行业中,出现很多此类行为是由于设计者并不理解为何(why)一组特定的架构约束是有用的。换句话说,当选择那些优秀的软件架构来使用时,它们背后的推理过程(reasoning),对于设计者来说并非是显而易见的。
这篇论文探索了在计算机科学的两个研究学科(软件和网络)边界上的交汇点。软件方面的研究长期以来关注于对软件设计进行分类和开发设计方法学,但是却很少能够客观地评估不同的设计选择对于系统行为的影响。网络方面的研究则恰恰相反,聚焦于系统之间普通通信行为的细节和提高特殊通信技术的性能,却常常忽略了一个事实,即改变一个应用的交互风格(the interaction style)对于性能产生的影响要比改变交互所使用的通信协议更大。我的工作的动机是希望理解和评估基于网络应用的架构设计,通过有原则地使用架构约束,从而从架构中获得所期待的功能、性能和社交三方面的属性。当为一组相互协作的架构约束取了一个名字之后,这组架构约束就成为了一种架构风格。
这篇论文的前三章定义了一个通过架构风格来理解软件架构的框架,展示了如何使用架构风格来指导基于网络应用软件的架构设计。当将常见的架构风格应用于基于网络的超媒体系统(network-based hypermedia)的架构设计时,将会产生一系列架构属性,根据这些架构属性对架构风格进行调查和分类,然后使用得到的分类来识别出一组能够改善早期Web架构的架构约束。
如同我们在第4章中所讨论的,设计Web的架构就必须要理解Web的需求。Web旨在成为一个互联网规模(Internet-scale)的分布式超媒体系统,这意味着它的内涵远远超越了单纯的地理上的分布。互联网是跨越组织边界互相连接的信息网络。信息服务的提供商必须有能力满足无法控制的可伸缩性(anarchic scalability)和软件组件的独立部署(the independent deployment of software components)两方面的要求。通过将动作控件(action controls)内嵌在从远程站点获取到的信息表述之中,分布式超媒体为访问服务提供了一种统一的方法。因此Web的架构必须在如下环境中进行设计,即跨越高延迟的网络和多个可信任的边界,以大粒度的(large-grain)的数据对象进行通信。
第5章介绍并详细描述了为分布式超媒体系统设计的REST(表述性状态移交)架构风格。REST提供了一组架构约束,当作为一个整体来应用时,强调组件交互的可伸缩性、接口的通用性、组件的独立部署、以及用来减少交互延迟、增强安全性、封装遗留系统的中间组件。我描述了指导REST的软件工程原则和为支持这些原则而选择的交互约束,并将它们与其他架构风格的约束进行了对比。
如同第6章中所展示的那样,在过去的6年间,我们使用REST架构风格来指导现代Web架构(译者注:与“早期Web架构”相对应)的设计和开发。这个工作是与我所创作的HTTP(超文本移交协议)和URI(统一资源标识符)两个互联网规范共同完成的,这两个规范定义了在Web上进行交互的所有组件所使用的通用接口。
就像大多数真实世界中的系统一样,并非所有已部署的Web架构组件都服从于其架构设计中所给出的每一个约束。REST既可以被用作定义架构改进的方法,也可以被用作识别架构不匹配(architectural mismatches)的方法。当由于无知或者疏忽,一个软件实现以违反架构约束的方式来部署时,就会发生架构不匹配。尽管往往无法避免架构不匹配,但是有可能在它们成为正式规范之前识别出它们。第6章中总结了几种在现代Web架构中的不匹配情况,并且对它们为何会出现和它们如何背离REST进行了分析。
概括来说,这篇论文对于互联网和计算机科学领域的软件研究作出了如下贡献:
- 定义了一个通过架构风格来理解软件架构的框架,包括一组自恰的术语,用来描述软件架构;
- 通过当某种架构风格被应用于一个为分布式超媒体系统(distributed hypermedia systems)设计的架构时,将会产生的架构属性,来对基于网络应用软件的架构风格进行分类。
- 描述了REST——一种为分布式超媒体系统设计的新型架构风格;以及
- 在设计和部署现代Web架构的过程中,应用和评估REST架构风格。
第1章 软件架构
尽管软件架构的研究领域吸引了很多人的兴趣,但是对于在架构的定义中应该包含什么,研究者们几乎从未达成过共识。在很多情况下,这导致了在过去的研究中忽视了架构设计的一些重要方面。在本章中,以检查文献中现有的定义和我自己在基于网络应用的架构方面的领悟为基础,定义了一套自恰的软件架构术语。每一个定义都使用方框突出显示,随后讨论该定义是如何得来的,或者与相关研究进行比较。
1.1 运行时抽象(Run-time Abstraction)
软件架构是一个软件系统在其运行过程中某个阶段的运行时元素(run-time elements)的抽象。一个系统可能由很多层抽象和很多个运行阶段组成,每一个抽象和运行阶段都有自己的软件架构。
软件架构的核心是抽象原则:通过封装来隐藏系统的一些细节,从而更好地识别和支持系统的架构属性[注释]。一个复杂的系统会包含有多层抽象,每一层抽象都有自己的架构。架构代表了在某个层次上系统行为的抽象,架构元素(architectural elements)可以通过自身提供给同一层其他元素的抽象接口来描述[注释]。在每一个架构元素之中,可能还存在着另一个架构,由其定义由其众多子元素构成的系统,该系统实现了由父元素的抽象接口所展示的行为。这样的架构可以递归下去直到最基本的系统元素:不能再被分解为抽象层次更低的元素。
除了架构的层次,软件系统通常会有多个运行阶段,例如启动、初始化、正常处理、重新初始化和停止。每个运行阶段都有自己的架构。例如,配置文件在启动阶段会被当作架构的一个数据元素来处理,但是在正常处理阶段不会被当作一个架构元素,因为在这个阶段配置文件中的信息已经分布到了整个系统之中。事实上,也可以用配置文件来定义正常处理阶段的架构。系统架构的整体描述必须既能够描述各个阶段的系统架构的行为,也能够描述在各个阶段之间的架构的迁移。
Perry和Wolf[注释]将处理元素定义为“数据的转换”(transformers of data),而Shaw等人[注释]将组件描述为“计算和状态的所在地”(the locus of computation and state)。Shaw和Clements[注释]进一步指出:“组件是在运行时执行某种功能的软件单元。这样的例子有程序、对象、进程、过滤器。”这引出了软件架构(software architecture)和通常所说的软件结构(software structure)之间的一个重要区别:软件架构是软件系统在运行时的抽象,而软件结构则是静态源代码的属性。将源代码的模块结构与正在运行的系统中的行为部件对应起来,以及使用相同的代码部分(例如共享库)来实现独立的软件组件,尽管这些做法确实有很多好处,然而我们将软件的架构和源代码结构分离开是为了更好地关注软件在运行时的特性,这些特性并不依赖于某个特定的组件实现。因此,尽管架构的设计和源代码结构的设计关系密切,它们其实是相互分离的设计活动。不幸的是,有些软件架构的描述并没有明确指出这个区别(例如[注释])。
1.2 架构元素(Elements)
软件架构是由一些架构元素(组件、连接器和数据)的配置来定义的,这些元素之间的关系受到约束,以获得所期待的一组架构属性。
Perry和Wolf[注释]对软件架构的范围和知识基础进行了全面的检查,他们提出了一个模型,将软件架构定义为一组特定形式(form)的架构元素(elements),并通过一组基本原理(rationale)来描述。架构元素包括处理元素、数据元素、连接元素,其形式由元素的属性和元素之间的关系(即元素之上的约束)来定义。通过捕获选择架构风格、以及选择架构元素和形式的动机,这些基本原理为架构提供了底层的基础。
我的软件架构定义建立在Perry和Wolf[注释]的模型基础之上,是一个更加详尽的版本,但是没有包括基本原理的部分。尽管基本原理是软件架构研究中很重要的一个方面,尤其是在对于架构的描述方面,但是将它包括在软件架构的定义中,将会暗示设计文档是运行时系统的一部分。是否包括基本原理,确实能够影响一个架构的开发,但是架构一旦建成,它将脱离其所基于的基本原理而独立存在。反射型的系统(reflective systems)[注释]能够根据过去的性能改变今后的行为,但是这样做是用一个低层次的架构替换另一个低层次的架构,而不是将基本原理包括在那些架构之中。
用一个类比来做说明,想象一下,当一个大楼的蓝图和设计计划被烧毁了将会发生什么事情?大楼会瞬间倒塌么?不会的,因为支撑着屋顶重量的墙体仍然完好无损。按照设计,一个架构会拥有一组架构属性,允许该架构满足甚至超出系统的需求。忽视这些架构属性,在将来的改造中可能会违反架构的约束,这就好像用一面大型窗户取代承重墙会破坏大楼结构的稳定性一样。所以,我们的软件架构定义中没有包括基本原理,而是包括了架构属性。基本原理详细说明了这些架构属性,缺少基本原理可能会导致架构随时间的推移而逐渐退化,但是基本原理本身并不是架构的一部分。
Perry和Wolf[注释]的模型中的一个关键特征是不同类型的元素之间的区别。处理元素(processing elements)是执行数据转换的元素,数据元素(data elements)是包含被使用和被转换的信息的元素,连接元素(connecting elements)是将架构的不同部分结合在一起的粘合剂。我将使用更加流行的术语:组件(components)和连接器(connectors)来分别表示处理元素和连接元素。
Garlan和Shaw[注释]将系统的架构描述为一些计算组件和这些组件之间的交互(连接器)。这一模型是对于Shaw等人的模型[注释]的扩展,按照一些组件和这些组件之间的交互来定义一个软件系统的架构。除了指出了系统的结构和拓扑以外,架构还展示了期望实现的系统需求和构建系统的元素之间的对应关系。更加详细的定义可以在Shaw和Garlan[注释]的文章中找到。
在Shaw等人的模型中,令人惊讶之处是他们将软件架构的描述当作成是架构本身,而不是将软件的架构定义为存在于软件之中。在这个过程中,软件架构被简化为通常在大多数非形式化的架构图中能够看到的东西:方框(组件)和直线(连接器),而数据元素和其他很多真实软件架构的动态方面都被忽略了。这样的一个模型不足以描述基于网络应用软件的架构,因为对于这类软件而言,数据元素在系统中的特性、位置和移动,常常是系统行为唯一的和最重要的决定因素(the single most significant determinant)。
1.2.1 组件(Components)
组件是软件指令和内部状态的抽象单元,通过其接口提供数据的转换能力。
在软件架构中,组件是最容易被识别出来的方面。在Perry和Wolf[注释]的定义中,处理元素被定义为:提供对于数据元素的转换的组件。Garlan和Shaw[注释]将组件简单描述为:执行计算的元素。我们的定义试图更加精确地将组件和位于连接器中的软件(software within connectors)区分开来。
组件是软件指令和内部状态的抽象单元,通过其接口提供数据的转换能力。数据转换的例子包括从二级存储将数据加载到内存、执行一些计算、转换为另外一种格式、封装在其他数据之中等等。每个组件的行为是架构的一部分,能够被其他组件观察到(observed)或辨别出来(discerned)[注释]。换句话说,应该由某个组件为其他组件提供的接口和服务来定义该组件,而不是由隐藏在该组件提供的接口之后的实现来定义。Parnas[注释]将此定义为:其他架构元素能够对该组件作出的一组假设。
1.2.2 连接器(Connectors)
连接器是对于组件之间的通讯、配合或者协作进行中间斡旋的一种抽象机制。
Perry和Wolf[注释]将连接元素模糊地描述为:将架构的不同部分结合在一起的粘合剂。Shaw和Clements[注释]提供了一个更加精确的定义:连接器是对于组件之间的通讯、配合或者协作进行中间斡旋的一种抽象机制。连接器的示例有:共享的表述、远程过程调用、消息传递协议和数据流。
也许理解连接器的最佳方式是将它们与组件加以对比。连接器将数据元素从它的一个接口移交(transferring)到另一个接口而不改变数据,以此来支持组件之间的通信。在其内部,连接器可以包含一个由组件组成的子系统,为了移交的目的对数据进行某种转换、执行移交、然后做相反的转换并交付与原始数据相同的结果。然而,在架构所能捕获到的外部行为抽象中,可以忽略这些细节。与之相反,从外部的角度观察,组件可以(尽管并非总会这样)对数据进行转换。
1.2.3 数据(Data)
数据是组件通过连接器接收或发送的信息元素。
上面已经提到,是否包含数据元素是Perry和Wolf[注释]所提出的模型与大多数其他软件架构研究所提出的模型[1,5,9,53,56,117-122,128]之间的最大区别。Boasson[注释]批评当前的软件架构研究过于强调组件的结构和架构开发工具,他建议应该把注意力更多地放在以数据为中心的架构建模上面。Jackson[注释]也有相似的观点。
数据是组件通过连接器接收或发送的信息元素。数据的示例有:字节序列、消息、编码过的参数、以及序列化过的对象,但是不包括那些永久驻留或隐藏在组件中的信息。从架构的角度来说,一个“文件”其实是一种转换,即文件系统组件从其接口接收到“文件名”数据,并将其转换为记录在(隐藏的)内部存储系统中的字节序列。组件也能够生成数据,例如与一个时钟或传感器相对应的软件封装。
在基于网络应用的架构中,数据元素的特性往往决定了一种特定的架构风格是否适用。在对移动代码设计范例(mobile code design paradigms)的比较中[注释]尤其明显,在这里你必须要在两种架构风格中做出选择:是直接与组件进行交互;还是将组件转换为一个数据元素,通过网络移交该数据元素,然后再对该数据元素做相反的转换,得到一个能够在本地与之交互的组件。如果不在架构层面上考虑数据元素,是不可能对架构做出评估的。
1.3 配置(Configurations)
配置是在系统运行期间的组件、连接器和数据之间的架构关系的结构。
Abowd等人[注释]将架构的描述定义为:支持根据三个基本的语义分类来对系统进行描述。这三个语义分类是:组件——计算的所在地;连接器——定义组件之间的交互;配置——相互交互的组件和连接器的集合。可以使用多种与特定架构风格相关的形象化符号来可视化地展示这些概念,以便于描述合法的计算和交互,以及所期待的系统约束。
严格来说,你可能会认为一个配置等价于一组组件交互之上的特定约束。例如,Perry和Wolf[注释]在他们的架构形式关系(architectural form ralationships)的定义中包括了拓扑。然而,将主动的拓扑与更加通用的约束分离开,使得架构师更容易区分主动的配置与所有合法配置可能会影响的领域。Medvidovic和Taylor[注释]提出了额外基本原理(additional rationale),用来在架构描述语言中区分出配置相关的内容。
1.4 架构属性(Properties)
软件架构的架构属性集合包括了对组件、连接器和数据的选择和排列所产生的
所有属性。架构属性的例子包括了由系统获得的功能属性(functional properties achieved by the system)以及非功能属性(例如,进化的容易程度、组件的可重用性、效率、动态扩展能力,这些常常被称作品质属性)(quality attributes)[注释]。
架构属性是由架构中的一组架构约束所产生的。架构约束往往是由在架构元素的某个方面应用软件工程原则[注释]来驱动的。例如,统一管道和过滤器(uniform pipe-and-filter)架构风格通过在其组件接口之上应用通用性(generality)原则——强迫组件实现单一的接口类型,从应用中获得了组件的可重用性和可配置性的品质。因此,架构约束是由通用性原则所驱动的“统一组件接口”,目的是获得上述两个所期待的品质,当在架构中实现了这种架构风格时,这两个品质就成为了可重用和可配置组件的架构属性。
架构设计的目标是创建一个包含一组架构属性的架构,这些架构属性形成了系统需求的一个超集。不同架构属性的相对重要性,取决于所期待的系统本身的特性。在2.3节检查了那些对于基于网络应用的架构特别重要的架构属性。
1.5 架构风格(Styles)
架构风格是一组相互协作的架构约束,这些架构约束限制了架构元素的角色和功能,以及在任何一个遵循该架构风格的架构中允许存在的元素之间的关系。
因为一种架构既包含功能属性又包含非功能属性,直接比较不同类型的系统的架构,或者甚至比较在不同环境中的相同类型系统的架构,都会比较困难。架构风格是一种机制,用来对架构进行分类并且定义它们的公共特征[注释]。每一种架构风格都为组件的交互提供了一种抽象,并且通过忽略架构中其余部分的偶然性细节,来捕获一种交互模式(pattern of interation)的本质特征[注释]。
Perry和Wolf[注释]将架构风格定义为:对于各种架构元素类型(element types)的抽象和多个特定架构的形式化方面(formal aspects,也许仅仅集中在架构的一些特定方面,而不是架构的所有方面)。一种架构风格封装了关于架构元素的重要决策,强调对于元素和它们之间的关系的重要约束。这个定义允许架构风格仅仅聚焦于架构的连接器,或者组件接口的一些特定方面。
与之相反,Garlan和Shaw[注释]、Garlan等人[注释]、Shaw和Clements[注释]都根据各种类型的组件之间的交互模式来定义架构风格。明确地说,一种架构风格决定了在此架构风格的架构实例中能够使用哪些组件和连接器,以及一组能够将它们组合在一起的约束[注释]。对于架构风格的这种狭隘观点,是他们的软件架构定义的直接结果——即,将架构看作是形式化的描述,而不是正在运行的系统,这就导致了他们仅仅基于从包含方框和直线的图中总结出来的共享模式(shared patterns)来进行抽象。Abowd等人[注释]更进一步,将架构风格明确定义为:用来解释一类架构描述(architectural descriptions)的一个约定的集合(collection of conventions)。
新的架构能够被定义为特定架构风格的实例(instances)[注释]。因为架构风格可以强调软件架构的不同方面,一个特定的架构可能是由多种架构风格组成的。同样地,可以通过将多种基本架构风格组合为单个协作式架构风格(coordinated style),来形成一种混合的架构风格。
一些架构风格常常被描述为适合于所有形式软件的“银弹”式解决方案。然而,一个好的设计者应该选择一种与正在解决的特定问题最为匹配的架构风格[注释]。为一个基于网络应用选择正确的架构风格,必须要理解该应用所属的问题领域[注释]。因此需要了解应用的通信需求,理解不同的架构风格和它们所导致的特殊问题,并且有能力预测每种交互风格对基于网络通信的特性(the characteristics of network-based communication)的敏感度(sensitivity)[注释]。
不幸的是,使用术语“风格”来表达一组相互协作的架构约束,常常会令人感到困惑。这种用法与“风格”一词在词典中的用法有很大的不同,后者强调的是设计过程的个性化。Loerke[注释]专门用一章来贬低专业建筑师在工作中为个性化风格保留位置的想法。与之相反,他将风格描述为挑剔者对于过去架构(past architecture)的观点,即,应该由可选择的原料、社区文化、统治者的自我意识等因素来负责架构的风格,而不是由设计者来负责。换句话说,Loerke认为在传统的建筑架构中,风格的真正来源是一组应用于设计之上的约束,达到或复制一种特定的风格应该是设计者的最低目标。由于将一组已命名的架构约束称作一种风格,使得对公共约束(common constraints)的特征的表达变得更加容易,我们使用架构风格作为一种进行抽象的方法,而不是暗示存在一种个性化的设计。
1.6 模式和模式语言(Patterns and Pattern Languages)
在进行架构风格的软件工程研究的同时,面向对象编程社区一直在基于对象的(object-based)软件开发领域探索如何使用设计模式和模式语言来描述重复出现的抽象。一种设计模式被定义为一种重要的和重复出现的系统构造。一种模式语言是一个模式的系统,以一种对这些模式的应用加以指导的结构来进行组织[注释]。设计模式和模式语言的概念,都是基于Alexander等人的著作[3,4]中关于建筑架构的内容。
模式的设计空间(design space)包括了特定于面向对象编程技术的实现关注点,例如类继承和接口组合,以及架构风格所带来的高层次的设计问题[注释]。在一些情况下,架构风格的描述也被称作架构模式(architectural patterns)[注释]。然而,模式的一个主要的优点是,它们能够将对象之间的相当复杂的交互协议描述为单个的抽象[注释],其中既包括行为的约束,也包括实现的细节。总的说来,一种模式或由多种模式集成在一起的模式语言,能够被看作是实现对象之间一组预期交互的方法。换句话说,通过在设计和实现选择(implementationchoices)方面遵循一条固定的路径,一种模式定义了一个解决问题的过程[注释]。
如同软件的架构风格一样,软件模式的研究也偏离了其在建筑架构中的起源。其实,Alexander提出的模式概念的核心并非是对于重复出现的架构元素的排列,而是发生在一个空间内重复出现的(人类的活动和情感)事件的模式。Alexander还理解到:事件的模式不能脱离于发生这些事件的空间[注释]。Alexander的设计哲学是,识别出在目标文化(target culture)中有哪些公共的生活模式(pattern of life,译者注:可以与上文说的“事件的模式”关联起来),确定有哪些架构约束可以被用来划分出一种特定的空间,使得期望的生活模式能够在这个空间中自然地产生。这些模式存在于多个层次的抽象和所有的规模中。
作为世界上的一个元素,每一种模式都是在特定环境中的一种关系,是在那个
环境中重复出现的一种特定的力学系统。存在一种特定的空间配置,允许系统中的这些力量(forces)为自己求解,以相互支持,最终达到一种稳定的状态。
作为模式语言中的一个元素,模式代表的是一种指导,展示出在某种有意义的环境中,如何能够一次又一次地重复使用这种空间配置,来为特定的力学系统求解。
模式,简而言之,既是在世界上出现的一个事物,又是一种规则,这种规则告诉我们如何创建这个事物,以及在何时必须要创建它。模式既是一个过程也是一个事物;既是对一个活着的事物的描述,也是对生成这个事物的过程的描述[注释]。
在很多方面,与面向对象编程语言(OOPL)研究中的设计模式相比,Alexander的模式实际上与软件架构风格拥有的共同点更多。一种架构风格,作为一组相互协作的架构约束,应用于一个设计空间之上,以求促使系统出现所期待的架构属性。通过应用一种架构风格,架构师通过区分不同的软件设计空间,希望结果能够更好地匹配应用中所固有的一些必须满足的先决条件,这会导致系统的行为增强了自然的模式(natural pattern,译者注:可以与上文说的“自然地产生”关联起来),而不是与之相冲突(译者注:这段话非常符合老子“道法自然”的思想)。
1.7 视图(Views)
架构视图常常是特定于应用的,并且基于应用的领域而千变万化……我们已经看到架构视图解决了很多的问题,包括:与时间相关的问题(temporal issues)、状态和控制方法(state and control approaches)、数据的表述(data representation)、事务生命周期(transaction life cycle) 、安全保护(security safeguards) 、峰值要求(peak demand)和优雅降级(graceful degradation)。无疑,除了上述的这些视图,还存在着很多可能的视图。[注释]
观察一种架构,除了可从一个系统中的很多架构及组成架构的很多架构风格的角度来之外,还有可能从很多其他的角度来观察。Perry和Wolf[注释]描述了三种重要的软件架构视图:处理、数据、连接。处理视图侧重于流经组件的数据流,以及组件之间连接的那些与数据相关的方面。数据视图侧重于处理的流程,而不是连接器。连接视图侧重于组件之间的关系和通信的状态。
使用多种架构视图,在特定架构的案例研究中是司空见惯的[注释]。在“4+1视图模型”[注释]这种架构设计方法学中,使用了5种相互协作的视图来组织对于软件架构的描述,每一种视图致力于解决一组特定的关注点。
1.8 相关工作
我在这里只包括了那些定义软件架构或者描述软件架构风格的研究领域。其他的软件架构研究领域还包括架构分析技术(architectural analysis techniques)、架构的恢复与再造(architecture recovery and re-engineering)、架构设计的工具和环境(tools and environments for architectural design)、从规范到实现的细化(architecture refinement from specification to implementation)、以及已部署软件架构的案例研究(case studies of deployed software architectures)[注释]。有关架构风格的分类、分布式过程范例(distributed process paradigms)、以及中间件,这些领域的相关工作会在第3章中进行讨论。
1.8.1 设计方法学
大部分早期的软件架构研究都集中在设计方法学(design methodologies)上面。例如,面向对象设计[注释]提倡以一种结构化的方式来解决问题,能够自然地导致基于对象的架构(或者更确切地说,不会导致任何其他形式的架构)。最早从架构层面上强调设计的设计方法学之一是Jackson系统开发方法(JSD)[注释]。JSD有意将对于问题的分析结构化,这样能够导致一种组合了管道和过滤器(pipe-and-filter,又称数据流data flow)风格和过程控制约束(process control constraints)风格的架构风格。这些设计方法学通常只会产生出一种架构风格。
研究者们对架构分析和开发的方法学进行了一些初步的研究。Kazman等人通过使用SAAM[注释]的基于场景的分析(scenario-based analysis)和ATAM[注释]的架构权衡分析(architectural trade-off analysis),对用于识别出架构方面(architectural aspects)的设计方法进行了描述。Shaw[注释]比较了一个汽车导航控制系统的多种不同的方框箭头设计(box-and-arrow designs)图,在每一种设计中都使用了一种不同的设计方法学并包括了多种架构风格。
1.8.2 设计、设计模式、模式语言手册
在与传统的工程学科保持一致的同时,Shaw[注释]提倡对于架构手册(architectural handbooks)的开发。面向对象编程社区率先开发了设计模式的目录,例子有“四人帮”的书籍(译者注:即著名的《设计模式》黑皮书)[注释]、Coplien和Schmidt[注释]的文章。
软件设计模式与架构风格相比,更加倾向于面向特定的问题(problem-oriented)。Shaw[注释]基于在[注释]中描述的架构风格,提出了8个架构模式的例子,还包括了最适合于每一种架构的问题种类。Buschmann等人[注释]对基于对象开发(object-based development)中公共的架构模式进行了全面的检查。这两份参考资料
都是纯粹描述性的,并没有试图去比较或者展示架构模式之间的区别。
Tepfenhart和Cusick[注释]使用了一张二维地图来区分领域分类学(domain taxonomies)、领域模型、架构风格、框架、工具包、设计模式、以及应用软件。在这张拓扑图中,设计模式是预先设计的结构,用来作为软件架构的建造块(building block);而架构风格则是一组运行特征(sets of operational characteristics),用来标识独立于应用领域的一个架构家族(architectural family)。然而,它们都未能成功地定义架构本身。
1.8.3 参考模型和特定于领域的软件架构
研究者们开发出了各种参考模型,为描述架构和展示组件之间的相互关系提供了概念框架[注释]。OMG[注释]开发了对象管理架构(OMA),作为代理式的分布式对象架构(brokered distributed object architectures)的参考实现,OMA详细说明了如何定义和创建对象、客户端应用如何调用对象、如何共享和重用对象。其重点是在分布式对象的管理方面,而不是在应用中的高效交互方面。
Hayes-Roth等人[注释]将特定于领域的软件架构(DSSA)定义为由以下部分组成:a)一种参考架构,为一个重大应用领域描述了一种通用的概念框架。b)一个包含了可重用领域专家知识的组件库。c)一种应用的配置方法,用来在架构中选择和配置组件,以满足特殊的应用需求。Tracz[注释]为DSSA作了综述(general overview)。
通过将软件开发空间(software development space)限制于一个满足某个领域需求的特定架构风格,DSSA项目成功地将架构决策的关注点转移到了正在运行的系统(running systems)上面(译者注:而不是仅仅关注方框直线图)[注释]。DSSA的例子包括:用于航空电子学的ADAGE[注释],用于自适应智能系统的AIS[注释],用于导弹导航、航海、以及控制系统的MetaH[注释]。DSSA更强调在一个公共的架构领域中(a common architectural domain)组件的重用,而不是如何选择特定于每一个系统的架构风格。
1.8.4 架构描述语言
最近发布的与软件架构有关的工作大多都是在架构描述语言(ADL)的领域里。根据Medvidovic和Taylor[注释]的定义,ADL是一种语言,用来明确说明软件系统的概念架构(conceptual architecture)和为这些概念架构建模。ADL至少包括以下部分:组件、组件接口、连接器、以及架构配置。
Darwin是一种声明式(declarative)语言,它旨在成为一种通用的表述方法,来详细描述由使用不同交互机制的不同组件组成的系统的结构[注释]。Darwin的有趣之处在于,它允许详细描述分布式架构(distributed architectures)和动态组合架构(dynamically composed architectures)[注释]。
UniCon[注释]是一种语言及相关的工具集的合称,用来将一组受限的组件和连接器组合为一个架构。Wright[注释]通过(根据交互的协议)指定连接器的类型,为描述架构组件之间的交互的提供了形式化的基础(formal basis)。
如同设计方法学一样,ADL经常引入一些特定的架构假设,这些假设有可能会影响到该语言描述一些架构风格的能力,并且可能会与存在于现有中间件中的假设相矛盾[注释]。在一些情况下,一种ADL是专门为单个架构风格而设计的,这样的ADL是以丧失通用性为代价,增强它在专业化的描述和分析方面的能力。例如,C2SADEL[注释]是一种为了描述以C2风格开发的架构而专门设计的ADL[注释]。与之相反,ACME[注释]是一种试图尽量通用化的ADL。ACME所做的权衡是,它不支持特定于架构风格的分析和建造实际的应用,而是支持在不同的分析工具之间交换分析结果(interchange among analysis tools)。
1.8.5 形式化的架构模型
Abowd等人[注释]声称,根据很小的一组从架构描述的语法领域(方框直线图)到架构含义的语义领域的映射,就能够形式化地描述架构风格。然而,他们所做的假设是:架构就是描述,而不是对于一个正在运行的系统的一种抽象。
Inverardi和Wolf[注释]使用化学抽象机(CHAM)的表达形式,将软件架构元素建模为化学物品,使用明确说明的规则来控制在这些元素之上发生的反应。CHAM根据组件如何转换可用的数据元素,以及如何使用组合规则将很多单一转换传播到整个系统中,来指定组件的行为。尽管这是一个很有趣的模型,有一点仍然不明确:假如某种架构形式的目的超出了仅仅转换一个数据流,如何使用CHAM来描述这种架构形式?
Rapide[注释]是一种并行的、基于事件的模拟语言,专门为定义和模拟系统架构而设计。模拟器生成一组部分排序的(partially-ordered)事件,这些事件能够用于分析在内部连接(interconnection)之上的架构约束的一致性。Le Métayer[注释]提出了一种根据图和图的语法来定义架构的表达方式(formalism)。
1.9 小结
本章探讨了本论文的背景,引入并形式化了一组自恰的软件架构的概念术语。为了避免出现文献中常见的架构和架构描述之间的混淆,这些术语是必需的。特别是在早期的架构研究中,往往未将数据作为一个重要的架构元素。最后,我调查了与软件架构和架构风格相关的一些其他的研究。
后面两章将通过聚焦于基于网络应用的架构,来继续我们对于背景材料的讨论,并且描述如何使用架构风格来指导它们的架构设计,然后使用一种分类方法学(classification methodology)来调查公共的架构风格,这种分类方法学侧重于架构属性,这些架构属性是在将架构风格应用于基于网络的超媒体架构时所产生的。