张云洁 张 璇,2 王 旭 任峻民 唐子淇
1(云南大学软件学院 昆明 650091)
2(云南省软件工程重点实验室(云南大学) 昆明 650091)
3(云南大学经济学院 昆明 650091)(932145749@qq.com)
在软件生命周期中,软件系统的需求会不断变化,新的需求频繁出现.当需求变更出现时,对于软件系统的影响往往难以评估,尤其是对于较大型的软件系统,很难明确需求变更可能会对整个系统或系统的一部分产生什么样的影响.而如果忽略这些影响,又可能导致需求变更实施成本高出预期数倍.尽管需求工程对于软件项目的成功至关重要,但大多数需求决策往往取决于开发人员的偏好和权衡,缺乏一种系统的、明确的管理方法.对软件需求变更进行有效管理对软件质量乃至软件项目的成功至关重要.为了衡量和评估需求变更所带来的影响,本文引入技术债务的概念.
技术债务运用经济学中“债务”概念来描述“长期软件质量与短期利益的权衡”[1-2].当为了实现项目短期利益而实施技术折中时,所欠下的技术债务从长期目标来看,会影响软件的质量、成本和开发运维效率.然而,在软件开发过程中,为了快速达到一个短期的目标,开发者可能会暂时忽略需求变更引发的影响,正如技术债务所定义的,在没有完全理解变更带来的长期影响时,很可能会产生不必要的副作用.目前,软件系统随着业务需求的演变,不断产生需求变更,研究表明,85%~90%的软件开发预算都用于了运维阶段.为了减少变更成本,尽早地管理需求变更非常重要.然而,软件需求存在的不确定性使面向软件需求变更进行技术债务管理更加具有挑战性[3].
应用经济学概念管理技术债务是一个引起学术界和工业界关注的研究课题.实物期权分析已应用于软件工程的多个领域,如软件体系结构[4]、设计[5]、风险管理[6]和软件开发方法[7].在经济学领域,边际贡献是指产品的销售收入超过产品的变动成本的差额,如果产品不能提供边际贡献,通常选择放弃生产这种产品[8].而边际收益是指增加一个单位产品的销售所增加的收益,利用边际效益分析法有利于实现利润最大化[9].将边际贡献和边际收益概念运用到需求变更技术债务的管理中,可以有效辅助对需求变更的取舍决策.因此,本文研究因需求发生变更而引发的技术债务,定义需求变更技术债务,根据需求变更之间的关联关系给出需求变更技术债务量化方法,同时采用边际效益分析法得到需求变更的边际贡献值,为需求变更的实现顺序提供依据,以协助项目组管理技术债务并且做出相应决策.本文的主要贡献包括:
1) 运用经济学中边际贡献的概念定义由需求变更技术债务带来的边际贡献,通过分析需求变更边际贡献与需求变更实现顺序的相关性,验证了需求变更边际贡献概念的可用性.目前,学术界和产业界还没有将边际贡献应用于管理需求变更技术债务的相关研究成果.本项目组的前期工作虽然也对需求变更技术债务进行了相关研究,提出基本的需求变更技术债务概念[10],但也未使用边际贡献的概念和分析方法.
2) 运用梯度提升决策树(gradient boosting decision tree, GBDT)算法提出需求变更技术债务的边际贡献能力分析方法,对各个变更因素取值对其边际贡献影响的重要度进行排序,以确定影响边际贡献大小的重要因素,为需求工程师进行需求变更管理提供支持.
3) 对需求变更技术债务、需求变更关联关系、需求变更边际贡献进行定义、检测、量化和评估,提出需求变更技术债务的边际贡献量化评估方法,为经济学和需求工程相结合的软件开发与实践提供新思路.
技术债务最普遍的特征之一是它的跨学科性质,因为它结合了金融和软件工程理论的要素.尽管这种性质可能会导致更多的挑战(由于软件和财务观点之间的差距),但它可能有助于软件工程师、架构师、测试人员等和项目经理之间的沟通.从业者的经验表明,使用基于经济学的术语和方法,如实物期权、成本收益分析和投资组合管理,可以弥合软件工程师和软件项目经理之间的认知差距,并有助于质量取舍的谈判,以加快产品交付[11].针对本文研究的需求变更技术债务,下面对该领域已有相关工作进行介绍.
技术债务简洁地描述了软件工程师在开发软件时面临的一个普遍问题:如何平衡短期价值与长期质量.它的吸引力在于,一旦技术债务变得可见,工程师就可以清晰地看出债务对软件项目有害或有益,以及债务积累和持续产生的利息在软件开发过程中对系统质量造成的影响[12-14].Zazworka等人[15]通过分析已有技术债务识别方法,发现不同的技术债务必须使用不同的识别方法.另外,Deo等人[16]研究已有技术债务方法与软件质量之间的关联关系,发现不同的技术债务方法关注不同的软件质量需求,在实践中需要明确技术债务类型.因此,在软件项目全生命周期过程中,不同阶段的技术债务也需要使用不同的方法进行识别和处理.Li等人[12]在对技术债务进行综述研究的工作中,总结了10类软件技术债务,其中,代码技术债务研究最多.并且,SonarQube已成为一个成熟地用技术债务来量化代码质量的平台,它可以为软件项目组发现其代码的技术债务,帮助其建立维护活动的计划[17].相对而言,需求技术债务由于其量化困难,研究成果较少[12].在已有的相关研究工作中,Ernst等人[18-19]首先定义需求债务为最优需求方案和实际解决需求方案之间的差距,而债务利息是这个差距的增长速率,并利用需求建模工具对变化的需求进行管理.Abad等人[20]应用实物期权方法对软件项目中的需求债务进行管理,且使用二项式模型和动态规划方法探讨使用实物期权方法对于需求债务评估的可行性.上述这些方法将技术债务概念引入需求工程领域,为后续研究工作奠定了重要基础,但他们仅对单个已实现的需求进行分析研究,忽略了需求变更可能引发的扩散影响.针对这个问题,本项目组前期充分考虑变更影响,提出需求变更技术债务概念,并对需求变更技术债务进行了初步的量化分析[10].基于前期研究工作考虑的需求变更影响,可以得出对需求变更进行全面分析并提供有效的债务控制对于需求管理决策是一个有效的支持.但所有上述方法都缺乏对新需求变更的预测分析能力,随着软件系统需求的持续变化,当需求发生变更时,如果只分析单个已有需求,不利于需求管理,因此,本文工作增加了对新需求变更的预测与分析,可以为需求变更管理提供更为有效的支撑.
在本节中我们将经济学中边际贡献的思想引入需求变更的技术债务管理中.
在软件的整个生命周期中,每当提出一个需求变更请求时,就可能伴随着一个需求变更技术债务的产生.需求变更之间必然存在的依赖关系使得需求变更管理更加困难,此依赖关系也是技术债务“利息”的来源.为了直观地展示需求变更之间的关联关系,使用一个有向图来描述.在这个有向图中,节点表示需求变更,边表示需求变更的关联关系,需求变更的关联关系图定义如下:
定义1.需求变更关联关系图.需求变更关联关系图是一个三元组G=V,E,R.其中V是节点的集合,vi∈V(i=1,2,…,m)表示一个变更需求;E是边的集合,eij∈E(i=1,2,…,m;j=1,2,…,n)表示一个有序元素对(vi,vj),vi,vj∈V;R是一个关联函数,它使E中的每一条边对应V中的一个节点,ri∈R(i=1,2,…,m)表示一个关联关系.
需求变更技术债务的一个重要指标就是需求变更之间的关联关系.变更请求之间的链接属性表示彼此之间的关系.以JIRA系统为例,链接属性有10种,如表1所示.引入经济学中边际贡献概念后我们对这10种关联关系进行研究,其中符合需求变更技术债务关联关系可变成本类关系的关系是blocks,depends upon,requires,relates to,breaks;符合需求变更技术债务收入类关系的关系是is required by,duplicates,is duplicated by,is depended upon by,contains,is related to,incorporates.其他类型不影响对技术债务的分析,因此,不列入可变成本类和收入类关系中.
Table 1 Issue Links in JIRA
定义2.需求变更关联关系类型.需求变更关联关系基本类型定义为2种,分别为可变成本类变更关联关系和收入类变更关联关系.可变成本类变更关联关系是指实现会增加其他需求变更实现代价的变更关联关系.收入类变更关联关系是指实现会给其他需求变更带来收益的变更关联关系.
在管理软件需求变更时,很大一部分的变更管理工作是由开发者基于其个人偏好和直觉而驱使的[21].而且技术人员与用户之间的沟通也会存在理解偏差.这种为了实现短期利益而忽略长期发展的需求变更所带来的技术债务,我们将其定义为需求变更技术债务.
定义3.需求变更技术债务.需求变更技术债务是因快速实现需求变更或未实现需求变更而引出的花费,分为本金和利息.本金是需求变更本身的花费,利息是与该需求变更有关联关系的其他需求变更的花费.
本文使用时间花费对需求变更的花费进行度量,时间花费为需求变更请求的解决时间与提出时间之差,即:
C=TR-TC,
(1)
其中,TR是需求变更请求的解决时间,TC是变更请求的提出时间,其中下标R(resolved)是解决,下标C(created)是创建,C(cost)是变更请求的时间花费.以变更请求HADOOP-1025为例:HADOOP-1025的提出时间为2007-02-01T02:54;解决时间为2007-02-04T05:57,则HADOOP-1025的时间花费为C=TR-TC=270 180 s.
需求变更技术债务的量化分为2部分,包括本金的量化及利息的量化.需求变更技术债务为
(2)
其中,D(debt)表示需求变更技术债务总值.C是需求变更的时间花费,cij是第i层(1≤i≤m)第j个(1≤j≤n)需求变更技术债务的利息,i和j分别是以该需求变更为原点和该需求变更具有第i级关系的第j个需求变更.CP则表示需求变更技术债务的本金,下标P(principal)表示本金.根据需求变更关联关系图,系数li表示与该需求变更关联的需求变更数的倒数,li用来表示关系的关联强度,li越小,这个需求变更的关系越复杂.系数rx(x≥1,整数)表示不同的依赖关系类型,可变成本类需求变更关联关系和收入类需求变更关联关系的系数值为1,其他关联关系系数值为0.
在前面的需求变更技术债务的量化过程中,我们得到了每一个需求变更技术债务的债务值,接下来,我们把需求变更项目的贡献定义为需求变更的边际贡献:
定义4.需求变更边际贡献.需求变更边际贡献是指需求变更对项目的贡献力,分为销售收入和可变成本2个部分.销售收入指的是与该需求变更具有收入类关联关系的需求变更债务值之和.可变成本指的是与该需求变更具有可变成本类的需求变更债务值之和.需求变更边际贡献值等于销售收入减去可变成本,即:
(3)
其中,M(marginal)表示需求变更的边际贡献率,Di表示与这个需求变更技术债务具有变更关联关系的需求变更的债务值,a表示需求变更之间的变更关联关系为收入类变更关联关系,设a=1,p表示需求变更之间的变更关联关系为可变成本类变更关联关系,设p=-1.
在经济学中,边际效益是指以最低的成本使经济利润最大化,从而达到帕累托最优.指与前一单位相比,后一单位物品或劳务的效用.如果后一单位的效用大于前一单位的效用,则边际效用递增,反之,边际效用递减.在会计中,边际效益是指以销售收入减去变动成本后的余额,以边际贡献为指标.边际贡献也是基于损益分析原理的产品生产决策的重要指标.
需求变更本身的债务值可以看作是该需求变更的固定成本.在需求变更的偿还过程中,一定量的具有变更关联关系的需求变更的边际贡献(也就是销售收入减去可变成本后的结果)首先是用来弥补需求变更的固定成本总额,在弥补了需求变更的所有固定成本后,如有多余,才能构成利润.这就有可能出现3种情况:
1) 当被偿还的需求变更的边际贡献等于所发生的固定成本总额时,只能保本,即做到不盈不亏.
2) 当被偿还的需求变更的边际贡献小于所发生的固定成本总额时,就要发生亏损.
3) 当被偿还的需求变更的边际贡献大于所发生的固定成本总额时,将会盈利.
因此,需求变更边际贡献的实质所反映的就是该需求变更为软件项目所能作出的贡献大小,只有当需求变更的贡献能力达到一定的数量后,该需求变更的处理所带来的边际贡献才有可能弥补其本身的技术债务,为软件系统的质量提升带来盈利.
在实际项目中,实现成本过于高且毫无实现价值的需求变更的技术债务偿还会被慎重考虑.因此,经过反复验证分析,我们设置临界参数,为该需求变更的边际贡献值与其固定成本即该需求变更本身债务值做比较.我们把这个临界值定义为需求变更参考系数.
定义5.需求变更参考系数.需求变更参考系数指的是需求变更的技术债务是否值得被偿还的判断参数.
形式化计算为
J=M-D,
(4)
其中,J表示判断参数,D表示债务值也就是固定成本,M表示边际收益.若J<0,表明需求变更边际贡献小于其自身的固定成本,则慎重考虑该需求变更;若J>0或J=0,表明需求变更边际贡献大于其自身的固定成本,则根据需更变更边际贡献顺序表做顺序处理.
需求变更边际贡献的量化评估使用如图1所示的5个步骤:
Fig. 1 Quantitative evaluation process of marginal benefit for requirement changes
步骤1. 从项目中收集历史需求变更数据,需求变更用vi∈V,i=1,2,…,n表示,根据2.1节中需求变更基本类型的定义,将需求变更关联关系分为2种基本类型.可变成本类变更关联关系在需求变更的关联关系图中定义为元素对(vi,vj)的关联关系rk=cost(其中:i=1,2,…,m;j=1,2,…,n;k=1,2,…,n);收入类变更关联关系在需求变更的关联关系图中定义为元素对(vi,vj)的关联关系rk=income(其中:i=1,2,…,n;j=1,2,…,n;k=1,2,…,n).
步骤2. 基于收集的数据进行筛选,并构建需求变更的关联关系图,图2给出一个Hadoop项目需求变更关联关系图的示例.
Fig. 2 Requirements change relationship model
2011年5月27日,名为dhruba borthakur的用户提交了需求变更的类型为改进的需求变更HDFS-2006,要求HDFS可以提供文件存储的扩展属性,但是开发人员并没有对其进行评估和处理,导致产生一系列bug(即HADOOP-11286,ACCUMULO-3100等),接下来,越来越多与其相关的需求变更被提出,最后,部分关联关系图如图2所示,其中,突出显示了3个具有可变成本类变更关联关系的节点,其他节点关系类似.
步骤3.计算需求变更技术债务值,包括本金和利息2个部分.例如:图2中变更请求HADOOP-10150的债务计算为
所有Hadoop项目需求变更技术债务计算后,结果排名前10的变更如表2所示.
表2给出了排名前10的需求变更技术债务值,对于债务值较大的需求变更,如HDOOP-8744,往往意味着其与其他需求变更之间的关联关系比较复杂,所以在偿还时需要考虑多方面因素.接下来,利用需求变更技术债务值的结果继续进行下一步需求变更边际贡献值的计算,对我们进行需求变更偿还决策提供参考.
Table 2 Hadoop Requirement Changes’ Technical Debt
步骤4.在上述需求变更技术债务的量化过程中,我们得到了每一个需求变更技术债务的债务值,根据定义4我们将一个需求变更具有可变成本类变更关联关系的需求变更债务值之和看作该需求变更的可变成本;将一个需求变更具有收入类变更关联关系的需求变更债务值之和看作该需求变更的销售收入.
例如变更请求HADOOP-9671的边际贡献值为
M(HADDOP-9671)=(235 693+3 154 727.5+225 976)-(617 499+4 672)=5 194 225.5 s.
与需求变更HADOOP-9671具有可变成本类关联关系的需求变更为HADOOP-2856(D=617 499 s)、HADOOP-4685(D=4 672 s);与需求变更HADOOP-9671具有收入类关联关系的需求变更为HADOOP-9392(D=2 435 693 s)、HADOOP-8779(D=3 154 727.5 s)、HADOOP-9533(D=225 976 s).根据式(3),用与该需求变更具有收入类关联关系的需求变更债务值之和减去与该需求变更具有可变成本类的需求变更债务值之和就可以得到需求变更HADOOP-9671的边际贡献.将得到的每一个需求变更的边际贡献由大到小顺序排列得到需求变更边际贡献顺序表.对于不存在变更关联关系的需求变更,对于其债务值的偿还,可以根据需要随时处理,所以不需要计算边际贡献值为实现顺序做决策.对于具有其他变更关联关系的需求变更,可按需求变更边际贡献顺序表顺序处理.
Hadoop项目中需求变更边际贡献计算结果排名前10如表3所示:
Table 3 Hadoop Marginal Contribution for Requirement Changes
得到边际贡献结果排序表后,可以把排序表的顺序作为需求变更实现顺序的参考.例如:表3中需求变更边际贡献值最大的为需求变更HADOOP-8065,其边际贡献值8 435 551.75,那么在我们考虑需求变更债务值的偿还时,应该对其优先考虑,以达到最大收益、最小成本的目的.
参照需求变更的边际贡献值对变更优先级进行排序意味着边际贡献值应与变更优先级具有相关性,下面我们用皮尔逊相关系数分析需求变更边际贡献与需求变更实现的时间相关性,以验证需求变更边际贡献排序表的可用性.使用皮尔逊相关系数计算为
其中,M为需求变更边际贡献,t为需求变更实现时间.
我们对Hadoop项目进行相关性计算,相关系数结果为0.912,表明需求变更边际贡献与需求变更实现顺序具有强关联关系,即:运用需求变更边际贡献为需求变更提供决策支持具有一定的参考价值.
步骤5. 需求变更参考系数J值计算.利用定义5和式(4),对需求变更进行参考系数计算,结合需求变更边际贡献的量化结果,得到需求变更参考系数J值表,给出需求变更优先级.例如:Hadoop项目中需求变更J值(J<0)部分计算结果如表4所示:
Table 4 J Values for Hadoop Requirement Changes
以表4中变更请求HADOOP-8065为例,变更请求HADOOP-8065是一个改进类型的变更请求,它希望可以提供一个密钥用于检索托肯认证实体和Hadoop服务的密钥或证书,主要包括:定义密钥提供API,以查询具有特定实体名称的密钥证书;定义并实现相关实体用于实现密钥提供的插件;基于本地密钥存储文件实现简单密钥提供程序.由表4可知,HADOOP-8065的J值为负且最小,所以HADOOP-8065为项目所带来的贡献不大,却会耗费大量的成本,由此可知,HADOOP-8065的处理是否偿还其债务值是需要开发人员慎重考虑的.而在实际情况中,HADOOP-8065的提出时间是2013年8月5日,这个变更请求截至2018年2月23日都没有被处理.
另外,Hadoop项目中需求变更J值(J>0)部分计算结果如表5所示.
表5中需求变更的J值均大于0,这些需求变更为盈利类,对于此类需求变更,可以依据需求变更边际贡献排序表的先后顺序依次处理.
Table 5 J Values for Hadoop Requirement Changes
本节的研究目的是构建一个能够预测需求变更边际贡献能力的预测模型.首先,定义预测指标,选取适当的预测方法和预测指标介绍预测模型的综合性能评价指标;接下来,介绍特征相对重要度的计算方法.
对于一些未解决的需求变更,其解决时间用实验时的时间来衡量,方法较为简单,而没有解决时间的情况,应该用预测方法预测更为合适.因此,下面我们采用科学的预测方法来分析未解决需求变更的边际贡献能力.在构建预测模型时,我们通过选择以下能够衡量需求变化边际贡献的特征来定义预测指标:
1) 指标能够反映需求变更解决时间的特征;
2) 指标能够反映需求变更边际贡献随着时间不断变化的特征.
在本项目的早期阶段我们发现:变更请求报告的重要程度可以使用变更请求报告本身的一些指标进行预测.受缺陷预测、需求易变性、缺陷报告质量、缺陷优先级排序的相关研究启发[21],我们定义了在JIRA跟踪系统中能够衡量变更请求报告的4个指标:需求变更的需求变更类型(issue type)、需求变更状态(status)、需求变更的重要性(priority)、需求变更的解决方式(resolution)等类别特征能够衡量至今未解决的需求变更即将花费的解决时间的指标.如表6所示:
Table 6 Prediction Indicators
受本项目前期工作[21]的启发,发现除了变更请求报告的提出时间、解决时间等指标可以直观地影响需求变更的时间花费以外,变更请求报告的一些其他指标对时间花费也会有一定的影响,从而进一步影响到需求变更的边际贡献能力大小,由此可见,选用这些指标来构建需求变更贡献能力的预测模型是可行的.
本文的研究目的是建立一个未偿还的需求变更的边际贡献能力预测模型.我们选择梯度提升决策树作为构建预测模型的方法.GBDT分类问题的决策树是二叉分类树,回归问题的决策树是二叉决策树,我们这里使用的是二叉分类树.GBDT与Adaboost最主要的区别在于两者如何识别模型的问题.Adaboost基于错分数据点对问题进行识别,通过改变错分数据点权重值对模型进行改进.GBDT通过负梯度来识别问题,通过计算负梯度来改进模型.在本文中以Spring Framework项目为研究案例,分析其JIRA系统需求变更跟踪管理数据,将需求变更的需求变更类型(issue type)、需求变更状态(status)、需求变更的重要性(priority)、需求变更的解决方式(resolution)等属性的取值作为特征值,将需求变更的边际贡献值分为贡献能力大、贡献能力小2类作为其标签.构建其训练数据集,以预测需求变更的贡献能力.本文选择分类回归树(classification and regression tree, CART)作为基学习器:GBDT预测模型提供需求变更贡献能力大小的分类预测.因此需要确定一个点来确定需求变更边际贡献能力的大小,贡献能力大的预测为强,贡献能力小的预测为弱.在我们的研究中,设置GBDT预测模型的分类点为一般数学中通常选取的中位数.我们把需求变更边际贡献值大于需求变更边际贡献值序列中位数的分类为强;把需求变更边际贡献值小于需求变更边际贡献值序列中位数的分类为弱.
为了评估预测模型的性能,本文使用曲线下面积(area under the curve,AUC)和查全率(recall)这2个指标来评价模型的性能.AUC是需求变更边际贡献能力被正确预测的数目大于被错误预测的数目的概率,AUC越大表示模型区分正例和负例的能力越强.查全率又称为召回率,是需求变更贡献能力被正确预测为能力大的数目与总的实际为能力大的数目的比值.
本文用Python语言开发了一套需求变更边际贡献分析工具以帮助软件项目管理需求变更,提高软件质量,减少开发成本.工具的预测模型流程图如图3所示:
Fig. 3 Flow chart of prediction model
利用需求变更贡献能力分析工具,我们先从变更请求报告中获得数据,再对数据进行预处理来得到关系图,然后进行度量指标的计算,同时得到需求变更边际贡献排序表和需求变更边际贡献值排序表.最后,定义预测指标,选择预测方法,以及预测模型性能的评价指标,进行需求变更边际贡献能力预测,根据评价指标验证预测模型的可用性.
本节以Spring Framework项目为研究案例,下面主要介绍案例数据的收集处理、需求变更边际贡献的指标计算、 需求变更边际贡献分析的实验过程和实验结果的分析.
本文分析研究变更请求追踪系统上的变更请求报告,用时5天,总共收集了Spring Framework项目20 000条变更请求报告,最终我们将收集的20 000条需求变更存入文件中,因为本文的研究涉及到需求变更的提出时间、解决时间、需求变更之间的关联关系、需求变更的需求变更类型(issue type)、需求变更状态(status)、需求变更的重要性(priority)、需求变更的解决方式(resolution)等属性.
在计算过程中,我们主要以具有需求变更关联关系的需求变更作为研究对象,所以从收集的20 000条变更请求报告中筛选出具有关联关系的6 000条需求变更进行下一步研究.我们将收集到的数据存入表格中,提取出计算本金所需要的提出时间、解决时间,方便后续实验对本金进行计算.数据存储如图4所示:
Fig. 4 Data storage
Fig. 5 Partial screenshots of calculation results
图4中的中括号表示此单元格为空,也就是该需求变更与其他需求变更不具有此项关联关系.其中序号2记录中的SPR-927表示SPR-926与SPR-927之间的需求变更关联关系为is duplicated by.
本文对JIRA中的10种关联关系进行了研究以建立需求变更关联关系数据集.其中符合需求变更技术债务关联关系可变成本类关系的关系是blocks,depends upon,requires,relates to,breaks;符合需求变更技术债务收入类关系的关系是is depended upon by,duplicates, is related to, is duplicated by,contains, is required by, incorporates.其他类型的关联关系出现较少,对整个软件项目的影响可以忽略不计,所以不纳入可变成本类和收入类变更关联关系中,作“不存在需求变更关联关系”处理.
根据第2节的量化方法及步骤,需求变更边际贡献计算部分结果如图5所示:
在图5中,第1列表示序号,Created列表示需求变更的提出时间,Resolved列表示需求变更的解决时间,capital列表示需求变更的本金,interest列表示需求变更的技术债务值,boundary列表示需求变更边际贡献值,T列表示需求变更边际效应参考系数值计算结果.
1) 需求变更边际贡献值计算结果分析
由第2节对边际贡献的皮尔逊相关性分析可知,需求变更的实现顺序与需求变更的边际贡献值强相关.那么对于具有其他变更关联关系的需求变更,可按需求变更边际贡献顺序表顺序处理;对于不存在变更关联关系的需求变更,其债务值的偿还可以根据需要随时处理.需求变更边际贡献计算结果排名前10如表7所示:
Table 7 Marginal Contribution of Requirement Changes
如表7所示,第1列为排名;第2列表示需求变更的编号;第3列表示需求变更边际贡献值.在需求变更边际贡献排序表排名第一的为需求变更SPR-11399,名为“Improve documentation of transactional support in the TestContext framework”.从现状来看,因为SpringTestContext框架中事务支持参考手册中的文档目前非常缺乏,目前只有2个示例:一个示例是虚构的TransactionalTest,它是一个基于JUnit的POJO测试类,它演示了与SpringTest-Context框架中事务相关的所有注释的用法,但不太具有代表性.另一个示例为AbstractClinicTests,它是Abstract Transactional JUnit4 Spring Context Tests的扩展,它演示了CountRowInTable()的使用.因此,尽管参考手册中有2个示例,但这2个示例都没有展示出最佳的实践或典型的使用场景.此外,使用TestNG的例子为零.所以提出该需求变更要求:
① 删除AbstractClinicTests示例,并在“事务管理”或“JUnit支持类”中创建类似的基于JUnit的示例.
② 将“PetClinic Example”的内容重新调整为新的“最佳实践”部分.
③ 创建1个基于测试的示例,类似于新的基于JUnit的示例,以便于比较.
④ 增加与SPR-11397讨论相关的测试内容.
⑤ 在SPR-6132中添加与讨论相关的测试内容.
该需求变更报告页面如图6所示.因为该需求变更与SPR-11397,SPR-6132都有相关性,实现了该需求变更也有益于需求变更SPR-11397,SPR-6132,对于这样的需求变更,我们可以考虑优先实现.
2) 需求变更参考系数分析
对于需求变更参考系数小于0的需求变更,一般意味着其对整个软件的贡献非常有限,却又花销巨大,在对需求变更实现进行决策时往往需要慎重考虑.需求变更参考系数排序后10位如表8所示:
Table 8 Requirements Change References
分析需求变更参考系数排序表最后1个需求变更SPR-5120,SPR-5120的提出时间为2019年8月29日,由Pedro Santo在Spring Framework变更请求追踪系统中提交,标题为Spring component scanning does not work within JBoss EJB container,其报告页面如图7所示.该需求变更是一个Improvement类型的需求变更,当提出者从一个JBoss管理的EJB中创建ApplicationContext时,spring检测功能失效,作者在不同的环境中测试spring组件,只有在JBoss管理的EJB中失效.该需求变更与多个需求变更都存在关联关系,如图8所示.在对需求边更SPR-5120进行处理时,需求同时考虑与其相关联的多个需求变更,需求变更SPR-5120是否偿还其债务值,也会对其他与之关联的需求变更债务值偿还决策产生影响,关联的需求变更越多,受到影响的需求变更也就越多,所以需要对其慎重考虑.
Fig. 6 Requirement change SPR-11397 report page
Fig. 7 Requirement change SPR-5120 report page
Fig. 8 Requirement change SPR-5120 association diagram
我们将需求变更属性和需求变更边际贡献值记录合并以后产生了4 828条可用数据,分析需求变更报告的所有属性,筛选出需求变更的需求变更类型(issue type)、需求变更状态(status)、需求变更的重要性(priority)、需求变更的解决方式(resolution)等类别特征,方便进行处理,部分结果如图9所示.
我们将需求变更边际贡献值分为2类,即贡献能力大、贡献能力小.再以5∶5的比例将4 828条可用记录分别作为训练集和测试集.然后我们对需求变更贡献能力的特征值进行度热编码.主要结果如图10所示.
Fig. 9 Partial screenshots of eigenvalue screening results
Fig. 10 Partial screenshots of one-hot coding results
梯度提升算法(GDBT)需要对一些重要参数进行设置,例如:每一轮的迭代步长v、树的最大深度MathDepth、损失函数L、模型的迭代次数N.每轮的迭代步长v=0.001;损失函数L设为均方差;接下来,在60~1 200的区间内寻找最佳迭代次数,由于平均绝对误差的最大值和最小值仅相差0.005 6,因此选择对应于最小平均绝对误差的迭代次数作为最佳值,即300作为迭代次数;然后调整树的最大深度MathDepth.随着树的最大深度增加,平均绝对误差波动,但平均绝对误差最大值和最小值之间的差值仅为0.013 15,因此基于均方根误差选择最佳MathDepth,均方根误差最小值0.172 8对应于树深度为9.
Spring Framework项目使用该预测模型的曲线下面积AUC结果如图11所示.本文提供了预测需求变更边际贡献能力的框架,根据得到的AUC=0.754 6,表明需求变更边际贡献能力被正确预测的数目大于被错误预测的数目的概率为75%及以上.另外,得到如表8的混淆矩阵表示的实验结果.
Fig. 11 Area under curve
Table 8 Predictive Experimental Results
实验结果表明, Spring Framework项目使用该预测模型的召回率为87%及以上,表明需求变更贡献能力被正确预测为能力大的数目与总的实际为能力大的数目的比值为87%及以上.在构建预测模型时,我们使用这4个预测变量:需求变更的需求变更类型(issue type)、需求变更状态(status)、需求变更的重要性(priority)、需求变更的解决方式(resolution).预测模型计算得到的查全率越高,则表明需求变更贡献能力的预测的准确度也越高.结果表明本文提出的预测方法具有一定的可用性.
Fig. 12 Importance ranking results
最后,我们对预测模型的特征值指标对需求变更贡献能力大小影响做了重要度排序,结果如图12所示.由图12可以看出,Resolution_Complete,Resolution_Duplicate,Resolution_Fixed这3个特征值对需求变更的贡献能力大小影响较大,分别为:0.238,0.225,0.173.解决方式Complete,Duplicate,Fixed分别表示完成、复制、已修复.从含义上看,已经完成、复制和已修复这3种解决方式是已经解决了的需求变更,所以不会带来太大的技术债务,所以贡献重要度排序较高.Issue Type_Improvement和Issue Type_New Feature对应的重要度分别为0.038和0.037.这2个特征值对于需求变更的贡献能力大小也有一定的影响,这2个特征值分别表示需求变更类型为改进和新功能.改进一般指针对当前系统的某个功能进行改进,通常不与其他的需求变更产生很复杂的关联关系,不会带来太大的技术债务.而新功能一般是指为系统增加1个新功能,改进和新功能这2个Issue类型都属于对系统的完善,虽然会产生一定的工作量,但是对于整个系统是有益的,所以能够对需求变更贡献能力大小产生一定影响.因此,在我们衡量需求变更贡献能力时,遇到这些关键特征值时,对需求变更贡献能力可以稍作乐观估计.
本文根据需求变更所产生的2种方式定义了需求变更技术债务,再引进经济学中“边际贡献”的概念,将需求变更跟踪系统中筛选出的10类需求变更之间的关联关系根据边际贡献要素给出关联关系的不同分类,将需求变更中的各种重要参数与边际贡献的各类要素一一对应,以便使用边际贡献分析法分析需求变更并且应用到大型开源项目Spring Framework中,通过实验验证了需求变更边际贡献概念的可用性和技术的可行性.之后,运用GDBT算法对Spring Framework中的需求变更历史记录进行研究,提出了一种需求变更的边际贡献能力分析方法,并且对各个字段取值对其边际贡献影响的重要度进行排序.结果表明,该分析方法可以为需求工程师衡量其工作量和风险提供有价值的结果.
目前,需求变更边际贡献分析方法仅应用于Spring Framework项目,还有很多不同的软件项目没有覆盖.另外,Spring Framework项目采用敏捷开发方法,和传统过程模型相比,可能会有不同.下一步的工作将探索如何将本文提出的方法应用到其他开源软件项目中或一些基于传统过程模型开发的软件项目中,进一步验证量化方法的效果.此外,本文的技术债务研究仅基于时间来进行需求变更技术债务的量化,而技术债务也涉及到项目代码、项目维护等,仅根据时间研究需求变更技术债务不够全面,下一步将尝试融合其他相关可量化指标,对多种技术债务量化方法的融合进行研究.