正如我们反复看到的一样,系统的软件构架在系统开发和开发该构架的组织中起到了 -个中心作用。对于系统和开发系统的项目,构架起到的是蓝图的作用。它定义了必须由 设汁和实现小组完成的工作任务,是系统质量厲性的主要载体,如性能、可修改性和安全 性。如果没有统一的构架构想,任何一个质量属性都无法实现。构架是一种用于早期分析. 以确保设计方法将产生一个可接受的系统的制品。此外.在系统部署后对系统的理解、维 护方面,构架也起着非常关键的作用。简而言之,构架足概念上的粘结剂,它为所有的涉 众将项目的每一个阶段结合在一起。
构架编档是创建构架的最有价值的一步。即使构架非常完美,但如果没有人理解它, 或(更糟糕的是)主要的涉众误解了它,它也没有什么用处。如果您创逮了 •个非常强大 的构架,那么,就必须用足够的细节明确地描述它,并以一种其他人可以快速找到所需要 信息的方式对其进行组织。否则,构架不会有什么用处,您所付出的努力也就白费了. 本章将帮助您确定耍捕获构架的哪些信息,并将讨论捕获构架信息的方针。本章还将讨论 有的表示法,包括UML。
9.1构架编档的使用
系统的构架取决于对构架的需求,因此构架的文档也取决于对文档的需求•一~•也就是 说.我们希望如何使用该文档。文档肯定不是•种“通用(one sizes fits all)“”情况。它应 该足够抽象,以使新员工能够很快了解:但也要足够详细,以能够作为分析的蓝图。比方 说.用于安全性分析的构架文档与实现人员将要使用的文档有很大不同。这两种文档又都不同于我们为使新员工熟悉该构架所提供的文档。
构架文档不仅是说明性的.而且是描述性的。也就是说,对于某呰观众來说,它通过 对要制定的决策做出限制,来说明哪些内容是真实的。对于其他观众来说,它通过叙述已 经做出的关于系统设计的决策,来描述哪些内容是真实的.
上述内容说明,文档的不同涉众具有不同的需要——不同种类的信息、不同的详细程 度的信息、对信息的不同使用方式。我们不应该期望产生一个构架文档,并且每个使用者 都用相同的方式使用它。相反,我们应该编制一个能够帮助涉众快速找到其感兴趣的信息, 并且妨碍找到信息的不相关信息最少的文档。
这可能意味者要为不同的涉众编制不同的文档。更有可能的是,这意味着耍编制-组文档, 该文档中有•个能够帮助不同的涉众在文档中导航的路线图(roadmap)。
通常.编写技术文档(尤其是软件构架文档)的最基本的规则之一•是从读者的角度来 编写。我们不会使用易于编写但很难阅读的文档,在这里,“易于阅读”指的是涉众能够 很容易阅读文档。
了解谁是涉众以及他们使用文档的方式可以帮助我们对文档进行组织,以使文档对涉 众来说可邢解和可使用。在第2章中.我们曾说过构架的主要用途足允3涉众之间进行交 流的工具,文档则促进了这种交流。表9.1给出了构架的涉众以及他们希望在文档中提供 的信息。
此外,可以将涉众分为两类:经验丰富的和缺乏经验的。缺乏经验的涉众希望获得的 信息与经验丰甯的涉众所需要的信息类似,但信息量少一些,介绍性的内容多些。对于 需要大致了解构架的人来说,阅读构架文档便是一个很好的选择:缺乏经验的开发人员、 资金赞助者、项目的参观者,等等,
介绍软件构架的文档
我刚表述完属性驱动的设计(ADD)方法(参见第7章L 一家大型制造公司的一个 业务部门的小组已经知道了我们所表述的大部分内容:ATAM (第II章)、重构(第丨0章) 和软件产品线(第14章).我非常愜意,心满意足地坐在那里.
然而,该客户还有一个问题需要解决„他们想进行基于构架的开发,但他们的开发组 很小,如果按照我们所表述的去做,需要花上几年的时间„然而,他们需要在合同期限内 完成产品的开发.他们没有足够的资源按照我们所讲迷的方法去做.现在,我们需要做的 是让他们采用基于构架的开发方法,但不需要理解涉及的所有内容,
讨论转向了文档和我们正在编写的关于软件构架编档的书籍.对于把文档作为维持公 司的产品知识的一种手段,这个客户很感兴趣.我们对构架重构进行实践,并根据本章描述的原则把结果编成文档,以此结束此次会议。
我一直认为文档是设计和开发过程的结束.从任何一个角度来说,构架都是必要的(沟 通、分析和培训 ),但它是派生的,而非驱动因素.
客户对此有持不同的看法.他们把对软件构架进行编挡看作是对其开发人员进行培训 的一个理想的手段,,在任何情况下他们都必须编写文档,因此,在企业文化中,为他们提 供一个把什么编成文挡的模板是顺理成章的事情在填写该模板的过程中,所必须把不同 的视图编成文档(我们需要为其定义有用的视图),他们需要证明他们设计的制品如何满 足了不同的质量目标,而且,在编写文档的过程中他们通常能够了解构架概念.
对我来说,将文档作为培训工具还是新事物,但它的作用非常强大.对一直纠缠于细节问题的人来说,考虑构架和构架问題是一个大的飞跃.看来对消费者来说,不需要很多 开销就可以通过文档理解软件构架中所包含的思想,这是一个非常不饼的培训工具。
——LJB
最渴望使用构架文档的大概就是设计师了、,他可能是设计该构架的人,也可能不是. 但无论在哪种情况F,他都需要査沂构架文档。新设计师对其前任设计师如何解决困难的 系统问题以及为什么制定了某个决策感兴趣。
即使未来的设计师是同一个人,他也会把文档作为知识的储存库。构架文档中有大蛩 洋细的设计决策,仅凭记忆不可能把当初的设计思路、决策全部回忆起来。
表9.1涉众和构架所满足的沟通需要
9.2视 图
与软件构架文档相关的最重要的概念大概就趄“视图”了。在第2章,我们把系统的 软件构架定义为“系统的一个或多个结构.它由元索、这些元素的外部可见厲性以及它们 之间的关系组成。”我们曾说过,视图就是构架元素的内聚集合的表示,由系统涉众编写 和阅读。结构就是元素集本身,因为元素存在于软件或硬件中。
在第2章我们讨论了作为复杂实体的软件构架。该实体不能用简单的思维方式描述。 我们可以用很贴近生活的建筑物的结构做•下类比,以对此进行说明。在搭建建筑物的结 构时,需耍考虑很多方面:卧室的布局、立面图、电气图、垂直图、通风图、通信模式、 采光视图和安全体系计划等。在这些视图中,哪个视图是构架?哪个都不是。哪些视阁传 达了构架?所有的视图都传达了。
视图的概念(可以将其看作是捕获结构)为我们提供了进行软件构架编档的基本规则:
构架编档就是将相关视图编成文档,然后向其中添加适合多个视图的文件。
该原则把构架编档问题分成了更多的易处理的部分,因此是通用的。本章余下部分将 阐述如下3个问题:
• 选择相关视图
• 对视图编档
• 将适合多个视图的信息放到文档中
9.3选择相关视图
在第2章我们鞞介绍过一组结构和视图。什么是相关视图? 了解涉众以及他们计划使
用文档的方式有助于您构建他们需耍的文档包。构架可以有很多用途——作为实现人员的 任务陈述.作为理解系统和资产恢复的起点以及作为项目规划的蓝阁等——每•个用途都 是由.个涉众所要求的。类似地,您和系统开发中的其他涉众最关心的质量属性将会影响 对哪种视图进行编裆的选择。例如.可以通过分层视图看出系统的可移植性。可以通过部 署视图推断出系统的性能和可靠性。诸如此类,不一而足。需要分析构架以确保提供了质 量属性的分析人员(或许是设计师)会要求在文档中提供这些质敏厲性。
简而言之,不同的视图支持不同的目标和用途。这就是我们基本上不提倡采用某个特 定视图或视阁集的原因。对哪些视阁编档取决于期望使用文档的方式。不同的视围强调不 同的系统元素和/或关系。
表9.2给出了具有代表性的涉众以及他们很可能会认为有用的视阁种类。您应该借助 该表考虑涉众是谁,以及哪些视图最适合他们。可以从哪些视图中进行选择?第2章给出 了一组视图,其中•些视阁反映在了表9.2中。第2章将视图分为如下3组::模块、组件-连接器(C&C)和分配。这种分类表明设计师至少需要用3种方式考虑软件:
(1)如何将其结构化为一组实现单元
(2)如何将其结构化为一组具有运行时行为和交互的元素
(3)它如何与其环境中的非软件结构相关
表9.2涉众和他们可能认为最有用的构架文挡
可以获得其他视图。视图只是代表一组系统元素以及它们之间关系,因此,您认为 对某-部分涉众团体有用的元素和关系就构成了 一个有效的视阁。下面是选择项目视阁的 •个简单的3步过程:
(1)产生一个候选的视图列表..先为项目建立•个涉众/视图表,如表9.2所示。您的 涉众列表很可能与表9.2不同.但只要与项目的具体情况尽量相符即可。在列中填充适用 于系统的视阁。•些视阁(如分解或使用)适用于每个系统,而其他视阁(如分层视图, 大多数组件连接器视阁(如客户机-服务器)或共享数据)只适用于按那种方式设计的系 统。确定了行和列后,填充毎个单元以说明涉众需要该视图提供多少信息:不滯要、仅霱 要提供概述、中等详细、非常i羊细。
(2)组合视图。第1步产生的候选视图列表中很可能会有很多视图。为了减少列表中 视图的数量以便于管理。先从表中找出仅需要概述或仅适合少数儿个涉众的视图。看看能 够满足更多涉众需要的另一个视图是否同样能够满足这几个涉众的需要。接下来,找出那 些能组合到-起的视图——也就是提供了两个或多个视图所具有的信息的一个视阁.对于 小型和中等规模的项目来说.实现视阁中通常会有很多模块分解视阁.也可以将模块分解 视图与使用视图或分层视阁很好地结合起来使用。最后,无论是什么样的组件-连接器视 图(例如进程视阁),只要展示了分配给硬件元素的组件,通常就可以与部署视图结合起 来使用。
(3)划分优先级.第2步后,您应该为涉众团体提供一个适当的视图集合。这时需要确定先做什么。决定先做什么取决于项目的具体情况,但是请注意,不需要在完成一个视 图后再开始另•个视阁。可以从-个概耍级的信息幵始.因此.宽度优先的方法通常是最 佳的。还有,一些涉众的利益可能要高于其他涉众的利益。与您公司管理层合作项目经理 或公司管理层需要更早且频繁的关注与信息。
9.4视图编档
没有对视图进行编档的工业标准模板,但是在实践中,如下7部分标准组织能够发挥 很好的作用。首先,不管您选择包含哪些部分,一定耍确保“有” 一个标准的织织。将具 体的信息分配给特定的部分能够帮助文档编写人员完成编写任务,并认识到已经完成,而且它有助于阅读文档的人快速找到自己感兴趣的内容。
(1)展示视阁屮的元素和元素间关系的主要表示。主耍表示中应该包含您首先希望传 达的有关系统(用该视图的词汇)的信息。它肯定应该包含视图的主耍元素和元素间的关 系,但在某些情况下,可能并不包含所有元素和元素间的关系。例如,您可能希望展示在正常操作中发挥作用的元素和元素间的关系,但想把错误处理或异常处理放在支持文档中。
主要表示通常是图形方式。实际上,大多数阁形表示法都是采用主要表示的形式来发 挥作用,只有很少的图形表示法是采用其他形式。如果主要表示足图形方式,那么,必须 给出对所使用的表示法或符号的解释。
有时,主耍表示是表格形式。表格通常是简洁地传达大量信息的极佳方法。文本形式 的主要表示的一个实例就是在第3章给出的A-7E模块分解视图。文本表示中也提供了视 图中最重要信息的摘要。9.6节将对使用UML用于主要表示进行讨论。
(2)元素目录至少详述了在主要表示中所描述的元素和它们之间的关系,大慨还宥其 他内容。产生主要表示通常是设计师的重点关注所在,但如果没有对图进行解释的支持性信息,主要表示就没有任何用处。例如,如果图中有元素A, B和C,那么,最好有一份文档用足够的细节來说明A. B和C是什么,它们的目的以及它们所扮演的角色,用视图 中的词汇对其进行描述。例如,模块分解视图中有作为模块的元素,“是……的一部分” 的关系,以及定义每个模块责任的属性;进程视图中有进程元素.定义同步或其他与进程 相关的交互的关系,以及包括时间参数的属性。
此外,如果有从主耍表示中遗漏与视图相关的元素或关系,那么.其目录就是介绍并 解释它们之处。
元素的行为和接口是元素目录的两个其他方面,我们将简要对其进行讨论。
(3)展示了在视图中描述的系统如何与其环境相关的上下文图。例如,在组件-连接 器视阁中,展示了哪些组件和连接器通过哪些接口和协议与外部的组件和连接器交互。
(4)可变性指南展示了如何应用该视图中所展示的构架的一部分的任何变化点。在一 些构架中,到了幵发过程的后期才制定决策,而且仍然必须将构架编成文档。可以在软件 产品线中看到关于可变性的例子,其中产品线构架适用于多个特定系统(在第14帝讨论)。 可变性指南中应该包括关于构架中每个变化点的文档,内容如下:
• 要在其中做出选择的选项。在模块视图中,选项就是模块的各种版木或参数化。在组件-连接器视图中,它们可能包括对复制、进度安排或协议选择的限制。在 分配视阁中,它们可能包括将软件元素分配给特定处理器的条件。
• 做出选择的时间。一些选择是在设计时做出的,一些是在构建时做出的, 一些是 在运行时做出的。
(5)解释了视图中所反映的设计合理性的构架背景.这一部分的目的是说明为什么要 这样设计.并提供一个合理的、令人信服的论据。构架背景包括:
• 基本原理,说明为何做出了视图中所反映的决策.以及为什么没有采用其他方案。
• 分析结果。说明设计的合理性,或解释当需要进行修改时,必须改变什么。
• 设计中所反映的假定。
(6)视图中所使用的术语表.对每个术语都进行了简要说明。
(7)其他信悤。这•部分的具体内容取决于组织的标准实践.它们可能包括管理信息, 如创作者、配置控制数据以及变更历史等。设计师可能会记录对某个需求文档的特定部分 的引用,以建立可跟踪性。从严格意义上说,此类信息并不属于构架方面的。然而,将其 记录在构架旁边是很方便的,此部分即针对此目的而提供的。在任何情况下,都必须详细 叙述管理信息。
图9.1 总结了上面描述的文档部分。
9.4.1对行为进行编档
视阁提供了系统的结构信息。然而.仅使用结构信息并不能对某些系统厲性进行推断。 例如.对死锁进行推断依赖于理解元素间的交互顺序,仅结构信息并不能提供该交互顺序 信息。行为描述可以提供元素间的交互顺序、并发机会以及交互的时间依赖性(在一个特 定时间或-段时间后)的信息。
可以将一个元素或协同工作的全部元素的行为编成文档„对什么进行建模取决于所设 计的系统的类型。例如,如果它是个实时嵌入式系统,就需要描述许多关于时间属性和 事件的时间的信息。在银行系统中,事件顺序(例如原子事务和回滚过程)比所考虑的事件的实际时间更重要。可以采用不同的建模技术和表示法,这取决于所要进行的分析的类 型。在UML中,顺序图和状态图就是行为描述的示例。现在,这些表示法已得到了广泛 使用。
状态图是在20世纪80年代开发的,用于描述反应式系统。开发人员向传统的状态图 中添加了大量有用的扩展,如状态嵌套以及“和”状态,这给模型抽象和并发提供了表达 力。可以通过状态图对系统的整体进行推断。它假定表述了所有的状态,并且分析技术对 系统是通用的。也就是说,能回答诸如此类的问题:对该刺激的响应时间总是少于0.5秒 吗?
顺序围对一系列刺激交换进行编档。它在组件实例及其交互方面提供了一个协作,并 展示了按照时间顺序排列的交互。纵向代表时间,横向代表不同的组件。顺序图允许根椐 一个特定的使用场景进行推理。它们展示了系统如何对一个特定的刺激做出反映,代表了 通过系统的路径选择。它们使得回答此类问题成为了可能:当系统对这些特定条件下的特 定刺激做出响应时,会发生什么并行活动?
9.4.2对接口进行编档
接口就是两个独立的实体相遇并进行交互或通信的边界。我们在第2萆对软件构架的 定义淸楚地表明元素的接口——对其他元素外部可见的属性的载体——是属于构架方面的。因为没有接口就不能进行分析或系统构建.因此对接口进行编档是构架编捫的重要组 成部分。
对接口进行编档包括命名和确定接口,然后对其语义和语法信息进行编档。前两个部 分组成了接口的“签名"。当接口的资源是可调用的程序时,签名就对程序进行命名并定 义其参数。参数要按顺序定义,它们具有一定的数据类型,有时还需要定义程序是否可以 变更参数的值。签名就是您将会发现的关于程序的信息,例如在元素的c或C++头文件或 Java接口中的信息。
签名是有用的(例如.它们可以支持自动构建检査),但只是其中的一部分内容。签 名匹配将保证系统的成功编译和/或链接。然而,关于系统足否能够成功运行,它不能提供 任何保证,但这是最终的目标。这一信息在语义上是与接口绑定在一起的。
接口文档中有一个接口规范,这是对设计师所选择的质量厲性的陈述。设计师应该仅 暴露与该接口交互所需要的信息。换句话说就逛,设计师应该选择哪些信息是允许并且适 合人们对该元素做出假定,以及哪些信息是不太能发生变化的。对接口进行编档就是在暴露太少的信息和太多的倌息之间达到一个平衡。如果暴露的信息太少,就会妨碍开发人员 成功地与元素进行交互。如果暴露的信息太多,将会使得末来更改系统的操作变得更加困 难,涉及面更广,并会使接口太复杂从而很难理解。经验就是把重点放在元素如何与其操 作环境进行交互上,而非放在其实现方式上。应该仅对外部可见的佶息进行编档。
作为模块出现的元素通常与组件-连接器视阐中的一个成多个元索直接对应。模块和 组件-连接器元素很可能有类似的(如果不相同的话)接口,在两个地方将其编成文档将 会产生不必耍的重复。为了避免出现这种情况,把组件-迮接器视阁中的接口规范指 向模块视阁中的接口规范,并仅包含关于其视阁的特定佶息。类似地.,一个模块可以出现 在多个模块视阁中——如模块分解或使用视阁.。同样,选择在-个视图中包含接口规范, 并在其他视阁中引用它.
对接口进行编档的模板,这里提供的是推荐使用的对接口进行编档的标准组织。可以 对它进行修改,以删除与组织的具体情况不相关的项.或添加适合自己绀织的特定情况的 项。使用哪个标准组织并不重要,重要的是一定要使用-个标准组织。使用您所需要的组 织为项目中的接口提供一个元素外部可见交互的准确概貌.
(1接口身份。当一个元素有多个接口时,识别每个接口以对其进行区分。这通常意 味着耍对接口进行命名。您可能还需要提供一个版本号。
(2)所提供的资源。接口文档的核心就足该元素所提供的资源。通过给出其语法、语 义(使用这些资源时将会发生什么)和对其使用的限制來定义资源。有几个对接口的语法 进行编裆的表示法。一个是在CORBA团体中使用的OMG的接口定义语言 (IDL)。它为 描述数椐类型、操作、属性和异常提供了语言构件。对语义信息的唯一语言支持就是注释 机制。大多数编程语言都有内建的用于指定元素签名的方法。C头(.h)文件和Ada软件 包规范就是两个例子。最后,使用用UML表示的<<imerface>>构造型(如图9.4所示)提 供了传达关于某接口的语法信息的方法。最少要对接口进行命名:设计师还可以规定签 名信息。
• 资源语法。这是资源的签名。该签名包括另一个程序编写一个使用该资源是语法正确的程序所需的所有信息。签名包括资源名,参数(如果有的话)的名称和逻
辑数据类型等。
•资源语义。资源语义描述了调用该资源的结果。它可能包栝:
•对调用资源的参与者可以访问的数据赋值。这可能会像设置返回参数 的 值一样简单,也可能会像 更新中央数据库-样复杂.
•将发出信号通知的事件,或将作为使用该资源的结果发送的消息。
•使用该资源后,将来其他资源的行为如何?
例如,如果某个资源破坏了 一个 对象,那么,
以后试图通过其他资源访 问该对象时,
将会产生非常不同的结 果(错 误)。
•可人为观察到的结果。在嵌入式系统中这迠很呰遍的;
例如,调用打开飞机 座舱中的显示屏的程序,
您会看到一个很明显的结果——显示屏打开。
此外,语义陈述还应该淸楚地阐述资源执行是原子的,
还是可能被挂起或中 断。
传达语义信息的最广泛的表示法就是自然语言。
布尔代数学通常用于书 写前置条件和后置条件.这
为表示语义提供了一个相对简单有效的方法。
还 可以通过写下活动序列或描述元素对
一个特定使用所做出的响应的交互,使 用踪迹来传达语义信息。
•资源使用限制。在什么情况下可以使用该资源?在可以读取数据前,大概必须 对 其进行初始化,或者必须在调用了一个方法后,才能调用某个特定的方法。 可能 对在任意时刻通过该资源交互的参与者数量有限制。
可能只有-个参与者对该资 源具有所有权,
他能修改该元素,而其他参与者只有访问权。
或许只有某些参与 者能够访问某些资源或接口,
以支持多级安全方案。如果该资源要求提供其他资 源,
或者对其环境做出了其他假设,那么,应该将这些内容记录在文档中。
(3)数据类型定义。如果任何接口资源采用了非底层编程语言提供的数据类型,设计 需要传达该数据类型的定义。如果它是由另•个元素定义的.那么,对该元素文档中 |的定义进行引用就足够了。在任何情况下,使用此类资源编写元素的程序员都需要知道: 如何声明数据类型的常量和变量(b)如何书写数据类型中的字面值(literal value): (c)可以对该数据类型的成员执行什么操作和比较:(d)如何在适当的地方将数据类型 的值转换为其他数据类型。
(4)异常定义。异常定义描述了可以由接口上的资源引发的异常。由于同一个异常可能会由多个资源引发,因此列出每个资源的异常,但在--个单独收集的字典里对其进行定 义通常是比较方便的。这一部分就是该字典。还可以在该字典中定义常见的异常处理行为。
(5)该接口提供的可变性。该接口是否允许用某种方式配置该元素?必须把这些“配置 参数”以及它们如何影响接口的语义编成文档。可变性示例包括可见数据结构的容量以 及基础算法的性能特征。为每个配置参数命名并提供一个范围值,并指定其实际值被确定的时间。
(6)接口的质量属性特征。设计师需要把接口使元素的用户知晓的质量厲性特征(如 性能或可靠性)编成文档。该信息可能是对将实现接口的元素实现的限制。您选择将重点放在哪些质量属性上以及对哪些质量属性做出承诺取决于上下文。
(7)元素需求。元素所需要的可能是具体的、由其他元素提供的已命名资源。对所提 供的资源来说.文档中的内容是相同的:语法、语义以及使用限制,将诸如此类的信息编 档为设汁人员做出的关于系统的一组假设通常是很方便的。采用这种形式时,可以在设计 进展的很多之前,由能够批准或报绝这些假设的专家对其进行评审。
(8)基本原理和设计问题。对于整个构架(或构架视图)的基本原理,设计师应该记 录元素接口设汁的原因。基本原理应该解释设计的动机、限制和折中,考虑和拒绝了哪些设计方案(以及原因),以及设计师关于在未来如何改变接口的一些远见卓识。
(9)使用指南。第2项和第7项在每个资源的基础上对元素的语义信息进行了编档。 有时,这会缺乏所需要的信息。在某些情况下,需要根据大量的单个交互如何关联来推断 语义。基本上,这牵涉到-项协议,该协议通过考虑一个交互序列进行编裆。协议可以代 表完整的交互行为,或元素的设计人员预计会反复出现的使用模式。如果通过其接口与该 元素交互是复杂的,那么,接口文档中将包含-个静态的行为模型,如状态阁.或以顺序 图的形式执行特定交互的示例。这类似于在上一部分中提供的视图级行为,但侧重点是单个 元素。
阁9.2对该模板进行了总结.它是图9.1中section 2.C部分的扩展。