面向软件演化的可靠性分析代数方法
2021-03-04张捷陆阳张本宏刘广亮
张捷 陆阳 张本宏 刘广亮
软件演化一直是软件工程领域的挑战性问题.由于客户需求、环境变化、技术进步等原因,软件有着更新演化的现实需要,由此带来的开发及管理问题可能非常复杂.针对软件演化的定量分析已经被公认是横亘软件生命周期的最复杂问题之一,而软件架构(Software architecture,SA) 的提出为问题的表述与解决提供了方向.近年来,通过使用SA相关方法和工具已较好解决了软件演化所带来的障碍、成本等问题,并且涌现出一些新的观点如演化风格、演化路径等[1−3].但在对软件演化过程的精确描述和完整建模上,并没有出现公认的一般性方法.需要说明的是,目前针对演化的研究都是过程性研究,它基于架构工程师对软件更迭过程的完整监控,若此工作仅依赖编码人员,会不可避免地出现架构侵蚀或架构偏移问题[4].一个可行思路是对现有的SA工具进行推广和扩充,使之能够适用于面向软件演化的过程性分析需要.SA 发展至今,其工具和方法的易用性一直是尚待解决的难题,如何准确、高效地描述演化需求和过程,进而使得架构设计者和开发者都可以快速掌握和应用,有很实际的意义.
另一方面,脱离架构指导的代码演变极易导致软件设计与实现的错位,而要修正此类问题往往代价巨大.以目前用户最多的学习管理软件Moodle为例,它在演化过程中曾经历过重大变化以及大量问题的修复[5].虽然拥有庞大的开发者社群和完整的开发过程记录,但是此开源项目尚没有清晰的架构设计和演化方案描述.每当新版本发布,仅用文字记录下哪些新开发的组件被加入,哪些组件被更改,工程方法的缺失使得版本更迭脱离了SA 设计指导,很可能最终导致代码实现架构与设计架构的差异.研究已经证实这些差异或称错位情形,对软件系统的质量指标如可用性、可维护性、可靠性等将产生非常负面的影响[6].
最近的软件演化研究多集中于实证分析,通过软件度量和失效数据等在演化过程中的变化揭示一般规律.如文献[7]提出通过分析驱动演化的错误报告及变更请求等以评估演化过程质量,其方法完全基于对过程度量数据的标准化衡量,利于工具实现.文献[8]利用复杂网络对Linux 操作系统演化过程进行实证研究,通过对前后近1 300 个发布版本中所有C 函数及其相互调用关系构建有向网络,展现了网络在规模、入/出度、聚类系数等不同拓扑性质下的演化过程.利用复杂网络拓扑属性分析,作者揭示了函数模块的各类演化形式,并指出主要组件函数模块演化的统计学规律.而文献[9]在对2002年~2016 年Linux 各版本的Bug 报告进行分类整合基础上,重点关注了故障触发在版本演化过程中的规律性特征,指明Linux 组件模块在测试时的重要性排列以及聚类系数对衡量错误类型比例的作用.上述研究使用的模型或方法具有新颖性与可操作性,但其关注的重点在对既有演化过程的数据分析,对演化过程及演化行为本身的描述并没有论及.此外,文献[10]通过构造Markov 过程用以表示运行在多重环境下的系统演化,用于系统可靠性及环境可靠性的数值分析.文献[11]关注了使用演化博弈论解决复杂网络环境下个体间间接互惠及合作演化的问题,对演化行为研究提供了新的思路.在文献[3]中,作者提出了一种基于QVT 语言的方法,将源码层面的演化行为转换到SA 层面以缓解架构与代码的失配问题.上述方法并不面向演化过程建模,且方法的易用性对开发者而言也并非友好.本文旨在使用轻量且抽象程度更高的代数方法建立软件演化过程的序列化描述,侧重于分析序列中演化行为对软件系统整体的影响,并结合代数描述的可计算性实时得出量化结果.
软件工程活动的主要目的在于开发和维护高质量的软件系统,对软件演化的定量分析应以提高软件产品质量为出发点.评价软件质量的指标与方法众多,本文选取可靠性指标进行研究,这是因为:1) 结构化软件可靠性模型(区别于传统增长类模型)与SA 有直接相关性,它可伴随结构的演变工作,适用于架构工程师预先评估整个演化过程的质量发展趋势;2) 可靠性的计算基于对软件结构的精确分析,这与其他软件质量指标相同或相近(如可维护性),使得研究不失一般性特点.特别地,当对象为一类安全关键软件系统时,因其对版本更迭前后的质量抖动更加敏感,相应的演化需求及演化进程需要更严格的评估及监控,而可靠性作为最关键的非功能性指标具有重要价值.基于此,本文站在可靠性的角度分析软件演化过程及其对软件质量的影响,主要解决以下三方面的问题:
1) 建立模型以准确描述软件结构的演化;
2) 演化过程中对软件可靠性的实时计算;
3) 对演化关键步骤及趋势的分析.
结构化软件可靠性建模研究始于Littlewood[12]的SMP (Semi-Markov process) 模型,他首先提出单个组件成功执行概率(或称组件可靠性) 和在工作流上的组件间控制转移概率是决定系统整体可靠性的两个关键因素.Cheung[13]在此基础上给出DTMC(Discrete time Markov chain)模型,它明确了二者与系统可靠性之间的函数关系.DTMC 模型相较SMP 具有强Markov 性质,但它仅将组件执行时间看作单位时间并忽略其在建模中的作用.随后Laprie[14]使用CTMC (Continuous time Markov chain) 将组件执行时间均值作为建模参数引入,用于刻画系统执行稳态.需要指出的是,在CTMC 模型中执行时间必须服从指数分布以满足Markov 性质,而近来有研究认为,这一限定在更复杂的应用场景中已不合时宜.如Zheng 等[15]在分析Web 服务的性能与可靠性时回归了SMP 方法,其强调在单个服务上的逗留时间满足一般分布,并通过在转移时间点(或称更新点) 上建立DTMC,以计算多种结构类型的组合服务可靠性和单个/组合服务的响应时间均值、方差,结果可用于可靠性及性能瓶颈分析.进一步地,通过将一维SMP 泛化至二维MRGP(Markov regenerative process),可描述服务端、用户端在不同场景、策略、行为下的组合状态迁移,其在用户感知的服务性能评估上优于传统CTMC 模型[16].
上述模型和方法的差异在对组件执行时间的处理上,而本文主要讨论软件演化可靠性分析一般性方法,倾向使用相对简便的DTMC 模型,以突出需要解决的核心问题是对软件演化的描述与可靠性实时分析.而解决问题的关键在于引入代数方法.通过代数方法将软件演化过程序列化,并跟踪分析序列中每一步操作,使得整个演化过程受到完整监控;同时代数方法本身的精确、轻量、易用等特征也确保了架构设计者的意图能够被开发人员准确理解,且不会造成他们太多额外的负担.本文余下的内容组织如下:第1 节将介绍相关知识背景,包括软件结构化可靠性分析的主流方法以及简单增量式演化的计算;第2 节给出了结构演化的实例,说明对其描述的困难程度;第3 节讨论如何使用代数方法构建面向演化过程的序列化模型;两个算例在第4 节中被深入讨论,以验证代数方法的有效性和易用性.
1 DTMC 模型与增量式演化
软件可靠性分析的关键在于模型的选择.传统的软件可靠性增长类模型基于测试期失效数据,并不适用于软件结构演化时的可靠性分析.这里只介绍主流的结构化模型分析方法,其基本模型为Cheung 的DTMC 模型[13].下文以欧洲航天局ESA 的小型控制系统软件[17]为例进行说明.
图1 ESA 软件组件迁移图Fig.1 The component transition diagram of ESA software
由图1 示,该软件系统含有4 个主要组件N1~N4,图中组件节点反映了系统执行的4 个稳态,节点间的控制转移以有向弧表示,弧上标注转移概率.注意到图1 中包含两个吸收态分别表示组件失效后到达以及成功执行到达的状态节点.去除节点后,可建立DTMC 一步随机转移矩阵Q如下:
其元素Qi,j表示了在Markov 过程中从状态节点i转移至节点j的转移概率.如Q1,2=R1P1,2,它反映由节点N1经一步转移至节点N2的概率等于成功执行N1组件的概率R1与转移分支概率P1,2的乘积.矩阵Q的n次幂Qn为n步随机转移矩阵,其元素反映了由节点i经n步转移至节点j的概率.而Q的Neumann 级数S表达了由N1经所有可能步数成功到达N4的概率和,即
其中,I为单位矩阵,并且易知级数收敛.对ESA 软件系统,其整体可靠性计算为
即由节点N1出发成功到达N4,并正确执行N4的概率.
由式(2),可认为Rsys为单个组件可靠度Ri的函数.称Bi为系统整体可靠性对组件Ni的敏感度,有
一个明显的结论是B4=S1,4,但其余并不容易得出.
DTMC 模型可以直接计算一类简单的增量式演化,增量指的是单个组件因为改动而导致的可靠度增加或降低[18].令A=I -Q,B=M4,1,其中,M4,1为元素A4,1的余子式.考查组件N3获得增量δ后的情形,演化后S1,4可计算为
式(4) 即为N3增量演化后的整体可靠性计算方法.对单个组件的简单增量式演化行为,可靠性分析的重点在于由增量幅度与整体可靠性变化幅度的关系,这显然与式(3) 的Bi有关.
考虑余子式一般情形,令U=Mn,1,可展开整理为
其中,Ci,j为元素Ui,j的代数余子式,规模为(n-2)×(n-2).
对矩阵A=I -Q,可整理为
其中,Di,j为元素Ai,j的代数余子式,规模为(n-1)×(n-1).综合式(5) 和式(6),对式(3) 加以改进,得到
此为单组件增量式演化后的敏感度,推导过程这里不再展开.可知计算过程非常复杂,并且时间复杂度在O(n3) 量级,这意味着随着转移矩阵Q规模的增长,计算负荷问题将凸显.
2 软件结构的演化
区别于简单增量式演化,本节讨论更一般的情形.软件系统在发布后会不断调整其体系结构以适应需求或者运行环境的变化.这些调整即演化行为可能来自软件的自适应机制(例如服务组件的动态匹配),也可能来自软件版本的更新(出于功能修补、性能优化等目的).站在结构度量的角度,我们希望可以完整跟踪软件的演化行为,以确定软件某些关键性能指标(可靠性、可用性、可维护性等) 的变化趋势,并定位那些导致整体性能抖动剧烈的单个组件或局部结构模块.
以上一节ESA 系统为例.图2 标注了各组件可靠度及组件间转移概率,数据来自文献[17].假设该软件在运行期间发生了演化,其主要模块Parsing、Computing 及Formatting 得到了更新,同时系统结构也因为组件接口更迭和局部性能优化发生改变.图3 表示其在演化发生后的情形.阴影表示组件N1~N3已被更新,可靠度也相应发生变化:解析模块因算法改进可靠度得以提升(增加0.04);格式模块因接口增加导致可靠度下降(减少0.02);组件N5作为N2的复制被加入到结构中,用来分担系统实时计算的压力,并且为了进一步优化性能,N2与N5耦合为并行结构,同时N2(及N5) 因为并行功能扩展导致其可靠度降低(均减少0.01).
图2 ESA 软件组件迁移图(标注可靠性信息)Fig.2 The component transition diagram of ESA software (labeled with reliability information)
图3 较图2 有多处更改,这些更改并非同时发生,而是遵循一个演化过程来进行.过程中的每一步都由一个或多个操作组成,而这些操作(下文称演化原子操作) 都会成为影响系统整体可靠性的小的变量.如果忽略过程直接使用DTMC 模型,对软件开发并没有实际的指导意义.我们认为针对软件演化的可靠性分析应兼具宏观与微观的视角:微观上,定位演化过程中这些小粒度原子操作以及它们所对应的组件模块和局部结构,可暴露软件系统演化时的潜在风险,将有利于分析影响整体可靠性的关键因素;宏观上,将过程看作操作序列的累积,可用于分析完整演化进程的可靠性趋势.
图3 ESA 软件组件迁移图(演化后)Fig.3 The component transition diagram of ESA software (after evolution)
满足上述需求的前提是对演化过程的理解与表达.事实上,追踪和描述软件系统中模块及模块间关系的变化过程一直是软件可视化技术的研究热点,可视化技术可以帮助开发者兼具静态、动态及演化的视角以分析结构和代码[19].但当前可视化技术仅聚焦于多视角分析,因计算和描述能力的限制尚无法揭示演化过程中的潜在效用变化,故仍然不适用于完整分析软件演化过程[20].图4 给出了一个针对图3 演化版本的系列图,使用了可视化技术中常见的小格图[21](Small multiples) 表达.
小格图显示了软件结构沿时间t连续变化的过程:在t=2 时刻,模块N1、N3已经完成了更新;在t=3 时刻加入了N2的复制N5,同时也相应增加了模块间关系(边).有时为了清晰反映单步变化过程,也可以在两个时刻间插入中间态(可使用动画),例如这里的t=2→3.需要说明的是,即使插入中间态的动画过渡,也无法准确描述出潜在关键信息.如这里t=4,相较于前一时刻新增了模块N2与N5之间的并行关系,但是这种特殊的耦合结构在图中没有明确表达,而这又是影响系统整体可靠性的关键信息.诸如小格图(包括其改进)、Difference maps[22]以及Glyphs[23]等可视化方法,在描述演化进程时都存有类似问题,并且它们都无法回避占用计算空间大、仍需手动对图识别比较等缺点.
下节将引入一种代数方法,它更轻量化易于描述和计算,能准确表达演化步骤和过程.
图4 ESA 软件演化过程的小格图表示Fig.4 Evolution process of ESA software represented by the small multiples
3 代数方法
将图2 所示的软件结构定义为三元组〈C,O,Ω〉,其中,C为组件模块集,O为使用连接子集,Ω为模块关系集.它的完整含义如下:
称上述三元组〈C,O,Ω〉为ESA 软件结构代数模型,其中关系集Ω含6 个代数表达式.这里沿用文献[24]的定义,将连接子定义为代数算子形式,关系集即为由组件模块和代数算子连接而成的表达式集合.此例中仅含激发算子⊕,它被用来表述组件模块间最基本的交互方式.如Ω中的第1 个表达式Role1=N1⊕N2,其涵义为N1对N2进行了一次激发,激发动作完成后,系统执行稳态将由N1迁移至N2.更多的算子可参考笔者前期所做的工作[25].
作为对软件体系结构的高度抽象,代数模型优势在于轻量化和可计算性方面.当相关参数信息完整时,使用现有形式语言分析技术对关系集(即表达式集) 进行一趟扫描,即可完整计算系统整体可靠性数值.笔者于文献[25]中验证了一个语法分析器,其算法基于使用广泛的LR(1) 分析,并针对代数模型进行优化以保证可扫描并识别出Ω中所有表达式.在此基础上,图5 给出了本文的可靠性自动分析流程.在建立代数模型之后,流程可对模型进行预处理和扫描解析.扫描过程中每当匹配成功一个基本结构范式,在状态空间对应更新系统状态节点;当扫描结束,一个状态空间上的DTMC 全部节点信息获取完成,参照式(2) 即可完成一次整体可靠性计算.需要说明的是,一次可靠性计算并不意味着流程终止,每当新的演化需求产生,其代数形式表达将用以更新现有代数模型,流程将自动重走一趟以完成针对此次演化的可靠性实时计算.
限于篇幅,对代数模型的预处理及扫描解析算法不再重述.下文详细解释框架中对演化处理的部分.对应图3,首先将ESA 软件系统演化后代数模型表示如下:这里算子‖表示并行耦合关系.
图5 面向软件演化的可靠性分析流程Fig.5 The reliability analysis process for software evolution
如前所述,认为从图2 至图3 必然经历一个演化过程.站在结构分析的角度,演化过程可看成由若干原子操作组成的行为序列.为了方便讨论,首先给出如下记号:
1)Ai,结构中间版本,对应第i步演化步骤相对前一版本Ai−1的更改,其中,A0为初始版本,An为演化完成版本;
2)Qi,对应版本Ai的整体软件质量度量(这里只讨论可靠性,以Ri代替);
3)Di=|Qi -Qi−1|,用来表示相邻版本质量之差,这里总是取正值以描述演化过程中的可靠性抖动程度.图6 反映了上述记号之间的关系.
图6 软件演化过程的版本表示Fig.6 The version-expression in software evolution process
在具体演化操作方面,文献[26]在软件质量相关度量基础上给出了演化原子操作分类,但其并不适用于基于结构分析的可靠性建模.文献[7]从故障数、变动率以及人工成本等角度对演化操作进行数据分析与度量,但其仍非面向过程的方法,无法精确描述演化行为.因此本文给出如表1 所示演化原子操作分类及定义,用以面向建模的精确性及可计算性.
表1 强调了演化操作定义的原子性,即操作不可再分.每种操作都将对应更新代数模型的三个集合C、O及Ω.如增加组件AM,其对应了组件集C中元素的增加,而移除组件间依赖RMD 会使得关系集Ω中的表达式被移除.
表1 演化原子操作分类Table 1 Classification of evolutionary atomic operations
注意到原子操作间具有较强关联性,一种操作往往会关联另一种操作,如结构中增加了新的组件模块,因其必然参与系统执行稳态的控制转移,故会导致模块间依赖关系的更新.单个演化步骤中不应只对应单个原子操作,有时也须考虑若干原子操作相关联的情况.
结合上文演化前代数模型〈C,O,Ω〉和演化后模型〈C′,O′,Ω′〉,可对演化过程作如下描述:
其中,A6为演化完成版本.注意这里A4步完成后,应将Ω集中所有N2及N5处替换为N2‖N5并删除冗余项.
中间版本A1、A2及A4关联原子操作UM,对应简单的增量式演化.注意除了A1外,其余不能直接套用式(4) 计算可靠性,因为版本A2、A4已经“身处”演化进程之中,它们均是对前一版本更改而非对初始版本更改.相对地,包括处理A5中更复杂的结构演化情形,本文提出流程框架展现了良好的适用性:通过对表达式集合Ω的一趟扫描,各中间版本的计算可实时自动完成.就演化过程建模而言,代数方法相对小格图等其它方法强调了过程描述的精确性与完整性.
根据上述演化模型并结合由图2 演化至图3 的具体数据变动,流程自动计算从A0至A6各版本系统整体可靠性.图7 反映了可靠性数值在演化进程中的趋势,可以看到:在A4版本之前,系统整体可靠性维持在一个较稳定水平;当到达A5版本后,可靠性数值显著下降,这是由于并行结构的引入使得组件间耦合度增加,从而对可靠性造成负面影响.图8 显示演化时的版本抖动程度,其数值意义为相邻版本的可靠性差值:D5明显区别于其余值,反映了由版本A4演变至版本A5的原子操作是影响整个演化过程的关键;D1、D2与D4对应了简单增量式演化(对应UM 操作),其值一定程度上可揭示组件的重要度,与式(7) 所计算的敏感度值相似,但计算难度大幅降低.
图7 ESA 软件演化过程可靠性变化趋势Fig.7 The reliability trends in evolution process of ESA software
图8 演化版本间抖动程度Fig.8 The reliability distance between evolution versions
4 算例研究
本节使用两个算例以验证本文提出代数方法的有效性与实用性.
4.1 算例1
4.1.1 数据介绍及参数设置
算例1 数据来自文献[27],该算例因具有典型性故被广泛应用于可靠性模型验证.最近对该算例的研究仍在持续,如在文献[28]中被用以比较一类DTMC 模型的性能.图9 中标明了算例1 的可靠性相关参数设置,包括单组件Ni的可靠性数值Ri,以及组件间控制转移概率Pi,j.图9 含该系统的初始结构设计:系统含15 个组件模块,初始设计时并不含特殊结构,即组件间仅以最基本的激发方式进行交互.为进行算例的演化验证,这里设定系统最终发布时,含有并行、容错及调用返回三种特殊结构类型,它们分别是:模块N3、N4构成并行结构、模块N10对N9构成容错结构、模块N11、N8以及N8、N5构成调用返回结构.
4.1.2 方法运行及阶段性结果
根据系统初始结构设计,建立代数模型如下:
图9 算例1 初始结构与相关参数Fig.9 The reliability trends in evolution process of ESA software
经流程框架自动扫描并计算,初始结构整体可靠性数值为0.8762.令初始结构版本A0为演化起点,以最终发布版本A17为演化终点,将演化过程作如下描述:
这里‖为并行算子,Ψ 为容错算子.
中间版本A1~A15对应单个组件的简单增量式演化.设定因平台迁移使用了新的事件系统,所有组件实现发生变化,导致可靠度平均下降了0.005.版本A16、A17中使用了CM 操作,分别对应N3、N4以及N9、N10进行结构耦合后的情形.表2 中列出演化过程的中间计算结果.其中各演化版本可靠性Ri的计算由流程框架自动完成,图10 表达演化过程的可靠性趋势.因为组件平均可靠度的降低,系统整体可靠性呈下行趋势,当到达最低点A16版本后,因为A17中引入容错机制的原因使得可靠性最终有所回升.
图10 算例1 演化可靠性变化趋势Fig.10 Reliability trends in evolution of Case 1
4.1.3 最终结果及分析
就面向过程的可靠性评价而言,本文倾向于使用类似图10 的可靠性趋势序列表达结果,以代替对最终版本的单次可靠性计算.除趋势外,将演化过程序列化的另一优势在于敏感度分析,即指出在演化过程中造成整体可靠性抖动明显的关键步骤及其背后关联的原子操作.如代数方法描述,中间版本A1~A15对应UM 原子操作,即单个组件更新的情形.因为组件可靠度平均下降幅度相同,故相邻版本质量差值D1~D15很大程度上可反映被更新组件N1~N15的重要程度.为说明其有效性,表2 中也给出了可靠性关键程度(Criticality) 的计算结果,它由下式定义:
其中,∆Ri为单个组件Ni的可靠性变化增量,∆Rsys对应因此引起的系统整体可靠性增量.当组件的平均可靠度增量幅度非常小时(≤0.005),Ci能够近似代替敏感度Bi,而相较于Ci,计算Bi的代价通常要大的多.
图11 中为了与前15 个D1~D15作对比,一组Criticality 值C1~ C15以曲线形式呈现(经过适当放大).观察Criticality 曲线变化与下方的Distance 图形基本一致.除去起始节点组件N1与终止节点组件N15外,组件N13的Criticality 值(C13=0.87296) 最大而组件N12其次(C12=0.79360),这与D13(0.00417) 及D12(0.00387) 是吻合的.这表明演化过程含多个简单增量式演化步骤时,通过计算Distance 值(增量幅度不同时考虑Di/∆Ri比值) 评估不同组件的可靠性关键程度是有效的.而计算Criticality 值几乎没有代价,它仅是为分析演化过程保留的中间结果.
图11 体现了演化过程的可靠性抖动情况.可看到处于最后的D16、D17明显高出其余Distance值一个量级,这说明涉及结构的演化原子操作(SM、CM) 对系统整体可靠性的影响往往最为关键.其中又以D17的值最为突出,这是因为容错结构本身即具有高可靠特征,如果对结构中关键节点(可靠性敏感的) 组件进行容错结构的演化设计,可对系统整体可靠性提升起显著作用.从架构设计者立场,需要与编码人员一起严格监控以使演化过程中的质量抖动幅度被限制在合理的区间内.序列化的代数建模方法针对了上述需求,并且方法本身是简洁、易用的.
表2 算例1 演化过程计算结果Table 2 Evolution process calculation results of Case 1
图11 算例1 版本抖动与组件关键程度Fig.11 Version distance and component criticality of Case 1
4.2 算例2
4.2.1 数据介绍及参数设置
算例2 来自一个大型交换机系统的软件结构设计,它最早被文献[13]所引用,并同样因其结构具有代表性多被用来比较和验证结构化软件可靠性模型.在文献[29]中,作者对该算例从相关性、敏感度等角度进行了深入分析与讨论,并与一类基于路径可靠性模型作出比较.图12 中标明了算例2 的可靠性相关参数设置,同时也给出了系统的初始结构设计.该系统含有10 个组件模块,初始设计不含有特殊结构.在算例2 的演化验证中,将重点关注组件间的控制转移变化对可靠性影响.这里设定系统结构关键组件N1、N2及N5在最终发布前控制转移分支概率发生变化,在演化过程中将对这一行为建模并分析分支的可靠性敏感度.
4.2.2 方法运行及阶段性结果
根据系统初始结构设计,可建立代数模型如下:
图12 算例2 初始结构与相关参数Fig.12 The reliability trends in evolution process of ESA software
对此算例设定二阶段演化过程:首先在版本A1~A10中使组件N1~N10可靠度依次下降0.01(对应UM 原子操作),通过实时计算版本可靠性及相邻版本Distance 值,识别出结构中的关键组件节点;其次对关键组件,调整与之相关的控制转移概率(对应UMD 原子操作),以分析节点转移分支的偏重对整体可靠性影响的程度.演化过程如下:
根据设定,前10 个中间版本A1~A10被看作第一阶段,后4 个版本A11~A14看作第二阶段.参照表3 中各版本可靠性数值,图13 给出了演化过程的整体趋势.可看到系统可靠性在第一部分呈逐步快速下降趋势,符合预期.图14 中给出了相应Distance 值D1~D10,经比较易知软件结构中N1、N2、N3、N5及N10属于相对可靠性敏感的重要节点组件.其中,D5(0.01074) 甚至超过了起始节点D1(0.00837) 及终止节点D10(0.00789),说明其在结构中的关键程度.同样地,为了说明D1~D10值的有效性,在图14 中也附以Criticality 值C1~C10(经放大处理),观察易知其曲线与Distance 图形基本保持一致,说明使用Distance 值分析组件节点的可靠性敏感度是有效的.
图13 算例2 演化可靠性变化趋势Fig.13 Reliability trends in evolution of Case 2
4.2.3 最终结果及分析
在第一阶段演化过程计算结果基础上,从中筛选出可靠性敏感程度最高的组件N1、N2及N5.因在这些组件上的变动更易于引发明显的可靠性抖动,利于于后续演化分析.
第二阶段中有4 个中间版本A11~A14,分别对应以N1、N2及N5为分支节点的UMD 原子操作.3 个节点都具有代表性:N1处于特殊的起始位置,N5具有最大Distance 值,而N2是结构内部仅次于N5 的可靠性关键节点.
对UMD 操作分析的困难在于多参数情形.从版本A11开始,设定N1的实现发生更改,将直接影响其与后续组件N1~N4之间的控制转移关系,表现为相关分支概率的变化.在A11步,两组激发表达式被关联UMD 操作,使得分支转移概率比值P1,2:P1,3:P1,4由0.6:0.2:0.2 更新为0.5:0.2:0.3,注意只有P1,2与P1,4作为参数,而P1,3保持不变.图15(a) 中曲线II 表达了版本可靠性R11在P1,2与P1,4作为参数情况下所有可能的取值.当P1,4所占比越大时,R11值越高,实际A11版本较A10版本提升了可靠性.不考虑演化,曲线I 给出Rsys值与参数P1,2、P1,4之间的关系,它与曲线II 一致,说明了在演化过程中按曲线II 分析转移概率影响是有效的.
图14 算例2 版本抖动与组件关键程度Fig.14 Version distance and component criticality of Case 2
在A12步,比值P1,2:P1,3:P1,4经演化更新为0.4:0.3:0.3.这一步中P1,2与P1,3作为参数,P1,4保持不变.图15(b) 中曲线IV 对应R12所有可能取值,易知R12随着P1,3占比增大而提升.同样地,曲线III 表达了Rsys与参数P1,2、P1,3之间的关系,作为参照它与曲线IV 一致.版本A11、A12的两步演化在现实情况下可能只对应一步(由0.6:0.2:0.2 至0.4:0.3:0.3),增加1 个可变参数无疑加大了分析难度,亦不能给出两两比较的直观结果.故这里设定演化操作可进一步细分(如此处A11、A12),将更改限制在仅2 个参数可变的情况.组件节点拥有超过3个及以上的控制转移分支都可按此分析.
根据表3,R13值较前一版本增加,说明对节点N2而言,后续控制转移偏重N5分支则有利于可靠性提升.而R14值较前减少,说明对节点N5,控制转移偏重N7将导致可靠性下降.通过观察图14中D11~D14部分,第二阶段整体可靠性抖动程度相对平缓,但其中,D14(0.00497) 明显大于D11(0.00234)、D12(0.00185) 及D13(0.00205).版本A14对转移概率的更改幅度与之前版本相近,其影响程度却明显放大,从另一角度验证了节点N5在整体结构中是最关键的,这与文献[29]中敏感度分析结论一致.
目前可靠性模型对控制转移分支敏感度的分析仍然缺乏有效的方法,涉及对多参数的分析往往较为困难.一类基于路径的可靠性模型[24,26,29]中使用了多个执行路径来对应节点存有多个控制转移的情形,但是这种方法计算流程繁琐,不能简明分析关键节点组件的分支敏感度.本文在序列化的演化过程中使用原子操作细化描述控制转移概率的变化,每一步操作均通过实时扫描代数模型计算出可靠性变化,可监测出影响整体可靠性的关键步骤,具有可操作性与现实意义.
表3 算例2 演化过程计算结果Table 3 Evolution process calculation results of Case 2
图15 可靠性受分支概率参数变化的影响Fig.15 Reliability as a function of branch probability
5 结论
面向演化过程建模与分析一直是软件工程领域的难点问题.使用代数方法描述软件结构是精确无二义的,且相较于图形工具在可计算性上具有优势,适用于可靠性实时分析、计算.将演化过程序列化是本文的创新点.演化各中间版本(步骤) 可独立建模,中间版本前后衔接为完整的演化过程,从而建立起过程化分析模型.本文方法的有效性与易用性得到了算例验证,下一步,将在开源软件项目上开展实证研究,通过对软件更迭版本依序构建演化代数模型,并基于设计文档、源代码及代码度量数据获取可靠性建模参数,用以计算和分析可靠性变化趋势,以及揭示软件版本演化中的规律性特征和一些重要、易被忽视的中间环节.