架构需求与软件质量属性
架构的基本需求主要是在满足功能属性的前提下,关注软件质量属性,架构设计则是为满足架构需求(质量属性)寻找适当的“战术”。
软件属性包括功能属性和质量属性,但是,软件架构(及软件架构设计师)重点关注的是质量属性。因为,在大量的可能结构中,可以使用不同的结构来实现同样的功能性,即功能性在很大程度上是独立于结构的,架构设计师面临着决策(对结构的选择),而功能性所关心的是它如何与其他质量属性进行交互,以及它如何限制其他质量属性。
1 软件质量属性
《GB/T16260-1996(idt ISO/IEC9126:1991)信息技术软件产品评价质量特性及其使用指南》中描述的软件质量特性包括功能性、可靠性、易用性、效率、可维护性、可移植性等 6 个方面,每个方面都包含若干个子特性。
-
功能性:适合性、准确性、互操作性、依从性、安全性;
-
可靠性:成熟性、容错性、易恢复性;
-
易用性:易理解性、易学性、易操作性;
-
效率:时间特性、资源特性;
-
可维护性:易分析性、易改变性、稳定性、易测试性;
-
可移植性:适应性、易安装性、遵循性、易替换性;
正如上述列举与分类,软件的质量属性很多,也有各种不同的分类法和不同的表述。虽然术语没有统一的定义,但其含义可以认为业界已有共识。下面选取常用的质量属性术语,并做逐一说明。
1.运行期质量属性
-
性能:性能是指软件系统及时提供相应服务的能力。包括速度、吞吐量和持续高速性三方面的要求。
-
安全性:指软件系统同时兼顾向合法用户提供服务,以及阻止非授权使用的能力。
-
易用性:指软件系统易于被使用的程度。
-
可伸缩性:指当用户数和数据量增加时,软件系统维持高服务质量的能力。例如,通过增加服务器来提高能力。
-
互操作性:指本软件系统与其他系统交换数据和相互调用服务的难易程度。
-
可靠性:软件系统在一定的时间内无故障运行的能力。
-
持续可用性:指系统长时间无故障运行的能力。与可靠性相关联,常将其纳入可靠性中。
-
鲁棒性:是指软件系统在一些非正常情况(如用户进行了非法操作、相关的软硬件系统发生了故障等)下仍能够正常运行的能力。也称健壮性或容错性。
2.开发期质量属性
-
易理解性:指设计被开发人员理解的难易程度。
-
可扩展性:软件因适应新需求或需求变化而增加新功能的能力。也称为灵活性。
-
可重用性:指重用软件系统或某一部分的难易程度。
-
可测试性:对软件测试以证明其满足需求规范的难易程度。
-
可维护性:当需要修改缺陷、增加功能、提高质量属性时,定位修改点并实施修改的难易程度;
-
可移植性:将软件系统从一个运行环境转移到另一个不同的运行环境的难易程度。
在实践中,架构设计师追求质量属性常常陷入“鱼和熊掌”的两难境地,这就需要架构设计师的决策智慧了。表 9-1 反映了质量属性之间的相互制约关系(正相关或负相关),其中“+”代表“行属性”能促进“列属性”;而“-”则相反。例如,第一列符 说明许多属性(行)对性能(列)有副作用,第一行符 说明性能(行)对许多属性(列)有副作用,认识这一点,对于架构决策的权衡很重要。
6个质量属性及实现
本节从架构关注点来研究质量属性实现,将质量属性分为 6 种:可用性、可修改性、性能、安全性、可测试性、易用性。其他的质量属性一般可纳入这几个属性中(在其他文献中为了强调常单列出来),例如,可扩充性可归入可修改性中(修改系统容量),可移植性也可以作为平台的可修改性来获得。对于未能纳入的其他质量属性,可以用本章的方法进行研究。
那么,如何描述质量属性需求呢用质量属性场景作为一种描述规范,它由以下6个部分组成,如图 9-2 所示。
-
刺激源:生成该刺激的实体(人、计算机系统或其他激励器);
-
刺激:刺激到达系统时可能产生的影响(即需要考虑和关注的情况);
-
环境:该刺激在某条件内发生。如系统可能正处于过载情况;
-
制品:系统中受刺激的部分(某个制品被刺激);
-
响应:刺激到达后所采取的行动;
-
响应度量:当响应发生时,应能够以某种方式对应其度量,用于对是否满足需求的测试。
需要将一般的质量属性场景(一般场景)与具体的质量属性场景(具体场景)区别开来,前者是指独立于具体系统、适合于任何系统的一般性场景;而后者是指适合于正在考虑的某个特定系统的场景,具体场景通常是指从一般场景中抽取特定的、面向具体系统的内容。下面几个小节中为每个质量属性提供一张表,该表中给出了质量属性场景每部分的一些可能取值,整体上形成一个一般场景的表格描述。在实际应用时,根据系统的具体情况,从该表中选取适当的值,就能变成具体场景(可读性强、可应用),可以把具体场景的集合作为系统的质量属性需求。
实现这些质量属性的基本设计决策,称为“战术”,而把战术的集合称为“架构策略”。这些架构策略供架构设计师选择。下面几个小节将对各质量属性的战术进行示例性的总结。
“战术”作为逻辑部件位于图 9-2 的制品中,它旨在控制对刺激的响应。
1.可用性及其实现战术
(1)可用性的描述。可用性的描述如表 9-2 所示。
可用性一般场景可以用图 9-3 表示。
对一般场景进行具体化可以得到可用性具体场景,如图 9-4 所示。
(2)可用性战术。可用性战术的目标是阻止错误发展成故障,至少能够把错误的影响限制在一定范围内,从而使修复成为可能。战术分为:错误检测、错误恢复、错误预防。
① 错误检测
-
命令/响应:一个构件发出一个命令,并希望在预定义的时间内收到一个来自审查构件的响应,例如远程错误的检测。
-
心跳(计时器):一个构件定期发出一个心跳消息,另一个构件收听到消息,如果未收到心跳消息,则假定构件失败,并通知错误纠正构件。
-
异常:当出现异常时,异常处理程序开发执行。
② 错误恢复
-
表决:通过冗余构件(或处理器)与表决器连接,构件按相同的输入及算法计算输出值交给表决器,由表决器按表决算法(如多数规则)确定是否有构件出错,表决通常用在控制系统中。
-
主动冗余(热重启、热备份):所有的冗余构件都以并行的方式对事件做出响应。它们都处在相同的状态,但仅使用一个构件的响应,丢弃其余构件的响应。错误发生时通过切换的方式使用另一个构件的响应。
-
被动冗余(暧重启/双冗余/三冗余):一个构件(主构件)对事件做出响应,并通知其他构件(备用的)必须进行的状态更新(同步)。当错误发生时,备用构件从最新同步点接替主构件的工作。
-
备件:备件是计算平台配置用于更换各种不同的故障构件。
-
状态再同步:主动和被动冗余战术要求所恢复的构件在重新提供服务前更新其状态。更新方法取决于可以承受的停机时间、更新的规模及更新的内容多少。
-
检查点/回滚:检查点就是使状态一致的同步点,它或者是定期进行,或者是对具体事件做出响应。当在两检查点之间发生故障时,则以这个一致状态的检查点(有快照)和之后发生的事务日志来恢复系统(数据库中常使用)。
③ 错误预防
-
从服务中删除:如删除进程再重新启动,以防止内存泄露导致故障的发生。
-
事务:使用事务来保证数据的一致性,即几个相关密切的步骤,要么全成功,要么都不成功。
-
进程监视器:通过监视进程来处理进程的错误。
2.可修改性及其实现战术
(1)可修改性的描述。可修改性的描述如表 9-3 所示。
对于可修改性一般场景的图示及可修改性具体场景,读者可仿照前面可用性的描述方式,自行练习。
(2)可修改性战术。包括局部化修改、防止连锁反应、推迟绑定时间。
① 局部化修改。在设计期间为模块分配责任,以便把预期的变更限制在一定的范围内,从而降低修改的成本。
-
维持语义的一致性:语义的一致性指的是模块中责任之间的关系,使这些责任能够协同工作,不需要过多地依赖其他模块。耦合和内聚指标反映一致性,应该根据一组预期的变更来度量语义一致性。使用“抽象通用服务”(如应用框架的使用和其他中间软件的使用)来支持可修改性是其子战术。
-
预期期望的变更:通过对变更的预估,进行预设、准备,从而使变更的影响最小。
-
泛化该模块:使一个模块更通用、更广泛的功能。
-
限制可能的选择:如在更换某一模块(如处理器)时,限制为相同家族的成员。
② 防止连锁反应。由于模块之间有各种依赖性,因此,修改会产生连锁反应。防止连锁反应的战术如下。
-
信息隐藏:就是把某个实体的责任分解为更小的部分,并选择哪些信息成为公有的,哪些成为私有的,通过接口获得公有责任。
-
维持现有的接口:尽可能维持现有接口的稳定性。例如通过添加接口(通过新的接口提供新的服务)可以达到这一目的。
-
限制通信路径:限制与一个给定的模块共享数据的模块。这样可以减少由于数据产生/使用引入的连锁反应。
-
仲裁者的使用:在具有依赖关系的两个模块之间插入一个仲裁者,以管理与该依赖相关的活动。仲裁者有很多种类型,例如:桥、调停者、代理等就是可以提供把服务的语法从一种形式转换为另一种形式的仲裁者。
③ 推迟绑定时间。系统具备在运行时进行绑定并允许非开发人员进行修改(配置)。
-
运行时注册:支持即插即用。
-
配置文件:在启动时设置参数。
-
多态:在方法调用的后期绑定。
-
构件更换:允许载入时绑定。
3.性能及其实现战术
(1)性能的描述。性能描述如表 9-4 所示。
对于性能一般场景的图示及性能具体场景,读者可仿照前面可用性的描述方式,自行练习。
(2)性能战术。性能与时间相关,影响事件的响应时间有两个基本因素。
-
资源消耗:事件到达后进入一系列的处理程序,每一步处理都要占用资源,而且在处理过程中消息在各构件之间转换,这些转换也需要占用资源。
-
闭锁时间:指对事件处理时碰到了资源争用、资源不可用或对其他计算的依赖等情况,就产生了等待时间。
性能的战术有如下几种。
① 资源需求
-
减少处理事件流所需的资源:提高计算效率(如改进算法)、减少计算开销(如在可修改性与性能之间权衡,减少不必要的代理构件)。
-
减少所处理事件的数量:管理事件率、控制采样频率。
-
控制资源的使用:限制执行时间(如减少迭代次数)、限制队列大小。
② 资源管理
-
引入并发:引入并发对负载平衡很重要。
-
维持数据或计算的多个副本:C/S 结构中客户机 C 就是计算的副本,它能减少服务器计算的压力;高速缓存可以存放数据副本(在不同速度的存储库之间的缓冲)。
-
增加可用资源:在成本允许时,尽量使用速度更快的处理器、内存和 络。
③ 资源仲裁
资源仲裁战术是通过如下调度策略来实现的。
-
先进/先出(FIFO);
-
固定优先级调度:先给事件分配特定的优先级,再按优先级高低顺序分配资源;
-
动态优先级调度:轮转调度、时限时间最早优先;
-
静态调度:可以离线确定调度。
4.安全性及其实现战术
(1)安全性的描述。安全性的描述如表 9-5 所示。
对于安全性一般场景的图示及安全性具体场景,读者可仿照前面可用性的描述方式,自行练习。
(2)安全性战术:包括抵抗攻击、检测攻击和从攻击中恢复。
① 抵抗攻击
-
对用户进行身份验证:包括动态密码、一次性密码、数字证书及生物识别等;
-
对用户进行授权:即对用户的访问进行控制管理;
-
维护数据的机密性:一般通过对数据和通信链路进行加密来实现;
-
维护完整性:对数据添加校验或哈希值;
-
限制暴露的信息;
-
限制访问:如用防火墙、DMZ 策略。
② 检测攻击。一般通过“入侵检测”系统进行过滤、比较通信模式与历史基线等方法。
③ 从攻击中恢复。
-
恢复:与可用性中的战术相同;
-
识别攻击者:作为审计追踪,用于预防性或惩罚性目的。
5.可测试性及其实现战术
(1)可测试性的描述。可测试性的描述如表 9-6 所示。
对于可测试性一般场景的图示及可测试性具体场景,读者可仿照前面可用性的描述方式,自行练习。
(2)可测试性战术:包括输入/输出和内部监控。
① 输入/输出
-
记录/回放:指捕获跨接口的信息,并将其作为测试专用软件的输入;
-
将接口与实现分离:允许使用实现的替代(模拟器)来支持各种测试目的;
-
优化访问线路/接口:用测试工具来捕获或赋予构件的变量值。
② 内部监控。当监视器处于激活状态时,记录事件(如通过接口的信息)。
6.易用性及其实现战术
(1)易用性的描述。易用性的描述如表 9-7 所示。
对于易用性一般场景的图示及易用性具体场景,读者可仿照前面可用性的描述方式,自行练习。
(2)易用性战术:包括运行时战术、设计时战术和支持用户主动操作。
① 运行时战术
-
任务的模型:维护任务的信息,使系统了解用户试图做什么,并提供各种协助;
-
用户的模型:维护用户的信息,例如使系统以用户可以阅读页面的速度滚动页面;
-
系统的模型:维护系统的信息,它确定了期望的系统行为,并向用户提供反馈。
② 设计时战术。将用户接口与应用的其余部分分离开来,预计用户接口会频繁发生变化,因此,单独维护用户接口代码将实现变更局部化。这与可修改性相关。
③ 支持用户主动操作。支持用户的主动操作,如支持“取消”、“撤销”、“聚合”和 “显示多个视图”。
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!