一种基于代码圈复杂度度量的软件演化评估方法与流程

文档序号:11217422阅读:627来源:国知局
一种基于代码圈复杂度度量的软件演化评估方法与流程
本发明涉及一种基于代码圈复杂度度量的软件演化评估方法,属于软件演化与维护领域问题。
背景技术
:代码复杂度是对代码复杂程度的一种度量,是理解和维护代码所需工作量的一种指征。代码复杂度会直接影响到诸如可读性、可维护性、可理解性等软件质量属性。通过评估代码复杂度,可以帮助开发人员及时了解、控制和调整代码的复杂程度。圈复杂度是代码复杂度的一种,是用来衡量程序中判定结构的复杂程度的一种质量指标。通常,人们通过圈复杂度的度量与评估衡量软件模块判定结构的复杂程度,了解预防错误所需测试的最少路径条数,为测试人员设计测试案例提供指导。经验表明,程序的可能错误数和圈复杂度值的高低有很大关系:圈复杂度偏大的程序代码往往质量低,且难于测试和维护。随着软件的演化,其源代码会产生一定的变更,会对软件的圈复杂度、软件质量及其后继演化产生影响。有些演化操作能降低代码的圈复杂度,提高代码的质量;而有些演化操作则会提高软件的圈复杂度。很多软件项目或者由于最初设计结构的不合理,或者由于版本演化过程中累积问题的增多,最终在软件复杂性得不到有效控制的情况下崩溃,导致软件生命的结束。因此,在现有软件开发环境下,自动化地对软件的代码圈复杂度进行演化分析对于软件的迭代开发与重构、提高软件质量、延长软件的生命周期具有重要意义,并能为软件的演化提供评价依据。技术实现要素:技术问题:本发明的目的是提供一种自动化地对软件代码圈复杂度的演化进行评估和分析的方法,以解决软件演化过程中复杂度得不到有效控制的问题。较之其他软件演化度量和评估方法,该方法注重演化过程中软件圈复杂度的变化,实现对软件复杂度的控制。技术方案:本发明方法,强调软件演化中的质量控制,引入代码圈复杂度度量方法、圈复杂度阈值等,从不同层次对演化前后的软件圈复杂度进行度量和评估,进而对代码圈复杂度变化的原因进行分析,为软件维护方案提供参考。本发明的基于代码圈复杂度度量的软件演化评估方法,步骤如下:步骤1)分别为待评估软件的当前待测目标版本v_current和历史版本v_last的程序源码构造抽象语法树;步骤2)根据所述步骤1)获取的抽象语法树,分别从系统层、类层和方法层三个层次对待测软件版本的代码进行圈复杂度度量,所述待测软件版本包括当前待测目标版本v_current和历史版本v_last;步骤3)从类层和方法层分别评估待测软件版本的圈复杂度度量结果,找出软件中圈复杂度度量结果超出阈值范围的类和方法;步骤4)对待测软件的当前待测目标版本v_current和历史版本v_last的圈复杂度度量结果按层次进行分析比较,以确定变更发生的位置,具体为:先进行两个版本系统层圈复杂度的比较,确定两个版本间类的增删改;然后再进行类层次的分析,对前后版本中圈复杂度发生变化的类,确定其方法的增删改;最后进行方法层次的分析,考察同名方法的圈复杂度变化;步骤5)对当前待测目标版本v_current和历史版本v_last的项目源码本身进行分析比较,找出两者在所述步骤4)确定的变更发生的位置的代码差异,输出到格式文件中;步骤6)针对当前待测目标版本v_current和历史版本v_last,通过所述步骤4)得到的两个版本中圈复杂度发生增删改的类和方法,以及所述步骤5)得到的两个版本的代码差异,进行差异定位,即根据代码差异确定导致度量结果发生变化的原因,形成软件演化评估。进一步的,本发明的方法中,步骤2)中通过统计代码解析所得的抽象语法树中判定节点的数量来进行代码圈复杂度度量,规则为:判定节点是程序设计语言中表示条件判定的语句,通过条件判定来确定程序的控制流走向。进一步的,本发明的方法中,对于java语言,所述步骤2)中代码圈复杂度度量规则的判定节点存在于以下关键字所引导的语句中:if,for,while,do,case,catch,&&,||,:?,这些判定节点在抽象语法树ast中对应的节点如下表:表1.圈复杂度中判定节点和astnode对应表进一步的,本发明的方法中,步骤2)中分三个层次进行代码圈复杂度度量的具体方法是:方法层:通过扫描方法的抽象语法树,统计方法中的判定节点个数,将该判定节点数加1即为方法层的圈复杂度;类层次:通过扫描类的抽象语法树,统计类中的判定节点个数,将该判定节点数加1即为类层次的圈复杂度;同时类层次的圈复杂度应与该类中所有方法的圈复杂度之和相等,并据此对类层次圈复杂度结果进行校验;系统层:通过扫描整个系统的抽象语法树,统计系统中的判定节点个数,将该判定节点数加1即为系统层次的圈复杂度;同时系统层次的圈复杂度应与该系统中所有类和方法的圈复杂度之和相等,并据此对系统层圈复杂度进行校验。进一步的,本发明的方法中,步骤3)中对当前待测版本v_current代码圈复杂度的评估是通过将类层次和方法层次的度量结果与相关阈值进行比较分析完成的;方法层的圈复杂度的阈值划分如下:圈复杂度在1-10之间,程序简单,风险低;复杂度在11-20之间,程序有点复杂,有点风险;复杂度在21-50之间,程序很复杂,高风险;复杂度>50,程序无法看懂;类层的复杂度的阈值设定为50,一个项目中复杂度超过50的类所占比例应不大于5%。进一步的,本发明的方法中,步骤5)的具体流程为:分别获取软件当前版本v_current和前一版本v_last的.java文件的路径;将两个版本的源码进行对比,确定发生变更的所有文件路径,并存入变更文件路径集合fileset;遍历所述变更文件路径集合fileset中的路径,并分别在v_current版本和v_last版本中去匹配相应的路径;将两个版本中匹配成功的路径文件分别输入到源码差异分析器changedistiller中进行代码差异分析;提取分析结果,提取与圈复杂变化相关的代码变更类型,将结果输入到.csv格式文件中。进一步的,本发明的方法中步骤1)和步骤2)先将所导入的java文件转化为抽象语法树ast,再对该语法树进行遍历,统计其中“判定节点”的数量,以度量该java文件的圈复杂度。其计算公式为:java文件的圈复杂度=判定节点数+1............................公式1其中,判定节点确定为java语言中以下关键字所引导的语句:if,for,while,do,case,catch,&&,||,:?(三目运算符)。这些判定节点在抽象语法树ast中对应的节点(astnode)如上述表1。在此基础之上,我们从系统层、类层次以及方法层三个层次对v_current的软件代码圈复杂度进行度量。系统层圈复杂度度量将对项目目录中每一个.java文件中的判定结点进行统计。统计计数器初值为0,每访问到一个判定结点,统计计数器加1;由于方法的圈复杂度的值最小为1,所以每访问到一个方法声明的时候,也会对统计计数器加1。即,系统层的圈复杂度值为所有类中的所有方法的圈复杂度之和。类层圈复杂度度量统计并记录项目目录中各个类的全名及其圈复杂度;类的圈复杂度计算为类中每个方法的圈复杂度之和。方法层圈复杂度度量统计并记录项目中各个方法的全名及其圈复杂度,如公式1所示,圈复杂度值为判定节点数加1。获取了v_current的圈复杂度数据之后,可以按层次对其进行复杂度评估,考察其类层次和方法层次的复杂度是否超出阈值范围。系统层圈复杂度与系统的规模密切相关,因此没有阈值定义。根据业界常用的标准,本发明对方法层圈复杂度的阈值划分如下:圈复杂度在1-10之间,程序简单,风险低;复杂度在11-20之间,程序有点复杂,有点风险;复杂度在21-50之间,程序很复杂,高风险;复杂度>50,程序无法看懂。由于没有找到一个大家普遍认可的类层圈复杂度阈值规范,本发明进行了类层圈复杂度阈值分析实验以获取经验数据:通过对github开源代码库(https://github.com)中排名在前157的基于java语言的开源项目的圈复杂度的分析获取类层圈复杂度的阈值。由于这157个开源项目都是被公认为开发和维护比较好的开源项目,藉此可以确定类层圈复杂度阈值的合理性。阈值是在对上述157个项目进行类层次复杂度度量的基础上得到的,具体方法如下:(1)对这157个项目分别进行类层圈复杂度的度量。通过度量,我们共得到了132540个类的圈复杂度信息。(2)分析这些数据得到其平均值u和标准差s。通过处理这132540个类的圈复杂度数据,我们得到其平均值u为13.4,标准差为36.7。(3)将阈值设置为u+s。通过对u和s的计算,得到的类层圈复杂度阈值取整后为50。在这157个项目的132540个类中,类层圈复杂度超过50的类个数为6432,占比仅为5%,剩下95%的类的圈复杂度都是在50以下。据此,本发明对类层圈复杂度的阈值划分在50以内;一个项目中应将绝大多数(95%)类的复杂度控制在50以内。如果一个类的圈复杂度超过50,则视为复杂类,在后续演化中可以考虑拆分。如果一个项目中超过5%的类都出现了圈复杂度超过50的情况,则该项目的类层圈复杂度过高,后续演化中应考虑架构上的优化。进一步的,本发明的方法中步骤4)通过分析相邻版本的源码找出两版本之间的代码差异,将结果输出到格式文件(.csv文件)中。具体算法描述如下:(1)分别获取软件当前版本v_current和前一版本v_last的.java文件的路径;(2)根据步骤4)的结果,确定发生变更的所有文件路径,并存入变更文件路径集合fileset;(3)遍历fileset中的路径,并分别在v_current版本和v_last版本中去匹配相应的路径;(4)将两个版本中匹配成功的路径文件分别输入到源码差异分析器(changedistiller)中进行分析;(5)提取分析结果,提取与圈复杂变化相关的代码变更类型,将结果输入到.csv格式文件中。本发明方法可以在对软件的代码圈复杂度进行度量评估的基础上,对演化过程中软件各版本的代码复杂度进行对比,对版本间代码复杂度的变化进行定位和分析。本发明利用代码圈复杂度度量与评估,分析软件演化过程中代码复杂度变化的问题。在软件演化过程中,利用上述方法对软件各个演化版本进行代码圈复杂度的度量和评估,其评估结果可以展现演化过程中软件代码的质量变化。对于演化过程中复杂度发生了较大变化的版本,可进行相邻版本之间的代码差异分析,确定变更发生的位置,形成分析报告。相关人员可以根据分析报告了解当前版本软件与前一版本相比发生了哪些演化,分析演化过程中软件代码复杂度变化的原因,演化操作对代码复杂度的影响。有益效果:本发明与现有技术相比,具有以下优点:本发明方法通过对eclipsejdt生成的抽象语法树进行判定节点的分析和统计,从方法层、类层和系统层度量软件代码的圈复杂度,主要用于发现软件演化中代码复杂度的变化并对其进行原因分析,与现有技术相比,具有以下优点:(1)本方法利用eclipsejdt将待测java软件转化为抽象语法树,通过对抽象语法树的遍历统计规定范围内代码的判定节点个数来计算圈复杂度,能够从不同层面分别计算代码的圈复杂度。传统的圈复杂度度量通常用于面向过程程序中的单个函数,或者用于面向对象程序中的方法层面;本方法从系统层、类层次以及方法层次三个层面对软件的圈复杂度演化进行全面的度量和评估。(2)本方法通过对软件演化过程中各版本各层面的圈复杂度度量和评估,能够展现演化过程中软件代码各个层面上的复杂度变化;及时对复杂度超标的方法和类提出预警;及时发现演化过程中程序变复杂的趋势,并对软件开发人员提出预警。目前,有一些方法通过对软件复杂度的度量和评估做到了对其中复杂度偏高的方法进行预警,但目前尚未发现有方法针对演化过程中的复杂度变化趋势做出预警。(3)本方法支持对软件演化过程中圈复杂度发生明显变化的版本进行原因分析。现有的代码复杂度度量方法和工具仅提供对代码复杂度的度量,而代码变更分析方法则只提供了对代码整体变更的分析,并不针对复杂度变化,因而得出的变更信息种类繁杂,难以评判。本方法在获取各个软件版本类层次的圈复杂度数据的基础上,通过对比分析获取相邻版本中各类的复杂度变化情况,再通过相邻版本软件源码比对检测代码圈复杂度发生了变化的类和方法,对其变更类型、变更细节进行详尽分析,从而可以定位出圈复杂度演化的原因。附图说明图1是基于代码圈复杂度度量的软件演化评估方法流程图,表示典型的通过圈复杂度度量、评估和原因分析促进软件演化的整个流程。具体实施方式下面结合实施例和说明书附图对本发明作进一步的说明。图1给出了基于代码圈复杂度度量的软件演化评估方法的流程。实施例中所使用项目为java开源软件项目jeditor。jeditor是一个基于java的开源文本编辑器,截止目前发布了7个版本,代码行数在13098-13635之间,下载地址是http://sourceforge.net/projects/jeditor/files/。进行圈复杂度度量评估的的实施例为jeditor0.2版本;在对jeditor各个版本分别进行了度量的基础上,我们选择了复杂度变化最大的jeditor0.4和jeditor0.4.1进行圈复杂度演化原因分析的实施例。具体实施方式为:步骤1)使用jdt对jeditor0.2的程序源代码进行代码解析,生成抽象语法树。抽象语法树(abstractsyntaxtree,ast)作为程序的一种中间表示形式,在代码解析、程序分析等诸多领域有广泛的应用。它将java源代码映射为树的形式,每个java语法结构被表示成ast节点。java源码中的判定节点(如if,for等)均被解析为相应的ast节点(astnode),如ifstatement、forstatement等。具体映射规则请见表1。步骤2)根据解析后的ast树对jeditor0.2进行方法层次、类层次和系统层次的圈复杂度度量和评估。系统层度量扫描整个版本的所有.java文件的ast树,对每个.java文件中的判定节点个数进行统计,每访问到一个判定节点,圈复杂度就加1;同时由于方法的圈复杂度的最小值为1,所以每访问到一个方法声明时,系统层的圈复杂度也会加1。以此方式度量出整个系统的圈复杂度。类层次度量做相似的操作,对版本中各个类的判定节点个数进行统计,并存入类层圈复杂度信息数据库表(classmccabeinfo)中。该信息表中存放了项目的名称、版本号、类名、所属包名、文件名以及类的圈复杂度信息。方法层度量针对每一个方法进行判定节点的统计,并将度量结果存入方法层圈复杂度信息数据库表(methodmccabeinfo)中。该信息表中存放了项目的名称、版本号、方法所属包名、方法所属类名、文件名、方法名以及方法的圈复杂度信息。度量完成后,可根据阈值对jeditor0.2版本中的类和方法进行评估分析。根据系统层圈复杂度度量,可得:jeditor0.2的系统圈复杂度值为1983。因为系统层圈复杂度度量结果与系统规模息息相关,无法以普通评估标准对其进行评估,将在演化评估中对其进行分析。根据类层圈复杂度度量,可得:jedtor0.2类总数为96个,其中圈复杂度小于50的有85个,占总类数目的88.54%;复杂度大于等于50的类有11个,占比11.46%。根据我们对类层圈复杂度的阈值定义,目前超过阈值的类占比11.46%,超过5%,建议予以调整。类层度量还可得到所有复杂度大于阈值50的类的全名,并按照复杂度由大到小的顺序排列。jeditor0.2中圈复杂度最高的类为jeditor,圈复杂度260。通过人工查看源码,发现这个类的代码行达到了2746行,属性有44个,方法有60个,明显类中包含功能太多。根据方法层圈复杂度度量,可得:jeditor0.2项目版本的方法总数为550个,圈复杂度小于10的方法有522个,占总方法个数的94.91%;圈复杂度在10到20之间的有14个,占比为2.55%;圈复杂度在20到50之间的方法有8个,占比为1.45%;圈复杂度大于50的方法为6个,占比为1.09%。具体数据如表2所示:表2.方法的圈复杂度分布表方法圈复杂度(cc)范围方法个数所占比例cc<=1052294.91%10<cc<=20142.55%20<cc<=5081.45%cc>5061.09%方法层度量也可得到所有复杂度大于阈值的方法的全名,并按照复杂度由大到小的顺序排列。jeditor0.2项目版本中圈复杂度最高的方法值为130,是org.jeditor.scripts.perltokenmarker类中的marktokensimpl(byte,segment,int)方法。从软件代码库中获取jeditor项目的其它6个版本的源码,分别按照步骤1)和步骤2)进行代码解析和各层次的圈复杂度度量。jeditor项目各版本系统层圈复杂度度量结果如下:表3.jeditor各版本的系统层圈复杂度jeditor版本号0.20.30.40.4.10.4.20.4.30.4.4系统层圈复杂度cc1983198520002032204720472049jeditor项目各版本类层圈复杂度度量结果如下:表4.jeditor各版本的类层圈复杂度jeditor项目各版本方法层圈复杂度度量结果如下:表5.jeditor各版本的方法层圈复杂度从表3可以看到:各版本中系统圈复杂度最低的是0.2版本,为1983;最高的是0.4.4版本,为2049。从整体趋势上看,jeditor项目的圈复杂度逐渐提高,在0.4.2版本后趋于稳定。变化幅度最大的是0.4到0.4.1版本,但复杂度增加的数值较小,所以可以看出jeditor项目的整体逻辑结构很稳定,项目版本间的变化较小。因此,以下的对比分析将针对变化幅度最大的0.4到0.4.1版本进行。步骤3)对jeditor0.4和0.4.1版本的类层复杂度信息表(classmccabeinfo)中调取两个版本中类信息进行分析和比较,定位发生变化的类;然后从相应版本方法层复杂度信息表(methodmccabeinfo)中调取类信息所有度量结果进行分析比较,找出其中质量指标变化之处。通过对两个版本类层次度量值的比对发现有3个类发生了变化,其中有一个是新增类。由系统分析得:两个变更类是jappeditor类和filepane类,0.4.1版的新增类是settingsdialog,它们都属于org.jeditor.app包。步骤5)对jeditor0.4和0.4.1版本的项目源码本身进行分析比较,找出两者的代码差异;进行差异原因分析,对导致度量结果各项变化的原因进行定位,并将结果输出到csv文件中。通过对两个版本的项目源码进行去重比对,发现:jappeditor类中新增3个方法,删除2个方法,同时其中的actionperformed方法复杂度由2降为1;filepane类中新增1个方法;0.4.1版本的新增类settingsdialog中有19个方法。方法名在此不再赘述。上述实施例仅是本发明的优选实施方式,应当指出:对于本
技术领域
的普通技术人员来说,在不脱离本发明原理的前提下,还可以做出若干改进和等同替换,这些对本发明权利要求进行改进和等同替换后的技术方案,均落入本发明的保护范围。当前第1页12
当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1