用于计算机软件分析的方法和装置的制作方法

文档序号:6562327阅读:176来源:国知局
专利名称:用于计算机软件分析的方法和装置的制作方法
技术领域
本发明涉及计算机软件的分析,包括源代码和预编码文件,诸如程序设计,以便估计有关计算机程序的生产、开发和维护的成本。分析也可以指向跟踪特定软件工程的进展,优化劳力对这种任务的配置,以及在某些场合优化软件设计自身。本发明涉及分析计算机程序或其一部分的方法和装置,还涉及包括计算机可读介质的计算机程序产品,在该介质上记录有为执行这种分析的计算机程序。
背景技术
为软件开发、增强、测试等进行精确的成本估计对于销售商在市场中保持赢利是必须的。如Fairly,R在软件工程概念(纽约McGraw书籍公司,1985年版,64页和72-75页)一书中所指出的,软件产品成本的估计是软件工程中最困难和最容易发生错误的任务,特别在计划阶段。
为减轻这一任务,已经提供有某些软件成本估计模型,例如在由Boehm等人在“美国程序员”(1996年,7月,2-17页)中公开的COCOMO2.0软件成本估计模型。COCOMO 2.0包括一族可定制的软件大小估计模型,包括对象点、函数点和源代码行;用于软件重使用和再设计的非线性模型;以及用于相对软件不经济尺度的模型提取的指数驱动方法。即使如此,成本估计(或劳力的估计)依然难于进行,因为某些(或所有)测量和选择定义它们的参数缺乏通用的约定,诸如它们指的是什么和它们怎样测量。例如,两个常用的参数-软件产品中的代码行和函数点数-对个人的人员解释是未定的,这因而可以导致在任何两个个人之间产生变化很大的估计,甚至同一个人在不同时间做出多种估计。当除去专门术语和不着边际的空话时,可用的估计技术有时不比由个人做出的受过训练的猜测更好。
发明概述本发明的目的是通过提供一种测量系统至少部分解决这种情形,该测量系统包括对软件代码复杂性的一种一致而可重复的测量。这通过定义和提供对该测量系统的两个中心概念-决策点和复杂性指数-而实现。
本发明提供一种决定计算机程序复杂性的方法,其中从程序源代码或其它预编码文件,诸如程序设计,决定在该程序中实际或者期望出现的某种预定事项。这些事项专门是指示正在向前的程序流中的中断的事项。这些事项例如是条件语句、循环、存储器分配、子程序调用等,它们中断了代码的线性流和/或思想的线性流,因此在编码时要仔细注意。例如,也许需要检查导致中断的代码部分,看程序流是否像期望的那样编码,函数调用的返回值是否被正确处理,是否避免了存储器漏失等。(代码和思想的)程序流的中断之所以被认为是复杂的,是因为需要暂停并反应正在进行的变化和正被选择的动作过程。
形成对比的是,程序中大而简单的语句块的出现是繁琐的但是并不复杂,因为这样的块可以从开始到结束顺序扫描而不需担心代码行中的逻辑(隐式或显式)流的中断。因此,代码行的数目(或它们是怎样定义的)不再重要。它们增加大小,而不是复杂性。
程序中出现程序流中断的所有事项,无论是显式还是隐式,都称为决策点。
我们遇到的决策点出现的地方,例如有1.条件语句2. 循环语句的头和尾3.子程序/函数调用4.存储器分配/重分配/解除分配5.给分配的存储器冠以别名6.在C++中的Goto、continue、break语句或在其它语言中的等价语句7.在C++中的switch、case、default语句或在其它语言中的等价语句8.在C++中的return语句或在其它语言中的等价语句9.不在返回该指针的函数的参数表中的指针的返回10.在一个循环体内,在迭代内第一次使用后重定义或修改的变量11.在一个表达式或语句内的隐式混合型操作
12.通过用户定义的数据类型在其过载的实现中使用嵌入运算符13.在分母不是常数时的除法运算符14.通信调用15.文件操作16.嵌套操作上面列出最普通遇到的决策点。其它的可以在需要时用手工添加。决策点的总数目告诉我们代码中必须仔细注意的地方的数目。这些是程序中可能强调的点。
在确定决策点后,给每一个决策点分配一个整数值,指示在这里称之为为该点的复杂性指数(CI)。这些值可以相加,以便对整个程序或其一部分提供一个总复杂性指数。另外可选的方案或在这之外,可以分析决策点在整个程序中的分布,例如通过形成一个复杂性指数的直方图,以确定高复杂性群。


为更好理解本发明,以示例方式参考附图,其中图1是一个计算机系统的简化示意图。
发明详述本发明涉及确定一个计算机程序或其一部分的复杂性指数和复杂性剖面图(complexity profile)。本发明涉及为执行这种确定的方法和装置,还涉及包括一个计算机可读介质的计算机程序产品,在该介质上记录有为执行这种决定的计算机程序。
图1表示一个可以实现本发明的计算环境的实施例。
该实施例包括所谓的独立计算机1,亦即一个并非固定连接到网络的计算机,它包括一个监视器2、键盘3、基于中央处理单元的微处理器4、硬磁盘驱动器5和随机存取存储器6,所有都通过一条连接总线7彼此相连。可操作键盘3允许用户连同用户数据输入命令到计算机,诸如检索查询式。除键盘3外,该计算机可以包括一个鼠标或轨迹球(未示出),用于输入用户命令,特别如果是该计算机由一个具有图形用户接口的操作系统控制的话。
为给计算机1输入程序指令,亦即把它们加载到存储器6和/或将其存储在磁盘驱动器5上,以便计算机开始操作,和/或在受到命令时能够操作,按照本发明,计算机1包括CD-ROM驱动器8用以接收CD-ROM9。
程序指令存储在CD-ROM9上,驱动器8从这里读这些指令。然而,熟悉本技术领域的人理解,驱动器8读取的指令可能不能从CD-ROM9直接使用,而是加载到存储器6和存储到硬磁盘驱动器5上,由计算机1从那里使用。另外,指令可能需要使用CD-ROM上或存储器6中的合适的解压缩软件从CD-ROM解压缩,无论那种情况,可能由计算机1以不同于它们在CD-ROM上存储的顺序接收和存储。
在CD-ROM驱动器8之外或代替CD-ROM驱动器8,可以提供任何适合的输入设备,例如软磁盘驱动器或磁带机或无线通信设备,诸如红外接收器(它们都没有表示在图中)。
最后,计算机1还包括一个电话调制解调器10,通过它该计算机可以经由电话线11、位于因特网服务提供商(ISP)场地的调制解调器12、和ISP的计算机13临时连接到因特网。
计算机1不一定是一个独立的环境。反之,它可以和其它计算机形成一个网络(未示出)的一部分,固定地连接在该网络上。它也可以固定地或具有临时链路连接到一个所谓的内联网上,亦即一组类似因特网网站或URL并且以和因特网同样的方式安排但是仅允许特定用户例如一个特定公司的雇员访问的数据保持场地。代替调制解调器10,计算机1可以具有对ISP的计算机13的一个数字硬导线连接,或者计算机1自身可以包括固定连接的因特网网站(URL),不管是否作为对其它远程用户的ISP。换句话说,代替仅可以通过本地键盘3使用的本发明,它可以为通过对作为ISP或者只作为一个因特网网站的计算机1的临时或固定连接的远程用户使用。
被分析的程序可以是通过键盘3已经输入到计算机的软件,也许用了很长时间,并存储在硬磁盘驱动器5或装入驱动器8的另一个CD-ROM上,假定该驱动器和该另外的CD-ROM能够在该CD-ROM上重写数据,或者在前面提到的可选软盘驱动器或磁带机上。计算机程序可以从例如形成上述网络一部分的文件服务器(未示出)获得,或从在因特网或上述内联网内的数据保持网站获得。
为给由于上列预定条件(或者可以加在其上的条件)产生的任何程序流中断(隐式或显式)的复杂性指数(CI)分配一个正整数值,后面会叙述。没有复杂性的具有值0。于是,一个主要包含简单块的非常大的程序具有低复杂性。另一方面,具有许多逻辑运算符、函数调用等的小程序将具有高复杂性。较低复杂性的程序容易理解。全部(或部分)代码的累积复杂性指数是与在其内决策点关联的单个复杂性指数的和。单个指数如下分配。
1.条件语句。一个条件语句或表达式的复杂性指数等于在该语句或表达式的运行时间期间必须被估值的条件的最大数目。如果一个条件可以在编译期间被静态估值,则将其忽略。例如,语句if(j>0&&k<10){…};式中j和k不能静态决定,具有复杂性指数2,因为必须在运行时间期间估值j>0和k<10。另一方面,在语句Cond=TRUE;if(Cond&&k<10){…}其中,该if语句具有复杂性指数1,因为Cond在编译阶段知道为TRUE,因此不需在运行时间期间估值。
2.循环语句的头和尾。如果隐含一个隐式条件估值,则循环语句的头(并非循环体)给定复杂性指数1。例如,在Fortran中,在doj=1,n...
...
...
enddo其中,该头具有循环继续直到j<=n的隐式条件。类似地,循环的尾给定复杂性指数1,因为它有在到达enddo时返回到循环的头部的隐式条件。
语句while(TRUE){…}具有复杂性指数1,因为在尾部(整个程序体的结尾)的隐式继续,但是因为整个头部(条件部分)具有固定值TRUE,因此其复杂性指数将是0。另一方面,语句while(j>0&&k<2){…}具有复杂性指数3,2是因为整个头部(条件部分)具有在运行时间期间要被估值的两个条件,加上为在尾部(while体的结尾)的隐式条件的1。
循环体的复杂性指数就象独立于该循环一样地评估,也就是说,它被接任何其它语句块对待。特别注意,一个循环的复杂性指数不依赖于在运行期间可能出现的循环重复的次数。
3.子程序/函数调用。一个子程序/函数调用可以具有复杂性指数0,如果该调用指向一个可信的子程序/函数,否则它将具有和其它子程序/函数同样的复杂性指数。这样,不管该子程序/函数是否是嵌入的(inline)都没有差别。例如,数学库函数,诸如sin(),cost()可以被考虑为可信函数,因为它们的行为被认为是已知的、可预测的、并在发布前正式形成文件的。另外,在被调用的函数中的每一函数参数可以在调用的一个特定实例中有它们各自的复杂性指数。例如,考虑语句MyUntrustedFunction(arg1,ptr1=ptr2,C=A*B*A);式中arg1是一个整数变量,ptr1和ptr2是同一类型存储器位置的指针,C和B是用户定义的矩阵类的对象,A是一个整数变量。对非可信函数MyUntrus tedFunction()的调用具有复杂性指数例如4。另外,在该特定的例子中,ptr1=ptr2具有复杂性指数1,因为给分配的存储器冠以别名(因为ptr1和ptr2引用的是同样的存储器位置,见下面的5),C=A*B*A具有复杂性指数6,因为操作符*的两次过载实例,操作符=的一次过载实例,对其我们已经假定还不是可信的运算符(见下面的第12项),和隐式混合型运算的3次实例(在该语句中的运算符=,*,具有混合类型语句中的*,见下面的第11项)。因此,该完整的语句具有复杂性指数4+1+6=11。
4.存储器分配/重分配/解除分配。这些操作的每一实例给定复杂性指数1。
5.给分配的存储器冠以别名。每一实例给定复杂性指数1。
6.Goto,continue,break语句。给每一关键词Goto,continue,break(或它们的等价词)复杂性指数1。
7.Switch,case,default语句。给每一关键词switch,case,default(或它们的等价词)复杂性指数1。
8.Return语句。给关键词return(或其等价词)的每一实例复杂性指数1,除去它是子程序/函数的最后一个语句,在该种场合,它的复杂性指数为0。如果子程序/函数的最后一个语句不是return,则这一条件具有复杂性指数1。
9.不在函数的参数表内的指针的返回。在return语句中的这种指针具有复杂性指数1。
10.在一个循环体内,在迭代内第一次使用后重定义或被修改的变量具有等于这种重定义或修改次数的复杂性指数。
11.在一个表达式或语句中的隐式混合型运算。在一个表达式或语句内每出现一次则具有复杂性指数1。考虑语句C=A*B*A;式中C和B是用户定义的矩阵类的对象,A是一个整数变量。这里,表达式A*B*A具有出现两次的运算符*,并且在每一场合它们各自的操作数具有不同类型。因此,这些对该表达式提供复杂性指数2。如果另外操作符*还是一个不可信过载操作符的话(见下面12),则该表达式的最后结果的数据类型有可能值得怀疑,因此操作符=也可能以不同类型的操作数结束。我们总是在悲观的一侧犯错误,于是这将提供另外的复杂性指数1。因此该语句的总复杂性指数为2+1=3。
12.通过用户定义的数据类型在其过载的实现中使用嵌入操作数。每当一个操作符符号用于表示多于一个的操作时,则该操作符称为过载。这最通常发生在当不同的数据类型共享同样的操作符符号时。例如,符号’+’(加操作)用于多种数据类型,诸如整数、矢量、矩阵等来指示相加。然而,在每一场合,加操作的细节不同。在布尔代数中,加操作符有时用于指示逻辑变量之间的’OR’操作。编译程序通过检查在该操作中涉及的操作数决定是哪一种操作。一组操作符符号,诸如’+’,‘-‘,‘*’,‘/’等,它们由程序语言保留用来预定义一定数据类型的操作,称为嵌入操作符。
在一个表达式或语句中的每一这种操作符的出现必须作为子程序/函数调用测试并相应决定其复杂性指数。考虑语句C=A*B*A;式中C和B是用户定义的矩阵类的对象,A是一个整数变量。这里,表达式A*B*A使用嵌入操作符*两次,并且在每一场合该操作符由矩阵类过载。类似地,嵌入操作符=也由矩阵类过载。如果过载的操作符是可信函数,则复杂性指数将是0,否则它将为3。
13.在分母不是常数时的除法运算符。在一个表达式中的每一这种出现具有复杂性指数1,因为在运行期间可能出现非故意用零除的情况。
14.通信调用。在并行程序中,每一通信函数调用(诸如MPI函数调用)具有复杂性指数1,因为它们都有可能中断程序流控制。注意这里的例外通信功能通常被视为可信的,因此期望具有复杂性指数0。然而,这里优先考虑的是可能中断在执行程序的一个或者多个处理器中的程序流的控制。
15.文件操作。对文件操作的每一调用(open,close,write,seek,等)具有复杂性指数1。
16.嵌套操作。嵌套自身不引入复杂性。然而,深层嵌套可以引起复杂性!如果内层嵌套的操作被视为好像在实际中它们都是对某个假设的函数的调用,而这些函数被分别编程,于是很清楚嵌套不增加复杂性。进到最内层嵌套并从那里展开对处理嵌套是有帮助的。因为复杂性基本上是感觉到的,因此形成代码使得嵌套的级通过检查变得明显是有帮助的。可以使用自动文本格式工具实现这一点。
我们将把复杂性指数在一段代码上的分布称为其复杂性剖面图。人们可以以多种方式表示该剖面图。一种这样的表示将是一个直方图,这里水平轴具有代码的行(其打印在纸上或者在屏幕上显示),而竖直轴是复杂性指数。完全空白的行或注释行不作为代码行计数。行内至少必须有一个字符,即使它只是一个括号,只要打印或显示代码的式样后面能一致。只要是遵守书写和格式化程序的一致的式样,则复杂性剖面图将容易地表示一种分布的最感兴趣的特征,诸如群集(cluster)。剖面图的形成基本上是在一个程序内决策形成点的序列和结构的分析。
复杂性剖面图具有某些明显的应用。例如,每当复杂性指数群集很重,则可能值得(重)编码这些部分为单独的函数。这将使代码开发、测试和维护容易。显然,这种函数应该由最好的程序员编写。另一个重要的应用是使高技能的程序员编写具有高密度复杂性指数的代码部分而使新程序员编写具有低密度复杂性指数的代码部分,使编码人员匹配编码分配。
新代码开发可以在总复杂性指数估计和从设计建立复杂性剖面图后开始。这应该由有经验的高级程序员进行。估计过程将给出在代码开发期间复杂性指数期望很高的那些设计部分清楚的指示。这种部分应该委托有经验的程序员编码。此外,下面将会指出,可以通过测量其当前的复杂性指数并将其例如与估计的基准复杂性指数和/或验收复杂性指数比较来监控项目进程。新指数在下面定义。
在编写程序代码(coding)开始前,从设计计算基于估计的复杂性指数。它可以被视为是为建立程序所需要的开发努力一个期望的测量。验收复杂性指数从下式计算验收CI=基于估计的CI-交付时期望可信赖的程序部分的CIs随着编写程序代码的进行,可以计算产生的程序的当前复杂性指数(使用在计算估计的基准CI中使用的同样的可信度考虑)并作为百分比与估计的基准CI比较。这将提供项目进展的一个好的测量。在项目结束时通过比较估计的复杂性剖面图与实际复杂性剖面图也将指示原来的估计多好或多坏和在设计中对其贡献的位置。在估计和实际实现之间的严重不匹配指示估计未正确进行(可能不完全),或在估计进行后设计有大的修改。因此复杂性指数是程序开发中诊断、故障查找和测量的一个有力工具。
另一方面,在测试进行时,将发现或使新程序的部分成为可信部分。在任何给定时间,对这种可信的部分,我们可以在想象上设定它们各自的CI为0并计算一个复杂性指数。可以使用该指数与验收CI接近程度作为与交付CI的接近程度的测量。可以直觉地看到,该指数是对交付接近度的高级指标,高于在软件工业中使用的那些指标,例如覆盖度。
为了代码维护和测试,我们从编译无错误的代码开始。还假定所有与考虑和选择有关的算法和领域的知识在从事编码前已经在详细设计阶段掌握。如果检测到设计的模糊性和/或错误,则应该将它们向设计者报告。永远不能允许编码人员做出临时决策或者第二猜测或者代替领域专家改正模糊性和错误。编码人员的任务只是准确地映射设计为代码。
在维护和测试时,最重要的信息也许是复杂性剖面图。例如,当发现一个错误且其位于CI密度高的程序部分以及该错误的解决方案并不明显,则应该使一个有经验的程序员检查该错误。在CI密度稀少的地方的代码区域中,代码容易理解。确实因为这一点,在这样的区域中,人们必须防止自满而要仔细检查代码逻辑。
对于项目工作量估计,一旦计算出复杂性指数,则可以通过经验因子加权来考虑从事编写代码、维护和/或测试任务的人的经验。个人可以通过不时取一个简单的测试确定他/她的加权因子基准。对于维护和测试任务,可以取一个具有复杂性指数例如200-250的不熟悉的和未注释的程序或函数并决定例如通过画其流程图理解它需要的总时间(包括休息期间,当人们故意试图不思考该问题时)。对于编码任务,取具有估计的复杂性指数200-250的设计文件并决定书写为它的代码需要的总时间(包括休息期间,非正式测试等)。用复杂性指数除总时间(以小时测量的)得到加权因子。
在给客户提交项目建议前,每一个为该项目的预期的程序员可以决定他/她的加权因子,而为该项目的总(智能)工作量W然后可以从下式估计W=P∑Ni=1Wipi,式中N是程序员的总数,P是总复杂性指数,Wi是第i个程序员的加权因子,pi是第i个程序员将处理的总复杂性指数P的百分比。
通过假定特定数目的工作小时/周为可分配给每个程序员的工作量,可以计算由指定组的程序员完成项目的时间。这去掉了进行大规模调查以导出程序员生产率的工业平均的需要,和处理需要考虑可分配的程序员的生产率的现实。
对于尚需书写的代码,可以从设计估计决策点及其各自的复杂性指数,并由此进行工作量和人员的估计。
在项目执行期间,通常期望改进个人的wi。因此可以期望保存在项目开始时采用的wi的基础上所做的估计。
因为个人的wi基于他/她处理未知的和未注释的代码的能力,这种代码相当复杂,或者基于个人从设计产生的代码,因此工作量的估计要比当前使用的方法可靠的多。
复杂性指数计算的例子选择了两个用C书写的函数,LU_Decom()和LU_Bksub()[摘自Press,WH等人所著《C语言数值方法》,剑桥大学出版社,1992年第二版,44-48页],来说明决策点和复杂性指数的思想。这些代码实现广泛使用的矩阵算法,LU分解,用于解联立线性代数方程。这些函数很小,可通过观察验证其正确性,因此可以被认为是可信的函数。然而,为说明复杂性指数计算方法,我们将假定它们是不可信的!在这两个函数中,已经用下划线标出决策点。凡在可应用的地方,用“//[impli.cont.]”指示循环中的隐式尾部条件。由这两个函数调用的函数NoMemory(),fabs(),和_Fatal()假定为可信函数。
例1<pre listing-type="program-listing"><![CDATA[  double*LU_Decom(double*a,intn,int*idx,double*d)   {   inti,iMax,j,k;   double big,dummy,sum,temp;   double*vv;  vv=new double[n];   if(!vv)NoMemory ();   *d=1.0;   for(i=0;i<n;i++){    big=0.0;    for(j=0;j<n;j++)if((temp=fabs(a[i*n+i]))>big)    big=temp;//[impl.cont.]    if(big==0.0)return NULL;//Ifmatrix is singular.    vv[i]=1.0/big    //[impl.cont.]  }  for(j=0;.i<n;j++){    for(i=0;i<i;i++){    sum=a[i*n+j];    for(k=0;k<i;k++)sum-=a[i*n+k]*a[k*n+j];// [impl.cont.]    a[i*n+j]=sum;    //[impl.cont.]}  big=0.0;  for(i=j;<n;i++){    sum=a[i*n+j];    for(k=0;k<j;k++)sum-=a[i*n+k]*a[k*n+j];∥[impl.cont.]    a[i*n+j]=sum;    if((dummy=vv[i]*fabs(sum))>=big) {    big=dummy;    iMax=i;    }    //[impl.cont.]    }  if(j!=iMax) {    for(k=0;k<n;k++) {    dummy=a[iMax*n+k];    a[iMax*n+k]=a[j*n+k];    a[j*n+k]=dummy;    //[impl.cont.]  }  *d=-(*d);  vv[iMax]=vv[j];  }  idx[j]=iMax  if(a[j*n+j]==0.0_Fatal(“Matrix is singular”,“”);  if(j!=n-1){    dummy=1.0/(a[j*n+j);    for(i=j+1;i<n;i++)[i*n+j]*=dummy;//[impl.cont.]    }  }  delete[]vv;  return a;}//[CI=39]]]></pre>该例中的复杂性指数是39。
例2<pre listing-type="program-listing"><![CDATA[  double*LU_Bksub(double*a,intn,int*idx,doubleb[])   {    inti,ii=-1,ip,j;   double sum;   for(i=0;i<n;i++){    ip=idx[i];    sum=b[ip];    b[ip]=b[i];    if(ii+1)for(j=ii;j<i;j++)          sum-=a[i*n+j]*b[j];//[impl.cont]    else if(sum)ii=i;    b[i]=sum;    ∥[imp.cont.]    }    for(i=n-1;i>0;i--){      sum=b[i];      for(j=i+1;j<n;j++)sum-=a[i*n+j]*b[j];//[impl.cont.]      b[j]=sum/a[i*n+i];       ∥[impl.cont.]  }  return b;  }//[CI=16]]]></pre>该例中的复杂性指数是16。
在上面的两个例子中,字符的每一个连续下划线组表示一个决策点。根据第3节第10项在循环体内重定义的变量用斜体和下划线表示。在上面的代码中,每一决策点具有复杂性指数1。不一定需要是这样。例如,在LU_Decom()中的语句if((dummy=vv[i]*fabs(sum))>=big)…其中,如果fabs()是一个不可信函数的话,则复杂性指数将更高。注意,用视觉检查代码中的下划线部分为每一个函数LU_Decom()和LU_Bksub()提供一个对复杂性剖面图的极好的感觉。然而,表示复杂性剖面图更正式的方式例如应该准备一个直方图。
对于具有(或者在它们建立期间开发)高密度复杂性指数的代码段由有经验的程序员检查和/或与设计者讨论以发现扩散和减弱复杂性指数群的语义上正确的方法也许是有用的,例如通过中断该群的全部或部分进入一个或者多个函数,并使它们分别开发。另外,可以请最好的编程人员开发当前不可信且对该群的密度贡献很大的函数到可信的函数中。测量一个代码的复杂性指数和它在任何时刻的复杂性的能力提供了解项目位于何处和控制其进程的工具。最重要的是复杂性指数群提供识别在开发、测试和维护期间需要专家帮助的代码区域的一种可靠工具。
本发明的上述实施例不需定义代码行、功能点、对象点等,因为它不依赖于它们。可以在程序开发的任何阶段计算和估计复杂性指数,因此它可以用来测量和控制程序在其开发期间的进程。同时,代码的大小不是决定程序复杂性、为建立、维护或测试该程序所需要的工作量等的参数,领域知识也不是因子。这并不奇怪,因为编程是数学活动,这里的事情是公理、符号系统和操作规则。在这种系统中当必须进行选择时产生复杂性,以及处理符号系统需要的专业培训的水平。因此,某些专业人员可以产生比从同样的设计而由其它人开发的较不复杂的系统。然而,给定一组关于如何从一个给定程序计算复杂性指数的明显的规则,则他们都应该从正被建立指数的程序得出同样的复杂性指数。领域知识在划分(framing)、解释需求和在设计中是至关重要的。设计向代码的映射原则上说应该独立于领域知识,并且在将来希望这种映射能自动进行。
对于一个要被开发的程序,可以从其相应设计合理地估计其决策点。这里,不同的专业人员对该程序可能得出不同的估计,但是它们应该能够同意在该设计中的决策点的数目。不同的估计基本上指示不同的专业人员根据它们的经验如何计划将一个设计对应成代码,而不是一个高于另一个。例如,一个高复杂性指数可能相当好地指示许多决策能力被塞进少数代码行中和新的(可能是非常有效的)数据类型或类将被开发,因此其方法开始时是不可信的。
叙述了在代码开发、测试、和维护中导致复杂性的核心事项,亦即在代码或设计中的决策点的数目,在这些地方要进行某些形式的显式或隐式的决定,这些决定需要仔细审查。例如,如果已经分配存储器,我们需要确认它实际上被分配,和在以后,它是否被恰当分配,是否别名留下来悬空,等等。
不依赖于使用从第三方来源的经验数据,而是在项目内关于、对于或由将实际工作在该项目上的或将连续工作在该项目上的人员产生这种数据。这种数据可以被容易地修改和很短的提前通知时间。
如果使用可重用的可信函数,则复杂性指数自动减少。人们不需单独考虑它。不可信可重用函数不减少复杂性。然而,它们常常提供在程序开发中迅速进展的错误感觉,仅在以后在测试和维护期间坚持出现问题面。
虽然本发明根据一个优选实施例说明,但是不打算限制本发明到该实施例。在本发明的精神之内的修改对于熟悉本技术领域的人十分明显。本发明的范围只由下面的权利要求定义。
权利要求
1.一种决定计算机程序复杂性的方法,该方法包括步骤i)审查程序,识别其内预先定义的程序事项的出现,该程序事项作为该程序向前的程序流中的中断的指示;ii)为每一这种事项,分配和记录一个对该事项预先确定的数值值;和iii)将分配的数值值相加来定义一个指示程序复杂性的复杂性指数。
2.根据权利要求1的方法,其中,所述预先确定的程序事项包括条件程序语句;循环语句的头和尾;对子程序或函数的调用;存储器分配、重分配、解除分配操作;给分配的存储器冠以别名;包含关键词Goto,continue,break,switch,case,default和return或等价关键词的语句;由函数返回的不在该函数的参数表中的指针;一个循环体内的变量,如果在循环迭代内第一次使用后重定义或修改过该变量;在一个语句或表达式内的隐式混合型操作;使用非常数分母的除法运算符;通过施加到用户定义的数据类型而过载的嵌入操作符;通信和文件调用,和嵌套操作。
3.根据权利要求1的方法,包括从所述数值值形成直方图以定义该程序一个复杂性剖面图的步骤。
4.根据权利要求1的方法,包括对形式为设计文件的所述程序执行所述步骤(i)和(ii)以形成第一组所述数值值,和对部分编码的所述程序再次执行步骤(i)和(ii)以形成第二组所述数值值;比较第一和第二组数值值决定编写代码的进程。
5.一种决定计算机程序复杂性的方法,该方法包括加载该程序到计算机中并使计算机执行步骤(i)审查该程序,识别其内预先定义的程序事项的出现,该程序事项作为该程序向前的程序流中的中断的指示;(ii)为每一这种事项,分配和记录一个对该事项预先确定的数值值;和(iii)将分配的数值值相加来定义一个指示程序复杂性的复杂性指数。
6.根据权利要求5的方法,包括使计算机识别在程序内的下述事项中的一个,亦即(i)条件程序语句;(ii)循环语句的头和尾;(iii)子程序或函数调用;(iv)任何产生对存储器分配、重分配、解除分配的操作;(v)给存储器冠以别名;(vi)关键词Goto,continue,break,switch,case,default和return或任何等价关键词的实例;(vii)由函数返回的不在该函数的参数表中的指针;(viii)一个循环体内的变量,如果在循环迭代内第一次使用后重定义或修改过该变量;(ix)隐式混合数据类型操作;(x)过载运算符;(xi)具有非常数分母的除法运算符;(xii)通信和文件访问调用;和(xiii)嵌套操作。
7.根据权利要求5的方法,包括使计算机显示一个指示遍及所述程序的所述数值值分布的直方图。
8.一种用于分析计算机软件的方法,该方法包括识别指示在执行该软件的向前的连续程序流中的中断的预定事项在软件中的出现,和指示所述事项在该软件内的分布。
9.在一个计算机中,一种分析加载到该计算机的软件的方法,该方法包括自动检查该软件以识别其内作为当执行该软件时在其向前的程序流中的中断的指示的软件语句。
10.一种计算机软件编辑器,可操作该编辑器以识别和指示正由该编辑器读取的软件内的预定事项在该软件内的出现,这些预定事项是在该软件的运行时间操作的行进流中的中断的指示。
全文摘要
一种分析软件的方法和系统,用以估计计算机应用的生产、开发和维护的成本。不像先前为这种分析的建议,它们主要的测量参数是代码行和函数点的数目,本发明的方法识别执行该程序中从特定间断产生的高复杂性软件段,亦即程序必须事实上进行决策的点。给这些事项分配复杂性指数,这些复杂性指数可以相加以给出该程序一个总复杂性值,或者这些指数可以作为表示该程序复杂性分布的直方图显示。
文档编号G06F11/36GK1339743SQ0112576
公开日2002年3月13日 申请日期2001年8月22日 优先权日2000年8月23日
发明者R·K·贝拉 申请人:国际商业机器公司
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1