第18章 用商业组件构建系统

 
 
在整本书中我们都强调了所期望的质量属性和构架之闾的关系„我们所做的趣本假设 是控制系统设计就可以控制所实现的质量厲性。慢慢地这变得不再正确。现在,所构造的 系统采用了越来越多的商业组件,这•方面是为了节约成本,还有就足在许多方面所需要的技术太专业了。组件改变了设计过程,它们还可能会限制构架。尽管所选择的商业组件 通常是用来实现某些功能组,但组件还包含构架(因此还有质量〉假设。设计师必须确保 这些假设是正确的,而且是一致的。
 
自从20世纪60年代以来.操作系统就强加了某些解决方案。在20肚纪70年代初期 出现了数据库管理系统。由于计算机无处不在.因此使用外部开发的组件来实现某些系统 目标的可能性有了很大提高。尽管组件的可用性不会使您使用或保留它们(参见引文 Quack.com).但您肯定需要理解如何将它们集成到系统中.
 
对于用商业组件构建的系统,组件选择涉及•个发现过程,该过程确定兼容组件的“装 配”,理解它们如何实现所期望质量属性,并确定是否可以将它们集成到所构建的系统中。
 
在以快速可用的打包形式提供大量功能时,商业组件起到了非常重要的作用.然而, 它们也妨碍了设计师对系统的质量属性进行总体控制.与在软件工程中非常相似,组件非 常有用,但它们并不是银弹,虽然有时会这样描绘它们。
 
本章描述了很容易做到的、一般意义上的过程,它可以指导组件选择。该过程先假定 对您选择“工作”的组件来说意味着什么,构建.些简单的原型来测试这些假设,演变发 挥作用的部分.并保留-份备用计划以防猜测是错误的。此处要说明的是不仅要选择和挑选组件,而且要选择并测试将要协同工作的组件的装配。
 
本章给出了某个过程的-个演示,该过程应用到了一个最近进行现场试验的系统中。
 
18.1组件对构架的影响
考虑如下情况。您正在生产控制化学工厂的软件。在化学工厂中,专门的显示可以使 操作员了解到在进行的化学反应的状态。您正在构造的软件的很大部分都用来绘出这些 显示。某家厂商销售产生这些显示的用户界面控制软件。因为与自己构建相比,购买要容 易一些,因此您决定购买控制软件——顺便说一下,该软件仅支持Visual Basic。
 
这•决策将会对您的构架产生什么影响?要么用带有其内建的以回凋为中心样式的 Visual Basic编写整个系统,要么用某个方式将操作员部分与系统的其余部分隔离开。这是 一个基本的构架决策,由该系统的某个部分的某个组件的选择驱动。
 
在许多情况下.在软件开发中使用商业组件都是很基本的,但这也会带来新的挑战„ 特别地,组件能力和责任是一个原理构架限制。
 
除了最简单的组件外,所有组件都有一个很难违反的假定的构架模式-例如,HTTP 服务器假定客户机服务器构架模式,该模式具有已定义的接口以及用于集成后端功能的机 制。如果您设计的构架与HTTP服务器组件所假定的构架冲突,则很难进行集成。
 
由于组件假定了一种构架模式.因此,在理解为所设计的系统选择的(或正在考虑之 中的)组件进行装配前,很难选择构架。组件选择通常会规定这些组件中固有的构架假设 和成功集成这些组件的机制,或至少是对其造成很大影响。这意味着在最终确定构架前, 必须确定对组件及其交互的理解。
 
18.2构架不匹配
并不是所有的组件都能够协同工作——即使它们是宣称具有兼容性的商业产品。组件 通常是“几乎兼容”,在这里.“几乎”是“不”的一种委婉说法。最危险的情况就是组件 看上去能够协同工作——汇编代码能够编译甚至能够执行~~但系统产生了错误的答案, 因为组件不能按照期望的那样协同工作。错误可能是微妙的,尤其是在实时或并行系统中, 在这些系统中,组件可能依赖于从表面上看对于彼此之间操作的时间或相对顺序的无害的 假设。
 
简而言之,不是专门针对您的系统开发的组件可能不会满足您所有的需求——它们甚 至不会与您为之配对的组件协作。更糟糕的是.只有在购买了组件并将其用在系统中后,才能知道这些组件是否合适,因为组件接口基本上没有指定其质量属性:您正使用的编译 器的安全性如何?您的台式机上的邮件系统的可靠性如何?您的应用所依赖的数学库的 准确性如何?当您发现在上述这些问题中任何一个问题的答案为“不够充分”时,会发生 什么情况?
 
Garlan, Allen和Ockerblcom使用术语“构架不匹配”来描述成功集成基于组件系统 的这障碍。他们把问题陈述为单独开发的组件中所包含的假设之间的不匹配.这通常体 现在构架方面,如当两个组件没有谁调用谁达成一致时。构架不匹配通常在系统集成时出 现——系统不编译、不连接或不运行。
 
构架不匹配是“接口不匹配”的一种特殊情况,这里的接口正如Pamas所定义的:组 件可以对彼此所做出的假设。遗憾的是,该定义已经超出了当前实践中接口的标准概念: 组件的API (例如.Java接口规范)。API命名了程序及其参数,并且可以给出关于其行为 的一些信息.但这仅是正确使用组件所需要的信息的一小部分。副作用、全局资源的消耗、 协调需求等都是接口的必要部分,完整的接口规范中都包括这些内容。接口不匹配可能会 出现在集成时间,正如构架不匹配一样,它还可能会促使发生以前提到的危险的运行时错误。
 
这些假定可以有两种形式。“提供”假定描述了组件为其用户或客户提供的服务。“需 求”假定详述了组件为了正确地发挥功能必须拥有的服务或资源。当两个组件的提供假定 和需求假定不匹配时,两个组件就会出现不匹配。
 
出现接口不匹配时.可以采取什么措施?除了改变需求以使以前的错误成为现在的特 性外(这通常是一个可行的选择),还可以采取如下3个行动:
 
•    通过仔细“规定”和审査系统的组件来避免接口不匹配
 
•    通过仔细的组件“限定”来检测没有避免的那些情况
 
•    通过“适配"组件来修复您已经检测到的那些情况
 
本节余下的部分将讨论避免、检测和修复不匹配的技巧-我们首先讨论修复不匹配的 技巧。
 
18.2.1修复接口不匹配的技巧
 
到此为止,几乎没有系统关注不匹配纠正(“或组件/接口修复”)。诸如“组件glue" 这样的术语使我们想到了集成代码的字符,并且反映了我们分配给其开发的第二类状态。 修复接口不匹紀通常被看作是黑客(或经验不多的程序员〉的工作.因为集成商业组件中 的无数“hack”不会破坏他们的美感。然而,我们大家都知道.链条中最弱的•环决定了 该链条的强度。因此,组件修复的质量可能直接决定了是否能够实现系统范围内的质量属 性,如可用性和可修改性。
 
更加规范的接口修复方法的第一步就是对基本的技巧及其质量属性进行分类。一个明 显的修复方法就是改变损坏了的组件的代码。然而,商业产品很少提供源代码,旧组件的 源代码可能已经丢失,或者惟一理解该组件的人已经不在这家公司了.考虑到上述这些情 况,这样做通常是不可能的。即使是可能的,我们通常也不想改变组件。该组件用在不止 一个系统中一使用组件的前提一如果改变该组件(以使其正常发挥作用)使得它在很 多旧系统中都不能使用,那么.现在必须在多个版本中对该组件进行维护•
 
改变(一个或两个)不匹配组件的代码的替代方案是插入一种修复不匹配的方式调解 其交互的代码。有3类修复代码:包装器、桥和中介器。
 
1.包装器
 
术语包装器暗含了 .种封装形式,我们用此形式把某个组件装在一个可选的抽象中。 这意味着客户只通过该包装器提供的替代接口就可以访问所包装的组件服务。可以把包装 看做是产生了组件的替代接口。可以把接口翻译解释为:
 
•    把组件接口的某个元素翻译为替代元素
 
•    隐藏组件接口的一个元素
 
•    保存组件的基本接口的一个元素(不改变)
 
举一个例子.假定我们有个早期组件,该组件提供对图形渲染服务的编程访问,其 中可通过编程访问的服务以Fortran库的形式提供,图形渲染以定制图元的形式进行。我 们希望客户可以通过CORBA访问组件,并且希望用X Window System图形代替定制图元。
 
可以使用CORBA的接口描述语言(IDL)来指定可以使CORBA客户获得组件服务 的新接口,而非通过与Fortran库连接得到。“提供假定”接口的修复代码是由IDL编译器 自动生成的C++框架代码。修复代码中还有将框架打入组件功能的手写代码。
 
有各种方法用来包装组件的“需求假设”接口,以完成从定制图形到X系统的转换。
 
•个方法就是编写一个翻译器库层,其API与定制图元的APi对应;该库的实现将定制图 形调用转换为X Windows调用。
 
2.桥
 
桥把任怠•个组件的需求假设转换为另一个组件的提供假设。桥和包装器的关键区别
是组成桥的修复代码独立于任何特定的组件。还有,桥必须由某个外部代理显示调用-
可能会由桥所连接的一个组件调用,但也未必。最后一点传达了这样.种观念’即桥通常 是暂时的.特定的转换是在桥构造时定义的(例如桥编译时)。在对中介器的讨论中,我 们将会淸楚地看到这些区别的重要性。
 
与包装器相比.桥通常集中在一个较窄的接口转换范围内,因为桥解决的是具体的假 定。桥试图解决的假定越多.它适用的组件就越少。
 
假定有两个早期组件:个组件为设计文档产生PostScript结果,个组件显示PDF (可移植文档格式)文档。我们希望对这些组件进行集成,以对设计文档调用显示组件。
 
在该场景中.个简单的接口修复技巧就是把PostScript转换为PDF的一个简单的桥. 可以独立于两个假定组件的具体特性编写该桥一用于从•个组件中提取数据.然后把它 传递到另一个组件中的机制。这让我们想到了 UNIX过滤器的使用,尽管这并不是可以使 用的惟一机制。
 
可以编写个脚本来执行该桥。对于两个集成组件来说.需要满足特定于组件的接口 特性。因此,根据我们的定义,外部代理/shell脚本不是包装器,因为它满足的是集成关 系的两个端点的接口。另一种选择是,这两种组件都能发射-个过滤器。在这种情况下.修 复机制包括•个包装器和过滤器的混合体:包装器包括所需耍的修复代码.这些代码用于检测 是否需耍发射桥并启动这-发射。
 
3.中介器
 
中介器展示了桥和包装器的属性。然而,桥和中介器的主要区别就是中介器集成了“规 划”功能.这实际上导致了转换的运行时确定(回想•下,桥是在桥构建时建立该转换的)。
 
从中介器变成了总体系统构架中更明显的组件这一点来说,中介器也与包装器非常类 似。也就是说,可以把语义简单且通常是暂时的桥看做是附带的修复机制,其在设计中的 角色可以保持为隐含的:相反.中介器具有足够的语义复杂性和运行时自适应(持续性), 以在软件构架中不仅仅扮演第一类的角色。为了对中介器进行说明,我们把重点放在其运 行时规划功能上,因为这是中介器和桥之间的主要区别。
 
说明中介的一个场景是智能数据融合。考虑-个生成大量高保真数据的传感器.在运 行时.可能会出现不同的信息使用者,他们对数据保真有不同的操作假定。大概某个低保 真使用者要求从数据流中除去某些信息。另一个使用者可能具有类似的保真耍求但对吞吐 量特性的要求不同,他要求将数据暂时缓存起来。在每种情况下,中介器都可以调节传感 器和其使用者之间的差别。
 
另•个场最涉及桥序列的运行时装配,以集成其集成需求在运行时出现的组件。例如, 个组件可以用D0格式产生数据,而另一个组件可能会用格式D2使用数据。可能没有直 接的D0—D2桥,但是有可以连接起来的单独的D0—D1和D1—02桥。因此,中介器将对 桥进行组装,以完成D0—D2的转换。该场景涉及常见的桌面集成概念和不太常见的运行 时适配系统。
 
18.2.2检测接口不匹配的技巧
 
为了修复不匹配.我们首先必须检测或确定它们。我们把确定不匹配的过程表述为组
件认证的一种增强形式。
 
术语“组件认证”用来描述确定-•个商业组件是否满足了各种“适用性”标准的过程。
 
-些组件认证过程将候选组件的原型集成作为对组件进行认证中的基本步骤。该集成步骤 发现了很难检测到的接口不匹配的微妙形式.如资源争用。需要该步骤等于默认了我们对 组件接口的理解非常贫乏。
 
对于组件提供的每个服务.必须满足一组需求假设.以提供该服务,执行该评估首先 要做的就是观察-•下是否做到了这一点。服务仅是一个描述如何对组件功能进行打包以供 客户使用的方便形式。那么,认证过程为:
 
•    为该系统将要使用的每个服务描述组件的所有需求假定
 
•    确保每个需求假定都由该系统中的某个提供假定满足
 
为了更具体地说明这些思想,考虑一下为多线程应用提供简单的数据管理服务的组件 的认证,它所提供的-项服务就是把数据值写到指定位置(可能由关键字指定)的能力。 为了提供多线程存储服务,组件可能要求操作系统提供各种资源一例如,•个文件系统 和锁定原语。可能会由组件提供者把组件的需求假定的列表编成文档,或者可能需要由组 件评估者发现。在任何•种情况下.对于确定操作系统的升级是否会对这一特定的集成关 系产生任何影晌.该特定映射都是有用的。也就是说,新的操作系统是否改变了 [write或 flock的语义?
 
该列表可能会包含额外的假定。例如,提供假定可能会规定应该把CORBA接口提供 给存储服务。根据所使用的对象请求代理的不同实现,这可能意味葙(也可能并不意味着) 额外的提供假定,该假定是关于执行存储服务的主机上的运行对象凊求代理进程的存在性 的假定。
 
假定列表可能会揭示出更有趣的依赖性。例如,相同的假设组件可能会允许•个变化 的但已经定义的客户机数量来共享-个数据管理器前端进程,并用创建的新进程来容纳溢 出的客户机。在预测组件是否会满足系统资源限制方面,这种形式的假定可能是非常关 键的。
 
18.2.3避免接口不匹配的技巧
 
避免接口不匹配的•个技巧就是从设计的最早阶段就采用一种规范的方法,在可行的 情况下,对组件的接口指定尽可能多的假定。指定组件对其环境做出的所有假定是否是可 行的或可能的?允许使用的组件对其环境做出假设是否是可行的或可能的?当然不是。是否有任何证据表明可以指定假定的•个子集?这样做是否值得?是的。第3章讲述的A-7E 软件设计把系统划分成了模块的一个层次树.最高层有3个模块.它们分解为叶子结点上的大约120个模块。为每个叶子模块编写了接口规范,包括访问程序(现在,在基于对象 的设计中被称为方法)、它们所要求和返网的参数、调用该程序的显著效果、允许该模块 的编译时剪裁的系统生成参数以及一组假定(每个模块大约有丨2个)》
 
假定通过确定模块所必须的资源,来陈述关于每个模块所提供的服务的“充分性”的 断言以及每个服务的“可实现性具体的主题包括共享资源的使用,以及通过模块的机 制、性能控制多线程的效果。这些假定在系统的生命期内保持不变,其主要设计目标是可 修改性。模块设计人员使用这些假定来保证已经适当地封装了一个模块中变化的所有方 面:领域专家和应用专家使用这些假定作为评佔的介质;模块的用户使用这些假定来确保 适宜性。A-7项目的参与人员感到仔细关注模块接口可以有效地消除软件生命期中的集成 步骤。为什么?因为通过仔细的规范可以避免构架不匹配,包括应用专家和领域t家进行 准确评审的明确的假定列表。
 
作为-组假设而不仅仅是API的接U的概念,可能会导致对如何指定在各种上下文中 协作的组件的接口产生更丰富的理解。私有接口只对组件的基本接口的那些提供和需求假 定可见,这些假定与其在特定系统中的集成需求相关,甚至与某一特定系统中的特定组件 相关。其思路就是禁止不需要的信息,这些信息的出现可能会不必耍地使系统复杂化。
 
与采用一个功能混合的基本接口相比,对相同的组件采用不同的接口有很多优点。对 组件间依赖的较精细的控制使得某种系统演变的可跟踪性更强——例如,预测升级一个商 业组件对新版本的影响。可以把包装器看做是引入秘密的修复策略。此外,构架模式可以 为该接U提供满足提供假定和需求假定的规范形式,以使在基于个定义了一小组组件类 型的构架模式的系统中.基本接口的不同派生接口的数量可以相对较少。
 
“参数化的”接口就是在调用组件服务前,可以通过改变变量的值来改变其提供和需求假定的接口。编程语言长期以来直拥有语义丰富的参数化技巧(如Ada Generics、ML 多态),在从设计和编码到调用其服务的期间,这些技巧对组件的接口进行剪裁。商业产 品也经常通过产品参数化来提供某种程度的定制(例如资源文件或环境变里)。参数化的 接口导致了不仅在组件外部(在这里设参数的值),而且在组件内部(以容纳不同的参 数值)的适配接口。
 
正如中介器是具有规划逻辑的桥•样,“协商接口”是具有自修复逻辑的参数化接口。 它可能是自动参数化本身,也可能是由外部代理进行参数化。可以把自配置软件看做是涉 及协商接口的软件,其中,协商是组件构建软件和主机平台之间的单向“拒绝或接受”对 话.可选地,诸如调制解调器这样的产品例行公事地使用协议在运行时(而非在安装时) 建立相互可接受的通信参数。
 
像可以作为修复策略来引入半透明的包装器一样,可以把中介器作为修复策略.以把 协商的接口引入非协商的组件中。
 
 
18.3作为搜索的基于组件的设计
 
因为组件能力和责任是系统开发中的构架限制的主要来源.而且系统使用多个组件, 因此,基于组件的系统设计就成为了搜索能够最好地满足系统目标的兼容的商业组件整体 (组件整体)。设计师必须确定是否可以集成每个整体中的组件,尤其是要评估-个组件 整体是否适合构架.并且支持系统需求。
 
实际上,毎个可能的组件整体都是探索的延续路径。该探索最初应把重点放在路径的 可行性上,以确保没有不能进行合理改编的重要的构架不匹配。它还必须考虑修复的可行 性,以及在修复完成后剩余的风险。
 
当然,同时探索多个路径是昂贵的。正如在示例中所展示的那样.我们更有可能把重 点放在主路径上,而把其他路径作为辅助路径。重点是要整体选择组件,而非逐一进行选 择,并且要记住,某个特定的路径组成了 一个要被验证的假定,而非一个己经确定的设计。
 
“在处理组件占支配地位的构架时,如何实现系统的质量属性? ”。第一个答案可能 是不能实现系统的质量属性。在许多情况下,使用现有的商业软件包在短时间内部署更大 功能的能力可能比性能、安全性或其他系统需求更重要。使用OTS组件有时会模糊需求 和系统设计之间的界限。对组件进行评估通常会导致对系统需求的修改,增加可以部署的 能力的期望,同时迫使重新考虑其他“需求”。
 
在基于组件的系统的集成中,系统需求中的某些灵活性是有益的.但是,识别对系统 的成功来说很基本的需求,并且不允许损害这些需求也很重要。然而.如何确保在以组件 为主导的构架中维持基本的质量属性?
 
在上一节中.我们提到了组件集成是一个主要的风险区域,系统设计师必须确定集成 组件整体的可能性.以使系统在功能上是完整的,并满足其质量属性需求。然后,必须对 组件整体进行评估,以确保不仅能成功地集成组件,而且它们还可以支持质量属性目标。 为了评估组件整体的可行性,包括其支持系统期望的质量属性的能力,我们使用模型问题。
 
在•个狭窄的范围内,可以把“模型问题”定义为对设计上下文的描述.它定义了对 实现的限制。例如,如果开发中的软件必须提供可以由 Netscape的Navigator和Microsoft 的IE使用的基于Web的接口,则设计上下文的这•部分就限制了解决方案空间。所要求 的任何质量厲性也包含在设计上下文中。
 
位于具体设计上下文中的原型被称为“模型解决方案"。模型问题可以有任意数量的 模型解决方案,这取决于设计上下文中风险所固有的严重性以及解决该风险的模型解决方 案的成功。
 
模型问题通常由设计小组使用。在最理想的情况下,设计小组由设计师和许多设汁人 员/X程师组成;前者是该项目的技术负责人,并负责制定主要的设计决策,后者可以为模型问题实现•个模型解决方案。
 
阁18.1给出了对模型问题工作流的说明。该过程由如下6个可以按顺序执行的步骤
 
(1)设计师和工程师确定“设计问题”。设计问题启动模型问题,它指向表示为假设 的一个未知问题。
 
(2)设计师和工程师定义“开始评估的标准”。这些标准描述了该模型解决方案将如 何支持假定或与假定相矛盾。
 
(3)设计师和工程师定义“实现限制”。实现限制规定了支配模型解决方案实现的设 计上下文的固定(不可改变的)部分。这些限制可能包括诸如平台需求、组件版本和业务规则这样的内容。
 
(4)工程师产生一个位于设计上下文中的“模型解决方案”。模型解决方案是-个仅 使用支持假定或与假定相矛盾所必须的一个组件(或多个组件)的特性的最小应用。
 
(5)工程师确定“结束评估标准”。结束评估标准包括starting    set plus标准,这是实 现模型解决方案的一个副产品。
 
(6)设计师根据结束标准对模型解决方案进行“评估”。评估的结果足拒绝或采用设 计解决方案.但通常也会导致出现必须以类似方式解决的新的设计问题。
 
在本章的余下部分,我们将介绍一个示例,并说明这些步骤在一个基于 Web的应用 ASE丨LM的开发中的应用。
 
 
“ATAM,艺术在哪儿”
本章对选定的组件整体是否能够满足使用这些组件的系统的质量和行为需求进行了 讨论,这很明显是一个构架问題.那么,为什么不使用诸如ATAM这样的构架评估方法回 答此问趙?毕竟,ATAM的目的就是根据系统的质量和行为需求对构架决策进行评估(如 使用用特定的方式“连接”起来的某些组件的决策).为什么不简单地说成"在这里进行 基于ATAM的评估”以及应该用此方法进行评估?
 
答案就是本章所描述的过程很少是关于评估打包的构架决策集的结果,而更多的是关 于帮助您制定这些决策的活动.活动更像是建立原型而非分析评估.
 
ASEILM示例说明了在开发人员开始思考所得到的组件整体如何提供各种质量属性 前,必须解决多少非常详细的兼容性问題„仅把组件整体放在一起就是一个挑战.在处理 一个组件整体时,另一个组件整体正整装待发,以防第一个组件整体不能产生预期的结果. 该过程能够使我们管理候选组件整体之间的欺骗动作,并且它能够使我们通过设计出小 的、实用的和常识性的步驟,以一种合理的方式在组件整体之间做出选择..
 
每个候选的组件整体都暗含了几个声称知道自己正在做什么的假定.您以半并行的方 式进行,将组件整体彼此连接起来,并将组件整体与系统的其余部分连接起来,直到您发 现“并不”知道自己在做什么„然后,您试着用不同方式把它们连接在一起,或者开始考 虑计划B (下一个组件整体).典型情况下,因为您发现自己并不知道组件整体如何管理 质量属性,因此才开始考處质量属性„
 
为了进行ATAM评估,您需要了解正在使用的组件的某些情况.描述这个过程的的目 的是要说明,现在还不清楚您知道什么.
 
我们已经用某个方法把该过程包装起来,以使其更可重复和可学习,但这只是常识. 您对于应该使用什么组件做了 一个见多识广的猜测,构建了原型来对组件和其交互进行测试,演变发挥作用的组件,并保留一份备用计划以防止猜测是错误的.关鍵是要知道您应 该用组件整体进行此項工作,而不是一次用一个组件。
 
用这种方式对组件整体进行验证后,它(以及它所包含的系统的构架)是否仍然是 ATAM评估或其他构架评估的主题?绝对是.
——UB和PCC
 
 
posted @ 2019-12-04 23:11  mongotea  阅读(175)  评论(0编辑  收藏  举报