第9章 · 原文阅读

软件架构设计

第9章 软件架构设计

像学写文章一样,在学会字、词、句之后,就应上升到段落,就应追求文章的“布局谋篇”,这就是架构。通俗地讲,软件架构设计就是软件系统的“布局谋篇”。

人们在软件工程实践中,逐步认识到了软件架构的重要性,从而开辟了一个崭新的研究领域。软件架构的研究内容主要涉及软件架构描述、软件架构设计、软件架构风格、软件架构评价和软件架构的形成方法等。

软件设计人员学习软件架构知识旨在站在较高的层面上整体地解决好软件的设计、复用、质量和维护等方面的实际问题。

9.1 软件架构概述

软件架构是软件抽象发展到一定阶段的产物,从编程的角度,可以清晰地看到软件抽象层次和表达工具的发展历史。

20 世纪 60 年代是子程序的年代:出现了原始的软件架构,即子程序,并以程序间的调用为连接关系。

20 世纪 70 年代是模块化的年代:出现了数据流分析、实体—关系图(E-R 图)、信息隐藏等工具和方法,软件的抽象层次发展到了模块级。

20 世纪 80 年代是面向对象的年代:基于模块化的编程语言进一步发展成面向对象的语言,继承性地增加了一种新元素之间的连接关系。

20 世纪 90 年代是框架的年代:标准的基于对象的架构以框架的形式出现了。如电子数据表、文档、图形图像、音频剪辑等可互换的黑箱对象,可以相互嵌入。

当前(最近 10 年来):中间件和 IT 架构作为标准平台出现,用可购买可复用的元素来构建系统,同时,基于架构的开发方法和理论不断成熟。

9.1.1 软件架构的定义

软件架构仍在不断发展中,还没有形成一个统一的、公认的定义,这里仅举出几个较权威的定义。

定义 1:软件或计算机系统的软件架构是该系统的一个(或多个)结构,而结构由软件元素、元素的外部可见属性及它们之间的关系组成。

定义 2:软件架构为软件系统提供了一个结构、行为和属性的高级抽象,由构成系统的元素的描述、这些元素的相互作用、指导元素集成的模式及这些模式的约束组成。

定义 3:软件架构是指一个系统的基础组织,它具体体现在:系统的构件,构件之间、构件与环境之间的关系,以及指导其设计和演化的原则上。(IEEE1471- 2000)

前两个定义都是按“元素—结构—架构”这一抽象层次来描述的,它们的基本意义相同,其中定义 1 较通俗,因此,本章采用这一定义。该定义中的“软件元素”是指比“构件”

更一般的抽象,元素的“外部可见属性”是指其他元素对该元素所做的假设,如它所提供的服务、性能特征等。

为了更好地理解软件架构的定义,特作如下说明:

在设计软件架构时也必须考虑硬件特性和网络特性,因此,软件架构与系统架构二者间的区别其实不大。但是,在大多情况下,架构设计师在软件方面的选择性较之硬件方面,其自由度大得多。因此,使用“软件架构”这一术语,也表明了一个观点:架构设计师通常将架构的重点放在软件部分。

将软件架构置于商业背景中进行观察,可以发现软件架构对企业非常重要。

这些因素通过功能性需求、非功能性需求、约束条件及相互冲突的要求,影响架构设计师的决策,从而影响架构。

9.1.2 软件架构的重要性

从技术角度看,软件架构的重要性表现为如下几方面。

架构明确了对系统实现的约束条件:架构是架构设计师对系统实现的各方面进行权衡的结果,是总体设计的体现,因此,在具体实现时必须按架构的设计进行。

架构影响着系统的质量属性:要保证系统的高质量,具有完美的架构是必要的(虽然不充分)。

架构可以用来预测系统的质量,例如,可以根据经验对该架构的质量(如性能)作定性的判断。

架构为维护的决策提供根据。在架构层次上能为日后的更改决策提供推理、判断的依据。一个富有生命力的架构,应该是在最有可能更改的地方有所考虑(架构的柔性),使其在此点最容易进行更改。

架构有助于原型开发。可以按架构构造一个骨架系统(原型),例如,在早期实现一个可执行的特例,确定潜在的性能问题。

借助于架构进行成本与进度的估计。

从软件开发过程来看,如果采用传统的软件开发模型(生命周期模型),则软件架构的建立应位于概要设计之前,需求分析之后。

基于架构的软件开发模型则明确地把整个软件过程划分为架构需求、设计、文档化、评审(评估)、实现、演化等 6 个子过程。本章各节将分别对这些子过程进行讨论。

9.1.3 架构的模型

软件架构作为一个有机的整体,可以分解成多个侧面来认识,每个侧面强调它的不同方面的特征,从而使架构设计师能整体地把握它的重点。我们可以将软件架构归纳成 5 种模型:结构模型、框架模型、动态模型、过程模型和功能模型。最常用的是结构模型和动态模型。

它可以看作是一种特殊的框架模型。

这 5 种模型各有所长,也许将 5 种模型有机地统一在一起,形成一个完整的模型来刻画软件架构更合适。即将软件架构视为这些模型的统一体,通过这些模型的表述(文档)来完整反映软件架构。例如,Kruchten 在 1995 年提出了一个“4+1”的视图模型。“4+1” 视图模型从 5 个不同的视角包括逻辑视图、进程视图、物理视图、开发视图和场景视图来描述软件架构。每一个视图只关心系统的一个侧面,5 个视图结合在一起才能反映系统的软件架构的全部内容。“4+1”视图模型如图 9-1 所示。

进程视图可以描述成多层抽象,每个级别分别关注不同的方面。

希赛教育专家提示:逻辑视图和开发视图描述系统的静态结构,而进程视图和物理视图描述系统的动态结构。对于不同的软件系统来说,侧重的角度也有所不同。例如,对于管理信息系统来说,比较侧重于从逻辑视图和开发视图来描述系统,而对于实时控制系统来说,则比较注重于从进程视图和物理视图来描述系统。

9.2 架构需求与软件质量属性

架构的基本需求主要是在满足功能属性的前提下,关注软件质量属性,架构设计则是为满足架构需求(质量属性)寻找适当的“战术”。

软件属性包括功能属性和质量属性,但是,软件架构(及软件架构设计师)重点关注的是质量属性。因为,在大量的可能结构中,可以使用不同的结构来实现同样的功能性,即功能性在很大程度上是独立于结构的,架构设计师面临着决策(对结构的选择),而功能性所关心的是它如何与其他质量属性进行交互,以及它如何限制其他质量属性。

9.2.1 软件质量属性

《GB/T16260-1996(idt ISO/IEC9126:1991)信息技术软件产品评价质量特性及其使用指南》中描述的软件质量特性包括功能性、可靠性、易用性、效率、可维护性、可移植性等 6个方面,每个方面都包含若干个子特性。

功能性:适合性、准确性、互操作性、依从性、安全性;

可靠性:成熟性、容错性、易恢复性;

易用性:易理解性、易学性、易操作性;

效率:时间特性、资源特性;

可维护性:易分析性、易改变性、稳定性、易测试性;

可移植性:适应性、易安装性、遵循性、易替换性;

正如上述列举与分类,软件的质量属性很多,也有各种不同的分类法和不同的表述。虽然术语没有统一的定义,但其含义可以认为业界已有共识。下面选取常用的质量属性术语,并做逐一说明。

1. 运行期质量属性

性能:性能是指软件系统及时提供相应服务的能力。包括速度、吞吐量和持续高速性三方面的要求。

安全性:指软件系统同时兼顾向合法用户提供服务,以及阻止非授权使用的能力。

易用性:指软件系统易于被使用的程度。

可伸缩性:指当用户数和数据量增加时,软件系统维持高服务质量的能力。例如,通过增加服务器来提高能力。

互操作性:指本软件系统与其他系统交换数据和相互调用服务的难易程度。

可靠性:软件系统在一定的时间内无故障运行的能力。

持续可用性:指系统长时间无故障运行的能力。与可靠性相关联,常将其纳入可靠性中。

鲁棒性:是指软件系统在一些非正常情况(如用户进行了非法操作、相关的软硬件系统发生了故障等)下仍能够正常运行的能力。也称健壮性或容错性。

2.开发期质量属性易理解性:指设计被开发人员理解的难易程度。

可扩展性:软件因适应新需求或需求变化而增加新功能的能力。也称为灵活性。

可重用性:指重用软件系统或某一部分的难易程度。

可测试性:对软件测试以证明其满足需求规范的难易程度。

可维护性:当需要修改缺陷、增加功能、提高质量属性时,定位修改点并实施修改的难易程度;

可移植性:将软件系统从一个运行环境转移到另一个不同的运行环境的难易程度。

在实践中,架构设计师追求质量属性常常陷入“鱼和熊掌”的两难境地,这就需要架构设计师的决策智慧了。表 9-1 反映了质量属性之间的相互制约关系(正相关或负相关),其中“+”代表“行属性”能促进“列属性”;而“-”则相反。例如,第一列符号说明许多属性(行)对性能(列)有副作用,第一行符号说明性能(行)对许多属性(列)有副作用,认识这一点,对于架构决策的权衡很重要。

9.2.2 6 个质量属性及实现

本节从架构关注点来研究质量属性实现,将质量属性分为 6 种:可用性、可修改性、性能、安全性、可测试性、易用性。其他的质量属性一般可纳入这几个属性中(在其他文献中为了强调常单列出来),例如,可扩充性可归入可修改性中(修改系统容量),可移植性也可以作为平台的可修改性来获得。对于未能纳入的其他质量属性,可以用本章的方法进行研究。

那么,如何描述质量属性需求呢?采用质量属性场景作为一种描述规范,它由以下6个部分组成,如图 9-2 所示。

刺激源:生成该刺激的实体(人、计算机系统或其他激励器);

刺激:刺激到达系统时可能产生的影响(即需要考虑和关注的情况);

环境:该刺激在某条件内发生。如系统可能正处于过载情况;

制品:系统中受刺激的部分(某个制品被刺激);

响应:刺激到达后所采取的行动;

响应度量:当响应发生时,应能够以某种方式对应其度量,用于对是否满足需求的测试。

需要将一般的质量属性场景(一般场景)与具体的质量属性场景(具体场景)区别开来,前者是指独立于具体系统、适合于任何系统的一般性场景;而后者是指适合于正在考虑的某个特定系统的场景,具体场景通常是指从一般场景中抽取特定的、面向具体系统的内容。下面几个小节中为每个质量属性提供一张表,该表中给出了质量属性场景每部分的一些可能取值,整体上形成一个一般场景的表格描述。在实际应用时,根据系统的具体情况,从该表中选取适当的值,就能变成具体场景(可读性强、可应用),可以把具体场景的集合作为系统的质量属性需求。

实现这些质量属性的基本设计决策,称为“战术”,而把战术的集合称为“架构策略”。

这些架构策略供架构设计师选择。下面几个小节将对各质量属性的战术进行示例性的总结。

“战术”作为逻辑部件位于图 9-2 的制品中,它旨在控制对刺激的响应。

1. 可用性及其实现战术

可用性一般场景可以用图 9-3 表示。

对一般场景进行具体化可以得到可用性具体场景,如图 9-4 所示。

心跳(计时器):一个构件定期发出一个心跳消息,另一个构件收听到消息,如果未收到心跳消息,则假定构件失败,并通知错误纠正构件。

异常:当出现异常时,异常处理程序开发执行。

主动冗余(热重启、热备份):所有的冗余构件都以并行的方式对事件做出响应。它们都处在相同的状态,但仅使用一个构件的响应,丢弃其余构件的响应。错误发生时通过切换的方式使用另一个构件的响应。

被动冗余(暧重启/双冗余/三冗余):一个构件(主构件)对事件做出响应,并通知其他构件(备用的)必须进行的状态更新(同步)。当错误发生时,备用构件从最新同步点接替主构件的工作。

备件:备件是计算平台配置用于更换各种不同的故障构件。

状态再同步:主动和被动冗余战术要求所恢复的构件在重新提供服务前更新其状态。更新方法取决于可以承受的停机时间、更新的规模及更新的内容多少。

检查点/回滚:检查点就是使状态一致的同步点,它或者是定期进行,或者是对具体事件做出响应。当在两检查点之间发生故障时,则以这个一致状态的检查点(有快照)和之后发生的事务日志来恢复系统(数据库中常使用)。

事务:使用事务来保证数据的一致性,即几个相关密切的步骤,要么全成功,要么都不成功。

进程监视器:通过监视进程来处理进程的错误。

2. 可修改性及其实现战术

对于可修改性一般场景的图示及可修改性具体场景,读者可仿照前面可用性的描述方式,自行练习。

维持语义的一致性:语义的一致性指的是模块中责任之间的关系,使这些责任能够协同工作,不需要过多地依赖其他模块。耦合和内聚指标反映一致性,应该根据一组预期的变更来度量语义一致性。使用“抽象通用服务”(如应用框架的使用和其他中间软件的使用)来支持可修改性是其子战术。

预期期望的变更:通过对变更的预估,进行预设、准备,从而使变更的影响最小。

泛化该模块:使一个模块更通用、更广泛的功能。

限制可能的选择:如在更换某一模块(如处理器)时,限制为相同家族的成员。

信息隐藏:就是把某个实体的责任分解为更小的部分,并选择哪些信息成为公有的,哪些成为私有的,通过接口获得公有责任。

维持现有的接口:尽可能维持现有接口的稳定性。例如通过添加接口(通过新的接口提供新的服务)可以达到这一目的。

限制通信路径:限制与一个给定的模块共享数据的模块。这样可以减少由于数据产生/使用引入的连锁反应。

仲裁者的使用:在具有依赖关系的两个模块之间插入一个仲裁者,以管理与该依赖相关的活动。仲裁者有很多种类型,例如:桥、调停者、代理等就是可以提供把服务的语法从一种形式转换为另一种形式的仲裁者。

运行时注册:支持即插即用。

配置文件:在启动时设置参数。

多态:在方法调用的后期绑定。

构件更换:允许载入时绑定。

3. 性能及其实现战术

对于性能一般场景的图示及性能具体场景,读者可仿照前面可用性的描述方式,自行练习。

资源消耗:事件到达后进入一系列的处理程序,每一步处理都要占用资源,而且在处理过程中消息在各构件之间转换,这些转换也需要占用资源。

闭锁时间:指对事件处理时碰到了资源争用、资源不可用或对其他计算的依赖等情况,就产生了等待时间。

性能的战术有如下几种。

减少所处理事件的数量:管理事件率、控制采样频率。

控制资源的使用:限制执行时间(如减少迭代次数)、限制队列大小。

维持数据或计算的多个副本:C/S 结构中客户机 C 就是计算的副本,它能减少服务器计算的压力;高速缓存可以存放数据副本(在不同速度的存储库之间的缓冲)。

增加可用资源:在成本允许时,尽量使用速度更快的处理器、内存和网络。

资源仲裁战术是通过如下调度策略来实现的。

先进/先出(FIFO);

固定优先级调度:先给事件分配特定的优先级,再按优先级高低顺序分配资源;

动态优先级调度:轮转调度、时限时间最早优先;

静态调度:可以离线确定调度。

4. 安全性及其实现战术

对于安全性一般场景的图示及安全性具体场景,读者可仿照前面可用性的描述方式,自行练习。

对用户进行授权:即对用户的访问进行控制管理;

维护数据的机密性:一般通过对数据和通信链路进行加密来实现;

维护完整性:对数据添加校验或哈希值;

限制暴露的信息;

限制访问:如用防火墙、DMZ 策略。

恢复:与可用性中的战术相同;

识别攻击者:作为审计追踪,用于预防性或惩罚性目的。

5. 可测试性及其实现战术

对于可测试性一般场景的图示及可测试性具体场景,读者可仿照前面可用性的描述方式,自行练习。

将接口与实现分离:允许使用实现的替代(模拟器)来支持各种测试目的;

优化访问线路/接口:用测试工具来捕获或赋予构件的变量值。

6. 易用性及其实现战术

对于易用性一般场景的图示及易用性具体场景,读者可仿照前面可用性的描述方式,自行练习。

用户的模型:维护用户的信息,例如使系统以用户可以阅读页面的速度滚动页面;

系统的模型:维护系统的信息,它确定了期望的系统行为,并向用户提供反馈。

9.3 软件架构风格

软件架构设计的一个核心问题是能否使用重复的软件架构模式,即能否达到架构级别的软件重用。也就是说,能否在不同的软件系统中,使用同一架构。基于这个目的,学者们开始研究和实践软件架构的风格和类型问题。

软件架构风格是描述某一特定应用领域中系统组织方式的惯用模式( idiomaticparadigm)。架构风格定义了一个系统家族,即一个架构定义一个词汇表和一组约束。词汇表中包含一些构件和连接件类型,而这组约束指出系统是如何将这些构件和连接件组合起来的。架构风格反映了领域中众多系统所共有的结构和语义特性,并指导如何将各个模块和子系统有效地组织成一个完整的系统。按这种方式理解,软件架构风格定义了用于描述系统的术语表和一组指导构建系统的规则。

对软件架构风格的研究和实践促进了对设计的重用,一些经过实践证实的解决方案也可以可靠地用于解决新的问题。架构风格不变的部分使不同的系统可以共享同一个实现代码。

只要系统是使用常用的、规范的方法来组织,就可使别的设计者很容易地理解系统的架构。

例如,如果某人把系统描述为客户/服务器模式,则不必给出设计细节,我们立刻就会明白系统是如何组织和工作的。

软件架构风格为大粒度的软件重用提供了可能。然而,对于应用架构风格来说,由于视点的不同,系统设计师有很大的选择余地。要为系统选择或设计某一个架构风格,必须根据特定项目的具体特点,进行分析比较后再确定,架构风格的使用几乎完全是特定的。

9.3.1 软件架构风格分类

讨论架构风格时要回答的问题是:

这些问题的回答包括了架构风格的最关键的四要素内容,即提供一个词汇表、定义一套配置规则、定义一套语义解释原则和定义对基于这种风格的系统所进行的分析。Garlan 和Shaw 根据此框架给出了通用架构风格的分类:

9.3.2 数据流风格

数据流风格的软件架构是一种最常见,结构最为简单的软件架构。这样的架构下,所有的数据按照流的形式在执行过程中前进,不存在结构的反复和重构,就像工厂中的汽车流水线一样,数据就像汽车零部件一样在流水线的各个节点上被加工,最终输出所需要的结果(一部完整的汽车)。在流动过程中,数据经过序列间的数据处理组件进行处理,然后将处理结果向后传送,最后进行输出。

数据流风格架构主要包括两种具体的架构风格:批处理序列和管道-过滤器。

1. 批处理序列

批处理风格的每一步处理都是独立的,并且每一步是顺序执行的。只有当前一步处理完,后一步处理才能开始。数据传送在步与步之间作为一个整体。(组件为一系列固定顺序的计算单元,组件间只通过数据传递交互。每个处理步骤是一个独立的程序,每一步必须在前一步结束后才能开始,数据必须是完整的,以整体的方式传递)批处理的典型应用:

2. 管道和过滤器

在管道/过滤器风格的软件架构中,每个构件都有一组输入和输出,构件读输入的数据流,经过内部处理,然后产生输出数据流。这个过程通常通过对输入流的变换及增量计算来完成,所以在输入被完全消费之前,输出便产生了。因此,这里的构件被称为过滤器,这种风格的连接件就像是数据流传输的管道,将一个过滤器的输出传到另一过滤器的输入。此风格特别重要的过滤器必须是独立的实体,它不能与其他的过滤器共享数据,而且一个过滤器不知道它上游和下游的标识。一个管道/过滤器网络输出的正确性并不依赖于过滤器进行增量计算过程的顺序。

图 9-5 是管道/过滤器风格的示意图。一个典型的管道/过滤器架构的例子是以 UNIXshell 编写的程序。UNIX 既提供一种符号,以连接各组成部分(UNIX 的进程),又提供某种进程运行时机制以实现管道。另一个著名的例子是传统的编译器。传统的编译器一直被认为是一种管道系统,在该系统中,一个阶段(包括词法分析、语法分析、语义分析和代码生成)

的输出是另一个阶段的输入。

管道/过滤器风格的软件架构具有许多很好的特点:

但是,这样的系统也存在着若干不利因素。

3. 批处理序列风格与管道过滤器风格对比

把批处理序列风格与管道过滤器风格比较:

共同点:把任务分成一系列固定顺序的计算单元(组件)。组件间只通过数据传递交互。

区别:批处理是全部的、高潜伏性的,输入时可随机存取,无合作性、无交互性。而管道过滤器是递增的,数据结果延迟小,输入时处理局部化,有反馈、可交互。批处理强调数据传送在步与步之间作为一个整体,而管理过滤器无此要求。

9.3.3 调用/返回风格

调用返回风格顾名思义,就是指在系统中采用了调用与返回机制。利用调用-返回实际上是一种分而治之的策略,其主要思想是将一个复杂的大系统分解为一些子系统,以便降低复杂度,并且增加可修改性。程序从其执行起点开始执行该构件的代码,程序执行结束,将控制返回给程序调用构件。

调用/返回风格架构主要包括三种具体的架构风格:主程序/子程序;面向对象风格;层次结构。

1. 主程序/子程序

主程序/子程序风格是结构化开发时期的经典架构风格。这种风格一般采用单线程控制,把问题划分为若干处理步骤,构件即为主程序和子程序。子程序通常可合成为模块。过程调用作为交互机制,即充当连接件。调用关系具有层次性,其语义逻辑表现为子程序的正确性,取决于它调用的子程序的正确性。

2. 面向对象风格

抽象数据类型概念对软件系统有着重要作用,目前软件界已普遍使用面向对象系统。这种风格建立在数据抽象和面向对象的基础上,数据的表示方法和它们的相应操作封装在一个抽象数据类型或对象中。这种风格的构件是对象,或者说是抽象数据类型的实例。对象是一种被称作管理者的构件,因为它负责保持资源的完整性。对象是通过函数和过程的调用来交互的。

图 9-6 是数据抽象和面向对象风格的示意图。

这种风格的两个重要特征为:

面向对象的系统有许多优点,并早已为人所知:

但是,面向对象的系统也存在着某些问题:

只要一个对象的标识改变了,就必须修改所有其他明确调用它的对象;

2. 层次结构风格

层次系统组织成一个层次结构,每一层为上层服务,并作为下层客户。在一些层次系统中,除了一些精心挑选的输出函数外,内部的层只对相邻的层可见。这样的系统中构件在一些层实现了虚拟机(在另一些层次系统中层是部分不透明的)。连接件通过决定层间如何交互的协议来定义,拓扑约束包括对相邻层间交互的约束。

这种风格支持基于可增加抽象层的设计。这样,允许将一个复杂问题分解成一个增量步骤序列的实现。由于每一层最多只影响两层,同时只要给相邻层提供相同的接口,允许每层用不同的方法实现,同样为软件重用提供了强大的支持。

图 9-7 是层次系统风格的示意图。层次系统最广泛的应用是分层通信协议。在这一应用领域中,每一层提供一个抽象的功能,作为上层通信的基础。较低的层次定义低层的交互,最低层通常只定义硬件物理连接。

层次系统有许多可取的属性:

但是,层次系统也有其不足之处:

9.3.4 独立构件风格

独立构件风格主要强调系统中的每个构件都是相对独立的个体,它们之间不直接通信,以降低耦合度,提升灵活性。独立构件风格主要包括:进程通讯和事件系统子风格。

1. 进程通信架构风格进程通信架构风格:构件是独立的过程,连接件是消息传递。这种风格的特点是构件通常是命名过程,消息传递的方式可以是点到点、异步和同步方式及远过程调用等。

2. 事件系统风格基于事件的隐式调用风格的思想是构件不直接调用一个过程,而是触发或广播一个或多个事件。系统中的其他构件中的过程在一个或多个事件中注册,当一个事件被触发,系统自动调用在这个事件中注册的所有过程,这样,一个事件的触发就导致了另一模块中的过程的调用。

从架构上说,这种风格的构件是一些模块,这些模块既可以是一些过程,又可以是一些事件的集合。过程可以用通用的方式调用,也可以在系统事件中注册一些过程,当发生这些事件时,过程被调用。

基于事件的隐式调用风格的主要特点是事件的触发者并不知道哪些构件会被这些事件影响。这样不能假定构件的处理顺序,甚至不知道哪些过程会被调用,因此,许多隐式调用的系统也包含显式调用作为构件交互的补充形式。

支持基于事件的隐式调用的应用系统很多。例如,在编程环境中用于集成各种工具,在数据库管理系统中确保数据的一致性约束,在用户界面系统中管理数据,以及在编辑器中支持语法检查。例如在某系统中,编辑器和变量监视器可以登记相应 Debugger 的断点事件。

当 Debugger 在断点处停下时,它声明该事件,由系统自动调用处理程序,如编辑程序可以卷屏到断点,变量监视器刷新变量数值。而 Debugger 本身只声明事件,并不关心哪些过程会启动,也不关心这些过程做什么处理。

隐式调用系统的主要优点有:

隐式调用系统的主要缺点有:

9.3.5 虚拟机风格

虚拟机风格的基本思想是人为构建一个运行环境,在这个环境之上,可以解析与运行自定义的一些语言,这样来增加架构的灵活性,虚拟机风格主要包括解释器和规则为中心两种架构风格。

1.解释器

一个解释器通常包括完成解释工作的解释引擎,一个包含将被解释的代码的存储区,一个记录解释引擎当前工作状态的数据结构,以及一个记录源代码被解释执行进度的数据结构。

具有解释器风格的软件中含有一个虚拟机,可以仿真硬件的执行过程和一些关键应用。

解释器通常被用来建立一种虚拟机以弥合程序语义与硬件语义之间的差异。其缺点是执行效率较低。典型的例子是专家系统。

2. 规则为中心

基于规则的系统包括规则集、规则解释器、规则/数据选择器及工作内存。

9.3.6 仓库风格

在仓库(repository)风格中,有两种不同的构件:中央数据结构说明当前状态,独立构件在中央数据存储上执行,仓库与外构件间的相互作用在系统中会有大的变化。

仓库风格包括的子风格有:数据库系统、超文本系统、黑板风格。

数据库架构是库风格最常见的形式。构件主要有两大类,一个是中央共享数据源,保存当前系统的数据状态;另一个是多个独立处理元素,处理元素对数据元素进行操作。而超文本系统的典型代表,就是早期的静态网页。三种架构子风格中,最复杂的是黑板系统。

黑板系统是在抽象与总结语言理解系统 HEARSAY-11 的基础上产生的,适合于解决复杂的非结构化的问题,能在求解过程中综合运用多种不同知识源,使得问题的表达、组织和求解变得比较容易。黑板系统是一种问题求解模型,是组织推理步骤、控制状态数据和问题求解之领域知识的概念框架。它将问题的解空间组织成一个或多个应用相关的分级结构。分级结构的每一层信息由一个唯一的词汇来描述,它代表了问题的部分解。领域相关的知识被分成独立的知识模块,它将某一层次中的信息转换成同层或相邻层的信息。各种应用通过不同知识表达方法、推理框架和控制机制的组合来实现。影响黑板系统设计的最大因素是应用问题本身的特性,但是支撑应用程序的黑板体系结构有许多相似的特征和构件。

对于特定应用问题,黑板系统可通过选取各种黑板、知识源和控制模块的构件来设计;

也可以利用预先定制的黑板体系结构的编程环境。图 9-8 是黑板系统的组成。黑板系统的传统应用是信号处理领域,如语音和模式识别。另一应用是松耦合代理数据共享存取。

我们从图 9-8 中可以看出,黑板系统主要由三部分组成:

9.4 层次系统架构风格

本章 9.3.3 节中已对层次系统架构风格进行了初步的介绍,下面将对几种经典的层次风格进行详细说明。

9.4.1 二层及三层 C/S 架构风格

C/S 架构是基于资源不对等,且为实现共享而提出来的,是 20 世纪 90 年代成熟起来的技术,C/S 结构将应用一分为二,服务器(后台)负责数据管理,客户机(前台)完成与用户的交互任务。

C/S 软件架构具有强大的数据操作和事务处理能力,模型思想简单,易于人们理解和接受。但随着企业规模的日益扩大,软件的复杂程度不断提高,传统的二层 C/S 结构存在以下几个局限:

二层 C/S 结构为单一服务器且以局域网为中心,所以难以扩展至大型企业广域网或Internet;

软、硬件的组合及集成能力有限;

服务器的负荷太重,难以管理大量的客户机,系统的性能容易变坏;

数据安全性不好。因为客户端程序可以直接访问数据库服务器,那么,在客户端计算机上的其他程序也可想办法访问数据库服务器,从而使数据库的安全性受到威胁。

正是因为二层 C/S 有这么多缺点,因此,三层 C/S 结构应运而生。三层 C/S 结构是将应用功能分成表示层、功能层和数据层三个部分,如图 9-9 所示。

表示层是应用的用户接口部分,它担负着用户与应用间的对话功能。它用于检查用户从键盘等输入的数据,并显示应用输出的数据。在变更用户接口时,只需改写显示控制和数据检查程序,而不影响其他两层。检查的内容也只限于数据的形式和取值的范围,不包括有关业务本身的处理逻辑。

功能层相当于应用的本体,它是将具体的业务处理逻辑编入程序中。而处理所需的数据则要从表示层或数据层取得。表示层和功能层之间的数据交往要尽可能简洁。

数据层就是数据库管理系统,负责管理对数据库数据的读写。数据库管理系统必须能迅速执行大量数据的更新和检索。因此,一般从功能层传送到数据层的要求大都使用 SQL 语言。

三层 C/S 的解决方案是:对这三层进行明确分割,并在逻辑上使其独立。原来的数据层作为数据库管理系统已经独立出来,所以,关键是要将表示层和功能层分离成各自独立的程序,并且还要使这两层间的接口简洁明了。

一般情况是只将表示层配置在客户机中,如果将功能层也放在客户机中,与二层 C/S 结构相比,其程序的可维护性要好得多,但是其他问题并未得到解决。客户机的负荷太重,其业务处理所需的数据要从服务器传给客户机,所以系统的性能容易变差。

如果将功能层和数据层分别放在不同的服务器中,则服务器和服务器之间也要进行数据传送。但是,由于在这种形态中三层是分别放在各自不同的硬件系统上的,所以灵活性很高,能够适应客户机数目的增加和处理负荷的变动。例如,在追加新业务处理时,可以相应增加装载功能层的服务器。因此,系统规模越大这种形态的优点就越显著。

9.4.2 B/S 架构风格

在三层 C/S 架构中,表示层负责处理用户的输入和向客户的输出(出于效率的考虑,它可能在向上传输用户的输入前进行合法性验证)。功能层负责建立数据库的连接,根据用户的请求生成访问数据库的 SQL 语句,并把结果返回给客户端。数据层负责实际的数据库存储和检索,响应功能层的数据处理请求,并将结果返回给功能层。

浏览器/服务器(Browser/Server,简称 B/S)风格就是上述三层应用结构的一种实现方式,其具体结构为:浏览器/Web 服务器/数据库服务器。采用 B/S 结构的计算机应用系统的基本框架如图 9-10 所示。

B/S 架构主要是利用不断成熟的 WWW 浏览器技术,结合浏览器的多种脚本语言,用通用浏览器就实现了原来需要复杂的专用软件才能实现的强大功能,并节约了开发成本。从某种程度上来说,B/S 结构是一种全新的软件架构。

在 B/S 结构中,除了数据库服务器外,应用程序以网页形式存放于 Web 服务器上,用户运行某个应用程序时只需在客户端上的浏览器中键入相应的网址,调用 Web 服务器上的应用程序并对数据库进行操作完成相应的数据处理工作,最后将结果通过浏览器显示给用户。可以说,在 B/S 模式的计算机应用系统中,应用(程序)在一定程度上具有集中特征。

基于 B/S 架构的软件,系统安装、修改和维护全在服务器端解决。用户在使用系统时,仅需要一个浏览器就可运行全部的模块,真正达到了“零客户端”的功能,很容易在运行时自动升级。B/S 架构还提供了异种机、异种网、异种应用服务的联机、联网、统一服务的最现实的开放性基础。

B/S 结构出现之前,管理信息系统的功能覆盖范围主要是组织内部。B/S 结构的“零客户端”方式,使组织的供应商和客户(这些供应商和客户有可能是潜在的,也就是说可能是事先未知的!)的计算机方便地成为管理信息系统的客户端,进而在限定的功能范围内查询组织相关信息,完成与组织的各种业务往来的数据交换和处理工作,扩大了组织计算机应用系统的功能覆盖范围,可以更加充分利用网络上的各种资源,同时应用程序维护的工作量也大大减少。另外,B/S 结构的计算机应用系统与 Internet 的结合也使新近提出的一些新的企业计算机应用(如电子商务,客户关系管理)的实现成为可能。

与 C/S 架构相比,B/S 架构也有许多不足之处,例如:

9.4.3 MVC 架构风格

MVC 全名是 Model ViewController,是模型(model)-视图(view)-控制器(controller)的缩写,它是分层架构风格的一种。MVC 是由挪威的计算机专家 Trygve M.H. Reenskau 于1979年提出的软件架构模式,MVC 最初用于 SmallTalk。MVC 提出的基本思想是进行关注点分离。一个典型的人机交互应用具有三个主要的关注点:数据在可视化界面上的呈现、UI 处理逻辑和业务逻辑。如果按传统的自治视图模式(即将与 UI 相关的逻辑都定义在针对视图的相关元素的事件上),将三者混合在一起,势必会带来一系列问题:

正是为了解决以上的问题,所以我们需要采用关注点分离的方针来将可视化界面呈现、UI 处理逻辑和业务逻辑三者分离出来,并且采用合理的交互方式将它们之间的依赖降到最低。

MVC 中各个部分的分工与协作是这样的:

如果需要涉及业务功能的调用,Controller 会直接调用 Model。在完成 UI 处理后,Controller会根据需要控制原 View 或者创建新的 View 对用户交互操作予以响应。

MVC 模式的基本结构如图 9-11 所示。

9.4.4 MVP 架构风格

MVP 的全称为 Model-View-Presenter,Model 提供数据,View 负责显示,Controller/Presenter 负责逻辑的处理。MVP 是从经典的模式 MVC 演变而来,它们的基本思想有相通的地方:Controller/Presenter 负责逻辑的处理,Model 提供数据,View 负责显示。当然 MVP与 MVC 也有一些显著的区别,MVC 模式中元素之间“混乱”的交互主要体现在允许 View和 Model 直接进行“交流”,这在 MVP 模式中是不允许的。在 MVP 中 View 并不直接使用 Model,它们之间的通信是通过 Presenter (MVC 中的 Controller)来进行的,所有的交互都发生在 Presenter 内部,而在 MVC 中 View 会直接从 Model 中读取数据而不是通过 Controller。

MVP 不仅仅避免了 View 和 Model 之间的耦合,还进一步降低了 Presenter 对 View的依赖。Presenter 依赖的是一个抽象化的 View,即 View 实现的接口 IView,这带来的最直接的好处,就是使定义在 Presenter 中的 UI 处理逻辑变得易于测试。由于 Presenter 对View 的依赖行为定义在接口 IView 中,我们只需要一个实现了这个接口的 View 就能对Presenter 进行测试。MVP 的结构如图 9-12 所示。

下面我们来分析 MVP 的优缺点。MVP 的优点包括:

MVP 的缺点包括:

由于对视图的渲染放在了 Presenter 中,所以视图和 Presenter 的交互会过于频繁。还有一点需要明白,如果 Presenter 过多地渲染了视图,往往会使得它与特定的视图的联系过于紧密。一旦视图需要变更,那么 Presenter 也需要变更了。比如说,原本用来呈现 HTML的 Presenter 现在也需要用于呈现 PDF 了,那么视图很有可能也需要变更。

9.5 面向服务的架构

迄今为止,对于面向服务的架构(Service-Oriented Architecture,SOA)还没有一个公认的定义。许多组织从不同的角度和不同的侧面对 SOA 进行了描述,较为典型的有以下三个:

9.5.1 SOA 概述

SOA 是一种在计算环境中设计、开发、部署和管理离散逻辑单元(服务)模型的方法。

SOA 并不是一个新鲜事物,而只是面向对象模型的一种替代。虽然基于 SOA 的系统并不排除使用 OOD 来构建单个服务,但是其整体设计却是面向服务的。由于 SOA 考虑到了系统内的对象,所以虽然 SOA 是基于对象的,但是作为一个整体,它却不是面向对象的。

SOA 系统原型的一个典型例子是 CORBA,它已经出现很长时间,其定义的概念与 SOA相似。SOA 建立在 XML 等新技术的基础上,通过使用基于 XML 的语言来描述接口,服务已经转到更动态且更灵活的接口系统中,CORBA 中的 IDL 无法与之相比。图 9-13 描述了一个完整的 SOA 模型。

在 SOA 模型中,所有的功能都定义成了独立的服务。服务之间通过交互和协调完成业务的整体逻辑。所有的服务通过服务总线或流程管理器来连接。这种松散耦合的架构使得各服务在交互过程中无需考虑双方的内部实现细节,以及部署在什么平台上。

1. 服务的基本结构

一个独立的服务基本结构如图 9-14 所示。

由图 9-14 可以看出,服务模型的表示层从逻辑层分离出来,中间增加了服务对外的接口层。通过服务接口的标准化描述,使得服务可以提供给在任何异构平台和任何用户接口使用。这允许并支持基于服务的系统成为松散耦合、面向构件和跨技术实现,服务请求者很可能根本不知道服务在哪里运行、是由哪种语言编写的,以及消息的传输路径,而是只需要提出服务请求,然后就会得到答案。

2.SOA 设计原则

在 SOA 架构中,继承了来自对象和构件设计的各种原则,例如,封装和自我包含等。

那些保证服务的灵活性、松散耦合和复用能力的设计原则,对 SOA 架构来说同样是非常重要的。关于服务,一些常见的设计原则如下:

3. 服务构件与传统构件

服务构件架构(Service Component Architecture,SCA)是基于 SOA 的思想描述服务之间组合和协作的规范,它描述用于使用 SOA 构建应用程序和系统的模型。它可简化使用SOA 进行的应用程序开发和实现工作。SCA 提供了构建粗粒度构件的机制,这些粗粒度构件由细粒度构件组装而成。SCA 将传统中间件编程从业务逻辑分离出来,从而使程序员免受其复杂性的困扰。它允许开发人员集中精力编写业务逻辑,而不必将大量的时间花费在更为底层的技术实现上。

SCA 服务构件与传统构件的主要区别在于,服务构件往往是粗粒度的,而传统构件以细粒度居多;服务构件的接口是标准的,主要是服务描述语言接口,而传统构件常以具体 API形式出现;服务构件的实现与语言是无关的,而传统构件常绑定某种特定的语言;服务构件可以通过构件容器提供 QoS 的服务,而传统构件完全由程序代码直接控制。

9.5.2 SOA 的关键技术

SOA 伴随着无处不在的标准,为企业的现有资产或投资带来了更好的复用性。SOA 能够在最新的和现有的系统之上创建应用,借助现有的应用产生新的服务,为企业提供更好的灵活性来构建系统和业务流程。SOA 是一种全新的架构,为了支持其各种特性,相关的技术规范不断推出。与 SOA 紧密相关的技术主要有 UDDI、WSDL、SOAP 和 REST 等,而这些技术都是以 XML 为基础而发展起来的。

1. UDDI

UDDI(Universal DescriptionDiscovery and Integration,统一描述、发现和集成)提供了一种服务发布、查找和定位的方法,是服务的信息注册规范,以便被需要该服务的用户发现和使用它。UDDI 规范描述了服务的概念,同时也定义了一种编程接口。通过 UDDI 提供的标准接口,企业可以发布自己的服务供其他企业查询和调用,也可以查询特定服务的描述信息,并动态绑定到该服务上。

在 UDDI 技术规范中,主要包含以下三个部分的内容:

2.WSDLWSDL(Web ServiceDescription Language,Web 服务描述语言)是对服务进行描述的语言,它有一套基于 XML 的语法定义。WSDL 描述的重点是服务,它包含服务实现定义和服务接口定义,如图 9-15 所示。

采用抽象接口定义对于提高系统的扩展性很有帮助。服务接口定义就是一种抽象的、可重用的定义,行业标准组织可以使用这种抽象的定义来规定一些标准的服务类型,服务实现者可以根据这些标准定义来实现具体的服务。

服务实现定义描述了给定服务提供者如何实现特定的服务接口。服务实现定义中包含服务和端口描述。一个服务往往会包含多个服务访问入口,而每个访问入口都会使用一个端口元素来描述,端口描述的是一个服务访问入口的部署细节,例如,通过哪个地址来访问,应当使用怎样的消息调用模式来访问等。

3.SOAP

SOAP(Simple ObjectAccess Protocol,简单对象访问协议)定义了服务请求者和服务提供者之间的消息传输规范。SOAP 用 XML 来格式化消息,用 HTTP 来承载消息。通过 SOAP,应用程序可以在网络中进行数据交换和远程过程调用(Remote Procedure Call, RPC)。SOAP主要包括以下四个部分:

SOAP 消息基本上是从发送端到接收端的单向传输,但它们常常结合起来执行类似于请求/应答的模式。所有的 SOAP 消息都使用 XML 进行编码。SOAP 消息包括以下三个部分:

4.REST

REST(RepresentationalState Transfer,表述性状态转移)是一种只使用 HTTP 和 XML 进行基于 Web 通信的技术,可以降低开发的复杂性,提高系统的可伸缩性。它的简单性和缺少严格配置文件的特性,使它与 SOAP 很好地隔离开来,REST 从根本上来说只支持几个操作(POST、GET、PUT 和 DELETE),这些操作适用于所有的消息。REST 提出了如下一些设计概念和准则:

9.5.3 SOA 的实现方法

SOA 只是一种概念和思想,需要借助于具体的技术和方法来实现它。从本质上来看,SOA 是用本地计算模型来实现一个分布式的计算应用,也有人称这种方法为“本地化设计,分布式工作”模型。CORBA、DCOM 和 EJB 等都属于这种解决方式,也就是说,SOA 最终可以基于这些标准来实现。有关这些标准的知识,已经在 13.1.1 节中详细介绍。另外,这些标准分别使用的 ORB、RPC 和 RMI(Remote Method Invocation,远程方法调用)等技术,将在 17.1.2 节中介绍,此处不再赘述。

从逻辑上和高层抽象来看,目前,实现 SOA 的方法也比较多,其中主流方式有 WebService、企业服务总线和服务注册表。

1.Web Service

在 Web Service(Web 服务)的解决方案中,一共有三种工作角色,其中服务提供者和服务请求者是必需的,服务注册中心是一个可选的角色。它们之间的交互和操作构成了 SOA的一种实现架构,如图 9-16 所示。

Web Service 模型中的操作包括发布、查找和绑定,这些操作可以单次或反复出现。

在采用 Web Service 作为 SOA 的实现技术时,应用系统大致可以分为六个层次,分别是底层传输层、服务通信协议层、服务描述层、服务层、业务流程层和服务注册层。

2. 服务注册表

服务注册表(service registry)虽然也具有运行时的功能,但主要在 SOA 设计时使用。

它提供一个策略执行点(Policy Enforcement Point,PEP),在这个点上,服务可以在 SOA 中注册,从而可以被发现和使用。服务注册表可以包括有关服务和相关构件的配置、依从性和约束文件。从理论上来说,任何帮助服务注册、发现和查找服务合约、元数据和策略的信息库、数据库、目录或其他节点都可以被认为是一个注册表。大多数商用服务注册产品支持服务注册、服务位置和服务绑定功能。

3. 企业服务总线

ESB 的概念是从 SOA 发展而来的,它是一种为进行连接服务提供的标准化的通信基础结构,基于开放的标准,为应用提供了一个可靠的、可度量的和高度安全的环境,并可帮助企业对业务流程进行设计和模拟,对每个业务流程实施控制和跟踪、分析并改进流程和性能。

在一个复杂的企业计算环境中,如果服务提供者和服务请求者之间采用直接的端到端的交互,那么随着企业信息系统的增加和复杂度的提高,系统之间的关联会逐渐变得非常复杂,形成一个网状结构,这将带来昂贵的系统维护费用,同时也使得 IT 基础设施的复用变得困难重重。ESB 提供了一种基础设施,消除了服务请求者与服务提供者之间的直接连接,使得服务请求者与服务提供者之间进一步解耦。

ESB 是由中间件技术实现并支持 SOA 的一组基础架构,是传统中间件技术与 XML、Web Service 等技术结合的产物,是在整个企业集成架构下的面向服务的企业应用集成机制。

具体来说,ESB 具有以下功能:

在企业应用集成方面,与现存的、专有的集成解决方案相比,ESB 具有以下优势:

9.5.4 微服务

微服务顾名思义,就是很小的服务,所以它属于面向服务架构的一种。通俗一点来说,微服务类似于古代著名的发明,活字印刷术,每个服务都是一个组件,通过编排组合的方式来使用,从而真正做到了独立、解耦、组件化、易维护、可复用、可替换、高可用、最终达到提高交付质量、缩短交付周期的效果。

从专业的角度来看,微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。每个服务运行在其独立的进程中,服务与服务间采用轻量级的通信机制互相沟通(通常是基于 HTTP 协议的 RESTfulAPI)。每个服务都围绕着具体业务进行构建,并且能够被独立的部署到生产环境、类生产环境等。另外,应当尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建。

所以总结起来,微服务的核心特点为:小, 且专注于做⼀件事情、轻量级的通信机制、松耦合、独立部署。

1.微服务的优势

微服务之所以能盛行,必然是有它独特优势的,下面我们来分析微服务有哪些方面的优势。

在微服务架构中,每个服务都是一个相对独立的个体,每个服务都可以选择适合于自身的技术来实现。如,要开发一个社交平台,此时,我们可能使用文档型数据库来存储帖子的内容,使用图数据来存储朋友圈的这些关系等,这样可以把每一块的性能都充分发挥出来。

同时,在应用新技术时,微服务架构也提供了更好的试验场。因为对于单块的系统而言,采用一个新的语言、数据库或者框架都会对整个系统产生巨大的影响,这样导致我们想尝试新技术时,望而却步。但微服务不同,我们完全可以只在一个微服务中采用新技术,待技术使用熟练之后,再推广到其他服务。

弹性主要讲的是系统中一部分出现故障会引起多大问题。在单块系统中,一个部分出现问题,可能导致整体系统的问题。而微服务架构中,每个服务可以内置可用性的解决方案与功能降级方案,所以比单块系统强。

单块系统中,我们要做扩展,往往是整体进行扩展。而在微服务架构中,可以针对单个服务进行扩展。

在大型单块系统中,即使修改一行代码,也需要重新部署整个应用系统。这种部署的影响很大、风险很高,因此不敢轻易地重新部署。而微服务架构中,每个服务的部署都是独立的,这样就可以更快地对特定部分的代码进行部署。

我们都知道,团队越大越难管理,同时团队越大也代表系统规模越大代码库越大,这样容易引起一系列的问题。且当团队是分布式的时候,问题更严重。微服务架构就能很好地解决这个问题,微服务架构可以将架构与组织结构相匹配,避免出现过大的代码库,从而获得理想的团队大小及生产力。服务的所有权也可以在团队之间迁移,从而避免异地团队的出现。

在微服务架构中,系统会开放很多接口供外部使用。当情况发生改变时,可以使用不同的方式构建应用,而整体化应用程序只能提供一个非常粗粒度的接口供外部使用。

在单块系统中如果删除系统中的上百行代码,也许不知道会发生什么,引起什么样的问题,因为单块系统中关联性很强。但在微服务架构中,我们可以在需要时轻易地重写服务,或者删除不再使用的服务。

2. 微服务面临的挑战

软件开发业内有一句名言“软件开发没有银弹”,虽然前面介绍了微服务很多方面的优势,但微服务并不能解决所有问题。下面我们来分析在使用微服务架构时可能面临的一些挑战。

使用微服务实现分布式系统的复杂度要比单块系统高。这表现在多个方面,如:性能方面微服务是拆分成多个服务进行部署,服务间的通信都是通过网络,此时的性能会受影响。

同时可靠性也会受影响。数据一致性也需要严格控制,其成本也比单块系统高。

相比传统的单块架构应用,微服务将系统分成多个独立的部分,每个部分都是可以独立部署的业务单元。这就意味着,原来适用于单块架构的集中式的部署、配置、监控或者日志收集等方式,在微服务架构下,随着服务数量的增多,每个服务都需要独立的配置、部署、监控、日志收集等,因此成本呈指数级增长。

传统单块系统部署往往是以月、周为单位,部署频度很低,在这种情况下,手动部署是可以满足需求的。而对于微服务架构而言,每个服务都是一个独立可部署的业务单元,每个服务的修改都需要独立部署。这样部署的成本是比较高的,如亚马逊,每天都要执行数十次、甚至上百次的部署,此时仍用人工部署是行不通的,要使用自动化部署。如何有效地构建自动化部署流水线,降低部署成本、提高部署频率,是微服务架构下需要面临的一个挑战。

传统单块架构中,团队通常是按技能划分,如开发部、测试部、运维部,并通过项目的方式协作,完成系统交付。而在微服务架构的实施过程中,除了如上所述的交付、运维上存在的挑战,在组织或者团队层面,如何传递 DevOps 文化的价值,让团队理解 DevOps 文化的价值,并构建全功能团队,也是一个不小的挑战。

微服务不仅表现出一种架构模型,同样也表现出一种组织模型。这种新型的组织模型意味着开发人员和运维的角色发生了变化,开发者将承担起服务整个生命周期的责任,包括部署和监控,而运维也越来越多地表现出一种顾问式的角色,尽早考虑服务如何部署。因此,如何在微服务的实施中,按需调整组织架构,构建全功能的团队,是一个不小的挑战。

由于微服务架构是把系统拆分为若干个可独立部署的服务,所以需要进行服务间的依赖测试。在服务数量较多的情况下,如何有效地保证服务之间能有效按照接口的约定正常工作,成为微服务实施过程中必须面临的巨大挑战。

传统的单块系统,功能实现比较集中,大部分功能都运行在同一个应用中,同其他系统依赖较少。而微服务架构则不同,在将系统功能拆分成相互协作的独立服务之后,随着微服务个数的增多,如何清晰有效地展示服务之间的依赖关系,成为了一个挑战。

3.微服务与 SOA微服务可以讲是 SOA 的一种,但仔细分析与推敲,我们又能发现他们的一些差异。这种差异表现在多个方面,具体如表 9-8 所示。

这些差异自然影响到其实现,在实现方面的主要差异如表 9-9 所示。

9.6 架构设计

9.2 节讨论了实现软件质量属性的战术,这些战术可以看做设计的基本“构建块”,通过这些构建块,就可以精心设计系统的软件架构了。

架构模式也称为架构风格,它是适当地选取战术的结果,这些固定的结果(模式)在高层抽象层次上具有普遍实用性和复用性。

通过架构模式,架构设计师可以借鉴和复用他人的经验,看看类似的问题别人是如何解决的。但不要把模式看成是一个硬性的解决方法,它只是一种解决问题的思路。Martin Fowler曾说:“模式和业务构件的区别就在于模式会引发你的思考。”

在本章的后续部分将进一步讨论架构模式。

1. 演变交付生命周期

业界已开发出各种软件生命周期模型,其中把架构放在一个适当位置的模型中,典型的有演变交付生命周期模型,如图 9-17 所示。

在生命周期模型中,架构设计就是从初步的需求分析开始逐步进行循环迭代(图 9-17中的反向箭头说明了这一点)。即:一方面在了解系统需求前,不能开始设计架构;另一方面,刚开始进行设计架构时并不需要等到全部需求都收集到。架构是由“架构驱动”因素“塑造”的,架构因素是指少数关键的、优先级别最高的业务目标质量需求。架构由少数关键需求决定并在循环迭代中处于基本稳定状态,它作为演变的基础设施。

2. 属性驱动设计法

上述模型强调先建立软件架构,再把架构作为骨架,在骨架上循环迭代,逐步长出有血有肉的系统之躯。属性驱动设计法(Attribute-Driven Design,ADD)就是一种定义软件架构的方法,该方法将分解过程建立在软件必须满足的质量属性之上。ADD 的输入为:功能需求(一般表示为用例)、限制条件和质量需求(一组特定于系统的质量场景)。

ADD 的步骤如下。

从具体的质量场景和功能需求集合中选择架构驱动因素。并不是同等看待所有需求,而是在满足了最重要的需求的条件下,才满足不太重要的需求,即针对架构需求有优先级。

选择满足架构驱动因素的架构模式,根据前面的战术创建(或选择)模式。其目标是建立一个由模块类型组成的总体架构模式。

实例化模块并根据用例分配功能,使用多个视图进行表示。

定义子模块的接口。

验证用例和质量场景,并对其进行求精,使它们成为子模式的限制。

3. 按架构组织开发团队

在架构的模块分解结构的最初几个层次相对稳定之后,就可以把这些模块分配给开发小组,其结果就是工作视图。像软件系统一样,开发小组也应该努力做到松耦合、高内聚。即每个模块都构成自己的小领域(专门知识或专门技术),并与其他模块的接口清晰,这样,不同的模块分到不同的开发小组中,就能减少各开发小组之间的沟通成本,而在各开发小组内部,由于是处理小领域的问题,容易建立起有效的沟通机制,如成员有这个小领域的背景知识(或培训获得)、共享决策信息。

同时,项目计划在架构确定之后可以结合分工进一步明细化,特别要规划好接口提供的时间点,保证项目开发的整体协调性。

4. 开发骨架系统

演变交付生命周期模型中有两个循环,第一个循环是通过迭代的方式开发出软件架构,第二个循环是在架构的基础上通过迭代的方式开发出交付的最终版本。开发骨架系统就是第二个循环的第一步。这一步就是以架构为指导,开发一个可运行的原型(骨架系统)。在骨架系统开发过程中要注意对接口进行充分协商,避免先开发的部分强制随后部分满足其不合理的接口要求。骨架系统完成后,就可以在其上进行增量开发,直到软件开发完成。

5. 利用商用构件进行开发

模式本来就是针对特定问题的解,因此,针对需求的特点,也可以选用相应的模式来设计架构,并利用对应于该模式的商用构件进行软件开发。例如可以使用 J2EE/EJB 进行开发面向对象的分布式系统。

9.7 软件架构文档化

记录软件架构的活动就是架构编档过程,也就是架构的文档化。它包含两个方面:一是过程,编档过程能促使架构设计师进一步思考,使得架构更加完善;二是结果,描述架构的文档将作为架构开发的成果,供项目关系人使用。

1. 架构文档的使用者

架构文档的使用者是架构的项目关系人。编写技术文档(尤其是软件架构文档)最基本的原则之一是要从读者的角度来编写,易于编写但很难阅读的文档是不受欢迎的。

架构的主要用途是充当项目关系人之间进行交流的工具,文档则促进了这种交流—— 架构项目关系人希望从架构文档中获得自己所关心的架构信息,如:系统实现人员希望文档提供关于开发活动的不能违反的限制及可利用的自由;测试人员和集成人员希望能从文档中得到必须组合在一起的各部分,并以此得到一个正确的测试黑箱;项目经理希望根据所确定的工作任务组建开发小组,规划和分配项目资源。

2. 合理的编档规则编写架构文档和编写其他文档一样,必须遵守一些基本规则,这里将任何软件编档(包括软件架构编档)的规则归纳为 7 条:

3. 视图编档

视图是最重要的软件架构编档概念,本书将在 9.11 节中专门讨论架构的视图。视图的概念为架构设计师提供了进行软件架构编档的基本原则。架构文档化就是将相关视图编成文档,并补充多个视图的关联关系。

视图编档的组织结构(内容及编排次序、大纲)虽然目前还没有工业标准模板,研究者(Bachmann 等人)提出的文档组织结构包含 7 个部分,如图 9-18 所示。

这部分是文档的主要组成部分,其中要注意:

—对元素及其协同工作的行为进行编档,如用UML 的顺序图和状态图描述行为;

—对接口进行编档,图9-19 说明了这部分的内容。

4. 跨视图文档

软件架构由多个视图文档来反映,按前面所述的要求完成每个视图的文档后,需要对这些文档进行一个整体的“打包”工作,这就是跨视图文档。它包括如下内容:

5. 使用 UML

UML 已经成为对软件架构进行文档化的事实上的标准表示法。在视图文档的组织结构中,UML 主要用于表示元素或元素组的行为。

有关 UML 的详细内容,请阅读 8.4.3 节。

6. 软件架构重构

前面已论述了架构编档,即在架构设计时完成编档工作。但是还有另外一种情况:系统已经存在,但不知其架构,即架构没有通过文档很好地保留下来(文档的缺失/失效)。如何维护这样的系统并管理其演变?其关键就是要找到软件架构,软件架构重构就是研究解决这一问题的方法,它是反向工程之一。

架构重构需要工具的支持,但任何一个工具或工具集对架构重构都是不够的。因为:

工具往往是面向特定语言的;

数据提取工具经常返回不完整的或错误的结果,因此,应在多个工具提供的结果间进行补充、验证和判断;

重构的目的(文档的用途)不同,决定了需要提取什么数据,这反过来影响了工具的选择。

以此为原则,就是架构重构的工作台方法,如 SEI 开发的 Dali。

软件架构重构由以下活动组成,这些活动以迭代方式进行,如图 9-20 所示。

上述过程中,架构是由重构人员通过对系统做出一组假定来获得,为了最有效地生成这些假定并对其进行验证,必须让熟悉系统的人参与此项工作,包括过去参与系统开发的人员或现在正在对其进行维护的人员。

9.8 软件架构评估

软件架构评估是在对架构分析、评估的基础上,对架构策略的选取进行决策。它也可以灵活地运用于对软件架构进行评审等工作中。

9.8.1 软件架构评估的方法

业界已开发出多种软件架构评估的方法,按基于的技术手段来看,可以分为三类:基于调查问卷或检查表的方式、基于场景的方式和基于度量的方式。

9.8.2 架构的权衡分析法

从技术角度对软件架构进行评估,旨在通过分析来预见软件的质量;通过分析来创建、选择、评估与比较不同的架构。例如,Kazman 等人在 2000 年提出的架构的 ATAM 方法。

ATAM 方法不但能够揭示架构如何满足特定的质量需求(例如,性能和可修改性),而且还提供了分析这些质量需求之间交互作用的方法。使用 ATAM 方法评价一个软件架构的目的是理解架构设计满足系统质量需求的结果。

ATAM 产生如下结果。

ATAM 的 9 个步骤如下。

已编写了文档的架构方法;

经过讨论得到的场景集合及其优先级;

效用树;

所发现的有风险决策;

已编成文档的无风险决策;

所发现的敏感点和权衡点。

9.8.3 成本效益分析法

在大型复杂系统中最大的权衡通常必须考虑经济性,因此,需要从经济角度建立成本、收益、风险和进度等方面软件的“经济”模型。成本效益分析法(the Cost Benefit AnalysisMethod,CBAM)是在 ATAM 上构建,用来对架构设计决策的成本和收益进行建模,是优化此类决策的一种手段。CBAM 的思想就是架构策略影响系统的质量属性,反过来这些质量属性又会为系统的项目关系人带来一些收益(称为“效用”),CBAM 协助项目关系人根据其投资回报(ROI)选择架构策略。CBAM 在 ATAM 结束时开始,它实际上使用了 ATAM 评估的结果。

CBAM 的步骤如下。

根据开发经验估算架构策略的成本,结合第 7 步的收益,计算出架构策略的 ROI,按 ROI 排序,从而确定选取策略的优先级。

9.9 构件及其复用

软件企业为了提高开发效率,越来越注重软件元素的复用(也称重用),因此,架构设计师在进行架构设计时,必须关注复用,例如,考虑丰富企业构件和充分使用已有的构件。

本节从构件角度研究如何使用软件复用技术,下一节重点讨论基于产品线的软件复用。

与复用技术密切相关的概念是构件(component,组件),业界对构件还没有公认的定义,如下为几种常见的定义。

定义 1:构件是指软件系统中可以明确辨识的构成成分。而可复用构件(reusablecomponent)是指具有相对独立的功能和可复用价值的构件。

定义 2:构件是一个组装单元,它具有约定式规范的接口及明确的依赖环境。

定义 3:构件是软件系统中具有相对独立功能、可以明确辨识、接口由契约指定、和语境有明显依赖关系、可独立部署的可组装软件实体。

对构件更广义的理解是把所有种类的工作成品(例如,各类文档、方案、计划、测试案例、代码)都看成是可复用的构件。

9.9.1 商用构件标准规范

当前,主流的商用构件标准规范包括 OMG(Object Management Group,对象管理组织)

的 CORBA、SUN 的 J2EE 和 Microsoft 的 DNA。

1. CORBA

CORBA(Common ObjectRequest Broker Architecture,公共对象请求代理架构)主要分为3 个层次:对象请求代理、公共对象服务和公共设施。最底层的对象请求代理(Object RequestBroker,ORB),规定了分布对象的定义(接口)和语言映射,实现对象间的通信和互操作,是分布对象系统中的“软总线”;在 ORB 之上定义了很多公共服务,可以提供诸如并发服务、名字服务、事务(交易)服务、安全服务等各种各样的服务;最上层的公共设施则定义了构件框架,提供可直接为业务对象使用的服务,规定业务对象有效协作所需的协定规则。

CORBA CCM(CORBA ComponentModel,CORBA 构件模型)是 OMG 组织制定的一个用于开发和配置分布式应用的服务器端构件模型规范,它主要包括如下 3 项内容。

2.J2EE

在 J2EE 中,SUN 给出了完整的基于 Java 语言开发面向企业分布的应用规范,其中,在分布式互操作协议上,J2EE 同时支持 RMI(Remote Method Invocation,远程方法调用)

和 IIOP(Internet Inter-ORB Protocol,互联网内部对象请求代理协议),而在服务器端分布式应用的构造形式,则包括了 Java Servlet、JSP、EJB 等多种形式,以支持不同的业务需求,而且 Java 应用程序具有跨平台的特性,使得 J2EE 技术在发布计算领域得到了快速发展。

其中,EJB 给出了系统的服务器端分布构件规范,这包括了构件、构件容器的接口规范,以及构件打包、构件配置等的标准规范内容。EJB 技术的推出,使得用 Java 基于构件方法开发服务器端分布式应用成为可能。从企业应用多层结构的角度,EJB 是业务逻辑层的中间件技术,与 JavaBeans 不同,它提供了事务处理的能力,自从三层结构提出以后,中间层,也就是业务逻辑层,是处理事务的核心,从数据存储层分离,取代了存储层的大部分地位。

从 Internet 技术应用的角度,EJB 和 Servlet,JSP 一起成为新一代应用服务器的技术标准,EJB 中的 Bean 可以分为会话 Bean 和实体 Bean,前者维护会话,后者处理事务,通常由Servlet 负责与客户端通信,访问 EJB,并把结果通过 JSP 产生页面传回客户端。

3. DNA 2000

Microsoft DNA 2000 是 Microsoft 在推出 Windows 2000 系列操作系统平台的基础上,在扩展了分布计算模型,以及改造 Back Office 系列服务器端分布计算产品后发布的新的分布计算架构和规范。在服务器端,DNA 2000 提供了 ASP、COM、Cluster 等的应用支持。

DNA 2000 融合了当今最先进的分布计算理论和思想,例如,事务处理、可伸缩性、异步消息队列、集群等内容。DNA 可以开发基于 Microsoft 平台的服务器构件应用,其中,如数据库事务服务、异步通信服务和安全服务等,都由底层的分布对象系统提供。

Microsoft 的 DCOM/COM/COM+技术,在 DNA 2000 分布计算结构基础上,展现了一个全新的分布构件应用模型。首先,DCOM/COM/COM+ 的构件仍然采用普通的 COM(Component Object Model,构件对象模型)模型。COM 最初作为 Microsoft 桌面系统的构件技术,主要为本地的 OLE(Object Linking and Embedding,对象连接与嵌入)应用服务,但是随着 Microsoft 服务器操作系统 Windows NT 和 DCOM(Distributed Component ObjectModel,分布式构件对象模型)的发布,COM 通过底层的远程支持使得构件技术延伸到了分布应用领域。DCOM/COM/COM+更将其扩充为面向服务器端分布应用的业务逻辑中间件。

通过 COM+的相关服务设施,如负载均衡、内存数据库、对象池、构件管理与配置等,DCOM/COM/COM+将 COM、DCOM、MTS(Microsoft Transaction Server,微软事物处理服务器)的功能有机地统一在一起,形成了一个概念、功能强的构件应用架构。

通过购买商用构件(平台)并遵循其开发标准来进行应用开发,是提高应用软件开发效率的常见选择

9.9.2 应用系统簇与构件系统

除专门开发构件的企业外,开发应用系统的企业也会发展自己的构件应用体系:通常是随着企业的不断成熟,逐步从已开发的应用系统中整理出来一些构件,反过来,将这些构件复用到优化与整合已有应用系统中或复用于开发新的应用系统。

一个应用系统中的复用率毕竟有限,通常在应用系统簇中进行软件构件复用。当要开发若干相关的应用系统时,可以先按复用的要求,界定这一组应用系统的共同“特性”,根据这些共同特性,建立模型,并按照复用的要求,将模型分解成恰当规模和结构的构件,对这些构件进行设计、实现、打包、编写文档,形成方便使用的可复用构件。这批可复用构件将用于支持该应用簇的各个应用系统的开发工作。这里的构件特指一个封装的代码模块或大粒度的运行模块。

软件企业将相关的构件有机地组织在一起,形成构件系统(较构件库层次更高),实施复用的软件企业通常拥有多个构件系统,有的是购置的,有的是自己开发的。

应用系统和构件系统都是系统产品(而不是工作产品)。它们都可以采用模型和结构的类型定义出来。一般情况下,构件系统只在开发单位内部使用,而应用系统提供给外部客户,与应用系统相比,构件系统具有通用性,可复用性,这就要求构件系统的开发过程应当实施更为严格的工程规范。

一个构件系统是能提供一系列可复用特性的系统产品。构件系统中的构件应当是高内聚、低耦合的,但构件之间应有若干种关系;可以发送消息给其他构件;可以与其他构件联合,支持协同工作。构件系统应当是易于理解和易于使用的,对构件应当是仔细地进行建模、实现、制作文档、测试等,便于以后的有效维护和改进。通常为支持构件的复用,应开发与构件系统相配的工具箱。

应用系统可以向构件系统输入构件(构件的需求源于应用系统或应用系统中的模块),反过来,构件系统向应用系统输出构件。这就是构件系统如何获得构件和如何提供构件的方式。

9.9.3 基于复用开发的组织结构

基于复用的开发组织与传统的开发组织结构不同,它需要有一部分用于开发可复用资产的资源,这部分资源应同具体应用系统的开发资源分开,以确保不被占用。

一种较平衡的组织结构如图 9-21 所示,它有三类职能部门:一是构件系统开发部门,它开发可复用资产;二是应用系统项目开发部(多个),它复用资产;三是支持部门,这个部门是可选的,它进一步隔离上述两主体部门,虽然牺牲了一些效率,但保证了构件的规范性。它的主要职责是对构件开发部门所提供的可复用资产进行确认、对构件库进行分类编目、向开发应用系统的工程师们发通告和分发可复用资产、提供必要的文档、从复用者处收集反馈信息和缺陷报告。可以这样理解:构件系统开发部门开发的构件系统由支持部门向应用开发部门推广,即支持部门是企业内的推广部。外部购买的商用构件也由支持部门维护与管理。

这三个平行部门之上有一个高层经理(复用经理),他关注总目标,协调相互关系。

一方面,构件开发者应当尽量接近应用开发者,以使其开发出的构件能尽量符合实际需要;另一方面,构件开发者与应用开发者分属两个并列的部门,使构件开发者能摆脱应用项目的日常压力,保证可复用资产的开发和持续改进。复用经理应当在构件开发和应用项目开发利益之间进行权衡,保证长期目标不受近期项目压力的影响。

9.10 产品线及系统演化

软件企业追求长远的发展,通常采用产品线模型及系统演化策略,它实质上是用架构技术构建产品线,并在此基础上借助复用技术持续演化,不断地推出新产品,满足市场追求产品升级换代的需求。

9.10.1 复用与产品线

软件产品线是指一组软件密集型系统,它们共享一个公共的、可管理的特性集,满足某个特定市场或任务的具体需要,是以规定的方式用公共的核心资产集成开发出来的。即围绕核心资产库进行管理、复用、集成新的系统。核心资产库包括软件架构及其可剪裁的元素,更广泛地,它还包括设计方案及其文档、用户手册、项目管理的历史记录(如预算和进度)、软件测试计划和测试用例。复用核心资产(特别是软件架构),更进一步采用产品线将会惊人地提高生产效率、降低生产成本和缩短上市时间。

创建一个成功的产品线取决于软件工程、技术管理和组织管理等多个方面的协调,这里只对软件架构方面进行讨论。

基于产品间共性的“软件”产品线代表了软件工程中一个创新的、不断发展的概念。软件产品线的本质是在生产产品家族时,以一种规范的、策略性的方法复用资产。可复用的资产非常广,包括以下几点。

需求:许多需求与早期开发的系统相同或部分相同,如网上银行交易与银行柜面交易。

架构设计:原系统在架构设计方面花费了大量的时间与精力,系统成功验证了架构的合理性,如果新产品能复用已有的架构,将会取得很好的效益。

元素:元素复用不只是简单的代码复用,它旨在捕获并复用设计中的可取之处,避免(不要重复)设计失败的地方。

建模与分析:各类分析方法(如性能分析)及各类方案模型(如容错方案、负载均衡方案)

都可以在产品中得到复用。

测试:采用产品线可积累大量的测试资源,即在考虑测试时不是以项目为单位,而是以产品线为单位,这样,整个测试环境都可以得到复用,如测试用例、测试数据、测试工具,甚至测试计划、过程、沟通渠道都可以得到复用。

项目规划:利用经验对项目的成本、预算、进度及开发小组的安排等进行预测,即不必每次都建立工作分解结构。

过程、方法和工具:有了产品线这面旗帜,企业就可以建立产品线级的工作流程、规范、标准、方法和工具环境,供产品线中所有产品复用。如编码标准就是一例。

人员:以产品线来培训的人员,适应于整个系列的各个产品的开发。

样本系统:将已部署(投产)的产品作为高质量的演示原型和工程设计原型。

缺陷消除:产品线开发中积累的缺陷消除活动,可使新系统受益,特别是整个产品家族中的性能、可靠性等问题的一次性解决,能取得很高的回报。同时也使得开发人员和客户心中有“底”。

9.10.2 基于产品线的架构

软件产品线架构是针对一系列产品而设计的通用架构,并在此基础上,进一步将系列产品共用的模块事先实现,供直接重用;将架构用框架的形式予以实现,供定制使用。这就是通常所说的“平台”。

产品线架构较之单个产品架构,有如下三点特别之处:

产品线的软件架构应将不变的方面提出来(正因为有不变,才产生了产品线),同时,识别允许的变化,并提供实现它们的机制。通常应考虑三个方面。

包含或省略元素:如条件编译。

包含不同数量的复制元素:如通过添加更多的服务器产生高容量的变体。

具有相同的接口但具有不同的行为或质量特性的元素版本的选择:如静态库和动态链接库的使用。

在面向对象的系统中,通过特化或泛化特定的类实现变化。

通过参数配置来实现变化。

评审方法:见下节的软件架构评估。

评估的内容:必须把评估的重点放在变化点上,以确保它(变化点)提供了足够的灵活性,从而能覆盖产品线的预期范围;它们支持快速构建产品。

评估的时间:应该对用于构建产品线中的一个或多个产品的架构的实例或变体进行评估。产品架构评估的结果通常能提供有用的反馈,推动架构的改进。当提议开发的一个新产品不在最初的产品线的范围内时,则可以重新对产品线架构进行评估,看如何使其容纳新的产品或是否有必要产生一个新的产品线。

9.10.3 产品线的开发模型

开发(确定)产品线的方法有两种模型:

一旦确定了产品线,就进入其演变阶段,它是产品线不断向前的发展过程。

9.10.4 特定领域软件架构

架构的本质在于其抽象性。它包括两个方面的抽象:业务抽象和技术抽象。其中业务抽象面向特定的应用领域。

特定领域软件架构(Domain Specific Software Architecture,DSSA)可以看做开发产品线的一个方法(或理论),它的目标就是支持在一个特定领域中有多个应用的生成。DSSA 的必备特征有:

从功能覆盖的范围角度理解 DSSA 中领域的含义有两种方法:

DSSA 的活动阶段如下。

在上述工作中,获得领域模型是基础也是关键,领域建模专注于分析问题领域本身,发掘重要的业务领域概念,并建立业务领域概念之间的关系。通常领域模型可用 UML 的类图和状态图表示。

希赛教育专家提示:对于中等复杂度的项目,应该在系统的领域模型中找到大约50 到100 个类。

领域模型的主要作用如下:

9.10.5 架构及系统演化

架构虽然为系统的变化提供了一定的自由度,但是系统的较大变化必然导致架构的改变。

架构(系统)演化是指向既定的方向、可控地改变。架构(系统)演化可以形成产品线,反过来,架构(系统)可以在规划的产品线中进行演化。

架构(系统)演化过程包含 7 个步骤,如图 9-22 所示。

9.11 软件架构视图

9.10 节从软件架构本身的特点出发讨论了架构建模及与特定应用领域密切相关的架构风格。本节将从对架构编档的角度对软件架构视图及其风格进行讨论。

9.11.1 软件视图的分类

现代软件系统非常复杂,通常在某个具体的时间内只需将注意力集中在某几个结构上(就像看病时,医生只是将注意力集中在某方面的人体结构上,骨科医生与心血管科医生关心不同的结构),结构是元素本身的集合,而视图则是捕获和表达结构(文档描述),虽然它们有区别,但在实际使用时则不严格区分,即从系统体系的角度说是结构,从文档角度说是视图,因此,本节将不再区分结构和视图术语。

软件架构是一种无法以简单的一维方式进行说明的复杂实体,从不同侧面的描述就是视图。架构的优势也在于使用视图:每个视图强调系统的某一个方面,同时忽视系统的其他方面,以便有助于处理或理解当前问题,描述完整的系统架构必须具备完整的视图集, “4+1”

方法就是一类完备视图集。

软件视图通常分为三种类型:

大量的架构风格供架构设计师选用,例如客户机/服务器是一种常见的架构风格,它是构件和连接件视图类型中的一员。架构风格是对元素和关系类型的特化,它还包括如何使用这些元素和关系类型的一组限制条件。架构结构/视图分类如表 9-10 所示。下面各小节中再分别对这三种类型及其风格从元素、关系及特征方面做进一步总结。

9.11.2 模块视图类型及其风格

模块将遵循某种方式将软件系统分解成可管理的功能单元。架构模块视图是通过文档来枚举系统的主要实现单元或模块,及这些单元之间的关系。

任务完整的架构文档必须包含有模块视图,它为源代码提供蓝图。该类型如表 9-11 所示。

下面对模块视图的四种风格进行总结。

9.11.3 C&C 视图类型及其风格

C&C 视图能定义由具有某种运行时存在的元素模型,这些元素包括进程、对象、客户机、服务器及数据存储器等。此外,它还包含作为元素的交互路径,如通信链路和协议、信息流及共享存储器访问。通常,可利用复杂的基础结构(如中间件框架、分布式通信信道和进程调度)来执行这些交互操作。该类型总结如表 9-16 所示。

C&C 视图风格是 C&C 视图类型的特化,C&C 视图风格为数不少,下面对 C&C 视图的几种风格进行总结。

点击查看大图

该风格总结如表 9-21 所示。

9.11.4 分配视图类型及其风格

硬件、文件系统和团队结构都会与软件架构进行交互,将软件架构映射到其环境的一般形式称为“分配视图类型”。该类型总结如表 9-23 所示。

分配视图类型的三种常见风格为:

部置风格:能描述构件和连接件对硬件的映射,硬件是软件执行的场所。

实现风格:能描述模块对包含它们的文件系统的映射。

工作任务风格:能描述模块对承担模块开发任务的人员、团队或小组的映射。

工作任务风格与模块分解风格关系密切,它能将模块分解风格用作其分配映射的基础。

这种风格能通过添加与开发工具、测试工具和配置管理系统等对应的模块分解进行扩展。工作任务风格还通常与其他风格联合使用,例如,团队工作任务可以是模块分解风格中的模块,可以是分层图中的层,也可以是多进程系统中的任务或进程。

9.11.5 各视图类型间的映射关系

为了完整地描述一个架构,必须使用多个视图,这些视图必须遵守一定的映射关系。