对代码指标的迷恋是什么?[关闭]


83

最近,我在SO上看到了许多与“代码指标”相关的问题,不得不怀疑是什么?以下是一些最近的示例:

在我看来,没有一种指标可以代替代码审查,但是:

  • 有些指标有时可能表明需要检查的地方,并且
  • 短时间内指标的根本变化可能表明需要检查的地方

但是我无法想到一个单一的度量标准本身总是表示“好”或“不好”的代码-总是存在一些异常和原因,导致测量无法看到。

从我忽略的代码指标中可以获得一些神奇的见解吗?懒惰的程序员/经理是否在找借口不读代码?人们是否拥有庞大的旧代码库并正在寻找起点?这是怎么回事?

注意:我已经在特定主题中的回答和评论中问了一些这样的问题,但没有得到任何答复,所以我认为我应该向整个社区询问,因为也许我遗漏了一些东西。最好运行一个指标批处理作业,而不必再次阅读其他人的代码(或者我自己的代码),我只是认为这不切实际!

编辑:我对所讨论的大多数指标(如果不是全部指标)都很熟悉,我只是没有孤立地看到它们的观点或将其视为质量的任意标准。


2
我的C#代码度量标准是the number of StyleCop warnings + 10 * the number of FxCop warnings + 2 to the power of the number of disabled warning types。只有在该度量的值尽可能小之后,一个人才有必要开始审查该代码(我认为)。总之:复杂的工具而不是简单的公式可以帮助提高代码质量。虽然这可能是题外话。
Hamish Grubijan 2010年

@Alfred-I just don't see the point of them in isolation or as arbitrary standards of quality.谁会想到孤立地使用度量或将其作为质量的任意标准?
luis.espinal,2011年

@luis是我的编辑,基于引发该问题的几个问题-答案是“管理”,主要是
Steven A. Lowe

+1是有用的项目符号列表,我认为这正是您所描述的
悲惨的变量

Answers:


85

正如他们所说,这个线程中的答案有点奇怪:

  • “团队”,就像这些指标中的“唯一受益者”一样;
  • “指标”,就像它们本身意味着什么一样。

1 /指标不是针对一个人口,而是针对三个人口:

  • 开发人员:他们关心有关对其代码进行静态分析的瞬时 静态代码指标(循环复杂度,注释质量,行数,...)
  • 项目负责人:他们关注来自单元测试,代码覆盖率,持续集成测试的每日 实时代码指标
  • 商业发起人(他们总是被人遗忘,但他们是利益相关者,是为开发付费的人):他们关心有关架构设计,安全性,依赖关系,...等方面的每周 全球代码指标

当然,所有这三个指标都可以监视和分析所有这些指标,但是每种指标的设计目的都是让每个特定的群体更好地使用它们。

2 /指标本身代表代码的快照,这意味着...没什么!

那些指标的组合以及那些不同分析级别的组合可能表示“好”或“坏”代码,但更重要的是,这些指标的趋势很重要。

那就是这些度量的重复将带来真正的附加值,因为它们将帮助业务经理/项目负责人/开发人员在不同的可能代码修复中确定优先级。


换句话说,您对“指标迷恋”的问题可能是指以下两者之间的区别:

  • “美丽”的代码(尽管在旁观者代码中始终如此)
  • “好的”代码(有效并且可以证明其有效)

因此,例如,一个复杂度为9的函数可以定义为“美丽”,而不是复杂度为42的一个长卷积函数。

但是,如果:

  • 后一个函数具有稳定的复杂度,加上95%的代码覆盖率,
  • 而前者有增加的复杂性,联合... 0%的覆盖率,

有人可能会争辩:

  • 后者代表一个“好的”代码(它可以正常工作,很稳定,如果需要更改,可以在修改后检查它是否仍然可以工作),
  • 前者是一个“不好的”代码(它仍然需要添加一些情况和条件以覆盖其所有工作,并且没有简单的方法进行回归测试)

因此,总结一下:

单个指标本身始终表示[...]

:不多,除了代码可能更“美丽”,这本身并不意味着很多...

从我忽略的代码指标中可以获得一些神奇的见解吗?

只有指标的组合趋势才能为您提供真正的“魔术洞察力”。


5
“漂亮”的代码很容易维护-如果是这样,那将具有很大的价值!
理查德·T

21

一个月前,我有一个项目以一个人的工作完成,该项目的测量复杂度很高。那是我第一次接触这类指标。

我得到的第一份报告令人震惊。我的几乎所有功能都未能通过测试,即使是(imho)非常简单的功能也没有通过测试。我通过将逻辑子任务移到子例程中来解决了复杂性,即使它们仅被调用过一次。

对于例程的另一半,我以程序员的自豪感为出发点,我试图以一种相同的方式重写它们,只是更简单,更易读。那行得通,我可以最大程度地降低客户的yclomatic复杂度阈值。

最后,我几乎总是能够提出更好的解决方案和更简洁的代码。性能并没有因此受到影响(请相信我-我对此感到偏执,而且我经常检查编译器输出的反汇编)。

我认为指标是一件好事,如果您将它们用作改进代码的理由/动机。知道何时停止并请求违反公制的补助是无穷的。

指标是指导和帮助,并非本身。


1
非常好,您已经成功地表达了一个非常重要的想法。我目前正在软件指标领域进行研究,我可能会参考。
PeterPerháč10年

5
+1表示“知道何时停止并请求违反公制的奖励是永远的。” 你说得对。坚持教条主义是有害的。
Shabbyrobe

14

我用过的最好的指标是CRAP分数

基本上,这是一种将加权圈复杂度与自动测试覆盖率进行比较的算法。该算法如下所示:CRAP(m) = comp(m)^2 * (1 – cov(m)/100)^3 + comp(m) 其中comp(m)是方法m的圈复杂度,而cov(m)是自动测试提供的测试代码覆盖率。

前面提到的文章的作者(请读下去,这很值得您花时间)建议CRAP最高得分为30,其得分如下:

Method’s Cyclomatic Complexity        % of coverage required to be
                                      below CRAPpy threshold
------------------------------        --------------------------------
0 – 5                                   0%
10                                     42%
15                                     57%
20                                     71%
25                                     80%
30                                    100%
31+                                   No amount of testing will keep methods
                                      this complex out of CRAP territory.

正如您很快看到的那样,该度量标准奖励的是编写不复杂且具有良好测试覆盖率的代码(如果您正在编写单元测试,并且应该这样做,而不是在测量覆盖率...那么,您可能会喜欢随风而散以及)。;-)

对于我的大多数开发团队,我都非常努力地使CRAP得分低于8,但是如果他们有正当的理由证明增加的复杂性是合理的,只要他们用足够的测试来覆盖复杂性即可。(编写复杂的代码总是很难测试的……对该指标有种种隐蔽的好处)。

大多数人发现最初很难编写通过CRAP分数的代码。但是随着时间的流逝,他们编写了更好的代码,问题更少的代码以及调试起来容易得多的代码。在任何度量标准中,这是关注最少,收益最大的度量。


10

对我来说,识别错误代码的最重要的度量标准是循环复杂性。我项目中的几乎所有方法都在CC 10以下,并且在CC超过30的传统方法中总是会发现错误。CC高通常表示:

  • 匆忙编写的代码(即没有时间找到一个优雅的解决方案,不是因为问题需要一个复杂的解决方案)
  • 未经测试的代码(没有人为这种野兽编写测试)
  • 已多次修补和修复的代码(即,充满ifs和todo注释)
  • 重构的主要目标

9

好的代码审查不能替代好的静态分析工具,后者当然不能替代一套好的单元测试,现在,如果没有一套验收测试,那么单元测试就不好了……

代码度量标准是放入工具箱中的另一种工具,它们本身并不是解决方案,它们只是适当使用的工具(当然,盒子中还有其他所有工具!)。


6

人们被机械方式理解和描述代码的想法所吸引。如果为真,请考虑对效率和生产力的影响!

我同意“代码善意”的度量与“好散文”的度量一样明智。但这并不意味着指标是无用的,只是可能被滥用了。

例如,某些指标的极值会指出可能的问题的出路。1000行长的方法可能无法维护。零单元测试代码覆盖率的代码可能具有比经过大量测试的类似代码更多的错误。发行版中添加的不是第三方库的大量代码跳跃可能会引起更多关注。

我认为,如果我们使用指标作为建议-一个危险信号-也许它们会有用。问题是人们开始使用SLOC来衡量SLOC的生产率或质量百分比。


6

我的主观意见是,代码指标表达了无法量化的机构魅力,能够量化某些本质上无法量化的内容。

从某种意义上讲,至少在心理上是有意义的-您如何才能对无法评估或理解的事情做出决定?最终,当然,除非您对主题知识丰富(并且至少与您要评估的内容一样好)或询问知识渊博的人,否则您无法评估质量,这当然只会使问题退回一步。

从这个意义上讲,也许可以用一个合理的类比来通过SAT分数评估大学入学者,这是不公平的,并且错过了每一种细微之处,但是如果您需要量化,则必须做点什么。

并不是说我认为这是一个很好的措施,只是我可以看到它的系统性。而且,正如您所指出的,可能有一些合理的指标(很多500多种线方法,高复杂度-可能是不好的)。我从来没有去过一个买过这个的地方。


6

我相信有一个代码度量标准。

我正在大型系统上工作。当我遇到一个新要求时,我便开始进行编码。完成并解决错误后,我将其检入版本控制系统。该系统进行比较,并计算出我所做的所有更改。

该数字越小越好。


2
考虑到以前的代码是由您自己或另一位具有同等或更高技能的开发人员开发的,因此这是正确的。如果在另一方面,代码是由技能较低的开发人员开发的,则差异中增加的行数(更改的行+新的行+很多已删除的行)实际上可能意味着随着您摆脱代码的改进劣质代码。
阿尔弗雷德·迈尔斯

@阿尔弗雷德:好的。我说的是理想世界,是对许多需求变化的平均值。下面是我在谈论的一个例子,它有一个学习曲线:stackoverflow.com/questions/371898/...
麦克Dunlavey

如果没有比较基准,您怎么知道自己做得很好?
JS

5

指标和自动测试并不意味着可以代替完整的代码审查。

他们只是加快了速度。使用自动检查器,很容易看到忘记遵循的约定,正在使用指定的包和方法等。您可以看到可以解决的问题而无需花费别人的时间。

经理们也喜欢对它们进行度量,因为他们认为自己已经获得了准确的生产率数据(尽管通常情况并非如此),而且他们应该能够更好地与人打交道。


5

测量仅在以下情况下有用:

  • 团队开发了它们
  • 团队同意了
  • 它们被用来识别特定区域

总的来说,任何不适合该指标的指标都会受到团队对其进行优化的影响。您想测量代码行吗?天哪,看看他们能写多少书!您想衡量代码覆盖率,真是太棒了,请看我覆盖该代码!

我认为指标可以用于识别趋势,实际上,我已经看到了一些有用的指标,例如绘制构建中断时的代码,代码搅动(整个项目中更改的代码行数)等。但是,如果团队不提出建议,或者他们不同意或理解他们,那么您很可能会遭受重创。


5

这是stan4j的一些复杂性度量。

蚀类结构分析工具。

我喜欢这个工具和指标。我将指标视为统计数据,指标,警告消息。有时由于某些方法或某些类确实具有某种复杂的逻辑而使它们变得复杂,因此需要做的是留意它们,检查它们以查看是否有必要对其进行重构或仔细地对其进行检查,通常是由于正常情况他们容易出错。由于我喜欢从复杂到简单的学习,因此我也将其用作分析工具来学习源代码。实际上,它包括其他一些指标,例如Robert C. Martin Metrics,Chidamber&Kemerer Metrics,Count Metrics,但我最喜欢这一指标

复杂度指标

圈复杂度指标

循环复杂度(CC)方法 的循环复杂度是该方法的控制流程图中决策点的数量加1。决策点出现在if / for / while语句,case / catch子句和类似的源代码元素中,其中控制流不仅是线性的。单个(源代码)语句引入的(字节代码)决策点的数量可能会有所不同,例如,取决于布尔表达式的复杂性。方法的圈复杂度值越高,测试该方法的控制流程图的所有分支所需的测试用例就越多。

平均环复杂度 度整个应用程序,库,包树或包的所有方法上的Cyclomatic Complexity度量标准的平均值。

脂肪指标 工件的Fat度量是工件的适当依赖图中的边数。依赖图的类型取决于度量变量和所选的工件:

脂肪 应用程序,库或程序包树的Fat度量标准是其子树相关性图的边缘计数。此图包含包树层次结构中所有工件的子级,因此还包括叶包。(要在“合成视图”中查看适当的图形,必须禁用“结构浏览器”的“平面包装”切换。如果所选工件是库,则必须启用“显示库”切换,否则必须将其禁用。)

包的Fat度量是其单元依赖图的边数。此图包含该软件包的所有顶级类。

类的Fat度量是其成员图的边缘计数。该图包含该类的所有字段,方法和成员类。(仅当代码分析是使用“详细级别成员”而非“类”执行的时,此图和“胖”值才可用。)

依赖库 的胖度(胖-库)应用程序的依赖的胖度度量是其库依赖图的边缘计数。该图包含应用程序的所有库。(要在“合成视图”中查看适当的图形,必须启用“结构浏览器”的“显示库”切换。)

扁平包依赖关系的胖度(胖-包) 应用程序的扁平包依赖关系的胖度量是其扁平包依赖关系图的边缘计数。该图包含该应用程序的所有软件包。(要在“合成视图”中查看适当的图形,必须启用“结构浏览器”的“平面包装”切换,并且必须禁用“显示库”切换。)

库的“扁平包装依赖关系的胖度”度量标准是其扁平包装依赖关系图的边缘计数。该图包含该库的所有软件包。(要在“合成”视图中查看适当的图形,必须启用“结构浏览器”的“平面包”和“显示库”切换。)

顶级类依赖关系的胖度(胖-单位) 应用程序或库的顶级类依赖关系的胖度度量是其单元依赖关系图的边缘计数。此图包含应用程序或库的所有顶级类。(对于合理的应用程序,它太大而无法可视化,因此无法在“合成视图”中显示。单位相关性图可能仅显示包。)


2

度量标准可能对确定项目的改进或降级很有用,并且可以肯定会发现样式和约定违规,但是没有替代方法可以进行对等代码审查。没有它们,您可能无法知道代码的质量。

哦,这是假设您的代码审阅中至少有一个参与者有线索。


2

我同意您的观点,即代码指标不应替代代码审查,但我认为它们应补充代码审查。我认为这可以说句老话:“无法改善无法衡量的东西”。代码度量可以为开发团队提供可能需要进一步调查的可量化“代码气味”或模式。大多数静态分析工具中捕获的指标通常是在我们领域的短历史研究过程中确定的具有重要意义的指标。



2

答案的一部分是某些代码指标可以为您快速,初步地解决以下问题:该代码是什么样的?

甚至“代码行”也可以使您了解正在查看的代码库的大小。

如另一个答案所述,指标的趋势可为您提供最多的信息。


2

自己的指标并不是特别有趣。重要的是您如何对待他们。

例如,如果您要测量每行代码中的注释数,那么您认为一个好的值是什么?谁知道?也许更重要的是,每个人都有自己的见解。

现在,如果您收集了足够的信息以能够将每行代码的注释数量与解决错误所需的时间或归因于编码的错误数量相关联,那么您可能会开始找到经验上有用的数字。

在软件中使用度量与在任何其他过程中使用任何其他性能度量之间没有区别-首先进行度量,然后进行分析,然后改善过程。如果您正在做的只是测量,那是在浪费时间。

编辑:回应史蒂文·A·劳的评论-绝对正确。在任何数据分析中,必须小心区分因果关系和单纯的相关性。而且,在适用性的基础上选择指标很重要。尝试测量咖啡消耗并赋予代码质量没有意义(尽管我确定有人尝试过;-))

但是,在找到这种关系(是否为因果关系)之前,必须先获得数据。

选择要收集的数据取决于您希望验证或改进的过程。例如,如果您尝试分析代码检查过程的成功(使用您自己的“成功”定义,是减少错误或减少编码错误,还是缩短周转时间等),则可以选择衡量指标错误总数和已审核代码中的错误率。

因此,在收集数据之前,您必须知道要使用它做什么。如果以度量为手段,那么目的是什么?


我同意,只是您为改进而进行的测量至关重要。如果您想减少制造过程中的缺陷,但您所衡量的只是缺陷数量和休息室中消耗的咖啡量,那么您将
Steven A. Lowe

换句话说,没有建立的相关性可以用作标准;您是否建议使用度量标准和相关性来建立标准?如果是这样,您能证明因果关系吗?还是我们再次测量咖啡的消耗量?
史蒂文·A·劳

2

我认为度量的微小变化没有意义:复杂度为20的函数不一定比复杂度为30的函数更简洁。但是值得运行度量以寻找较大的差异。

一次我调查了十几个项目,其中一个项目的最大复杂度值约为6,000,而其他每个项目的最大复杂度值都在100或以下。那就像棒球棒一样打在我头上。显然,该项目正在进行异常或可能有害的事情。


你看这个项目了吗?指标差异巨大的原因是什么?
史蒂文·劳

复杂性为6K的项目起初写得不好,但是随着它在极端压力下的发展而变得更糟。
约翰D.库克

1

我们是程序员。我们喜欢数字。

另外,您将要做什么,而不是描述代码库的大小,因为“代码量度无关紧要”?

举一个愚蠢的例子,一个150行的代码库和一个1.5亿行的代码库之间肯定存在差异。这不是一个很难得到的数字。


1
有一个区别,一个有更多的代码行。但是那又怎样呢?那没有说明软件的质量...
Steven A. Lowe

2
我知道我会选择下一个;-)
quamrana
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.