软件质量经济学
上QQ阅读APP看书,第一时间看更新

2.3.6 编码缺陷的专门案例

截至2011年,至少存在2500种编程语言。其中约1000种已经“死亡”,不再使用。另外1000种有其专门用途,不会在普通软件里出现。但是大约有500种编程语言被用在软件应用程序中。

很久以来,语言的定义中就有“级别”的概念。语言的“级别”概念一般是指,和低级语言相比,高级语言能够以更少的代码语句实现更多的功能。

20世纪70年代早期,IBM决定量化语言的级别,以便评估其相对性能。最初量化语言级别的方法是从基础的汇编语言开始的,将其定义为“1级语言”,即最低级的编程语言。(机器语言更为低级,但通常意义上它不算编程语言。)

其他语言是相对于汇编语言来定义的,使用的公式是计算需要多少条汇编语句来完成高级语言的一条语句的功能。例如,经过分析后COBOL被确定为“3级语言”。该定义的含义是,执行单条COBOL语句所完成的功能,基础汇编语言需要3条语句。如果你编写的应用程序需要1000条COBOL语句,那会需要大约3000条基础汇编语句。

1975年,IBM在首次开发功能点度量时,作为校验过程的一部分,度量了数百个应用程序和几十种编程语言的功能点总数和代码量。结果,语言级别的概念被扩展,既包含相对于基础汇编语言的代码语句,也包含了实现一个功能点通常所需的语句数目。

当把语言级别的思想作为量化的基础时,就有可能创建一个表格来展示数百种语言的级别了。到2011年,超过1000种编程语言的逻辑源代码语句和IFPUG功能点度量间的转换表可以从许多地方获得。

David Consulting Group、Gartner Group(高德纳咨询公司)和Software Productivity Research(SPR)等公司都会发布和销售这类表格。因为新的编程语言以每月大于一个的速度不断出现,所以这些表格需要不断地更新。

20世纪80年代早期,数百种编程语言的逻辑代码语句和功能点度量方法间的转换被进行了度量。逻辑代码语句和功能点度量之间的数学转换被称为backfiring。大概从1984年开始,在量化那些只有代码而没有需求和规格说明书的古老的遗留应用程序的功能点总和方面,backfiring成为使用得最为广泛的方法。backfiring很流行但却不是非常准确,因为个人编程风格多种多样。

backfiring以每个功能点的代码语句的平均值为基础。但是单个程序员能够在这些平均值上下变动至少1~2条。

大约从2008年起,更复杂的方法产生了。CAST软件公司、Relativity Technologies等几家公司开发出了自动化解析工具,这些工具能从源代码中提取出业务逻辑并使用真实的IFPUG计数规则综合得出功能点总数。换句话说,这些自动化工具挖掘遗留代码并创建综合规格说明书以用于功能点分析。

数千种编程语言的功能点和逻辑代码语句间的转换超出了本书的范围。为了说明涉及的相当简单的算法,表2-9展示了20种不同编程语言的语言级别的例子。

尽管表2-9把语言级别视为常量,但是这些级别会由于新的语言特性或者名字相同但语法不同的语言变种而变动。这些级别也会因为程序员个人的编程风格的不同而变动。用户较多的语言(如Java)的语言级别往往会有最大的级别范围。

表2-9也是基于“逻辑源代码语句”的。使用逻辑代码语句来为源代码计数的结果不同于直接数物理代码行的结果。很多编程语言允许多个指令写在同一物理行中。下面的例子含有5条逻辑代码语句,但只有一个物理行:

指令1:指令2:指令3:指令4:指令5

与之相反,有些编程语言允许将一个逻辑语句分割到多个物理行。下面的例子展示了只有1条逻辑语句但有6个物理行的代码:

If A equals value N then
Branch to routine X1 if N = 1
Branch to routine X2 if N = 2
Branch to routine X3 if N = 3
Branch to routine X4 if N = 4
Otherwise branch to routine X5

当所有常见的编程语言都被考虑进来的时候,基于物理行计数的代码规模上的巨大差异能相差一个数量级。

考虑到代码计数的困难,不少语言(如Visual Basic)能在根本不使用源代码行的情况下生成可执行代码。这类语言从按钮、下拉菜单和其他可视化技术中生成代码,这些可视化技术可以使用语言提供的预编译功能。

令人惊讶的是,“软件工程”领域在50多年里一直使用这种有着巨大变化范围的度量方法,而没有产生有效的计数标准。

有很多工具可用来计算物理行数,但其中一些工具包含了段落、注释、标题以及真正的源代码语句间的空行。

毫无疑问,基于物理行计数的backfiring和基于逻辑语句计数的backfiring也会产生非常不同的结果。遗憾的是,代码计数方法从未被标准化过。

主要软件杂志(如IEEE Software、The IBM Systems Journal等)的某位作者调查发现,大约1/3的文章在引用代码量时使用了逻辑语句,1/3使用代码的物理行数,剩余的1/3未作说明。

还有一个复杂的因素是,大多数软件应用程序至少同时使用两种编程语言,有些可能使用多达15种不同的语言。例如,COBOL和SQL在20世纪80年代是常见的语言组合,而目前常见的是Java和HTML。

当IBM大约在1975年开发出backfiring算法时,计数是基于逻辑代码语句的。这是因为程序员往往以逻辑代码语句来思考,而不是物理行。因此,逻辑代码计数在估算程序员的脑力劳动量方面提供了更好的近似数据。

在应用程序中,源代码计数的这些不同方法,加上数以千计的编程语言和几乎无以计数的语言组合,使预测和度量编码bug或缺陷变得更加复杂。

为了说明确定源代码规模的某些复杂性,表2-10给出了两种常见语言的例子:C和Visual Basic。表2-10起初假定用两种语言各自生成1000条逻辑语句。可以看到,这个1000条逻辑代码语句的常量所生成的物理行数以及功能点相差甚远。

表2-10说明语言级别和代码计数规则的差别让获取有用的应用程序规模数据变得有多么棘手。

现在我们考虑一下在涉及语言级别和代码计数级别的差别时,如何处理潜在缺陷。表2-11起初假定表2-10中的C和Visual Basic示例都有10个缺陷。

然而,在表2-11中编码缺陷是以"KLOC"来描述的。这个术语中,"K"是1000的缩写,而"LOC"是lines of code(代码行数)的缩写。因此,1KLOC就是1000行代码。(注意:电气工程里使用K来表示值1028,但是软件工程中使用K表示1000。)

如表2-11所示,同样的10个缺陷,按照代码计数规则和功能点标准化之后,结果截然不同。

迄今为止,缺陷值是一个常量。但实际上,低级语言(如基础汇编语言、C和宏汇编语言)通常比高级语言(如Java、Perl和Ruby等)含有更多的编码bug。表2-12给出了从1级(基础汇编语言)到20级语言中大致的潜在编码缺陷范围,从中可以看到一些程序生成器和面向对象语言。

注意,对大多数的语言级别而言,同一级别可能会有多达50种不同的语言。截至2011年,已知的编程语言总数达到2500种。因此,表2-12使用语言级别作为抽象的值,而不是试图比较数千种不同的语言。

表2-12显示了“潜在编码缺陷”(或者叫做原始代码中可能的编码缺陷个数)。但是随着这些缺陷被发现并尝试修复,必须认识到不良修复或新缺陷会不小心在缺陷修复中引入。较老的低级编程语言往往比现代的高级语言有更高的不良修复注入率。

正如所见,潜在编码缺陷会随语言级别而变化。编码缺陷也会随着个人编程技能、语言精通程度以及认证过的可重用代码量而变化。

由于缺乏会使用什么语言以及编程团队能力的相关信息,预测编码缺陷级别时使用平均值,大约为每KLOC(逻辑代码语句)有22个缺陷,或者每个功能点有1.75个缺陷。

如果你恰好使用了物理行而不是逻辑语句来统计代码的话,你得知道你所使用的语言的实际语法才行。同时还得知道代码行统计工具除了计算真正的代码外是否也计算了空行和注释。一个普遍的原则是,代码的物理行数由于太多变,在统计编码缺陷的有效潜在缺陷时不可靠。