代码度量
用 CppDepend 释放代码度量的力量
要学习度量,您可以打印 Placemat可视化专家 由 Stuart Celarier MVP (Corillian) 或者您可以打印此 度量速查表 由 Frank-Leonardo Quednau.
- 8个应用程序度量: NbLinesOfCode, NbLinesOfComment, PercentageComment, NbProjects, NbNamespaces, NbTypes, NbMethods, NbFields
- 14个项目度量:NbLinesOfCode、NbLinesOfComment、PercentageComment、NbNamespaces、NbTypes、NbMethods、NbFields、Assembly level、Afferent coupling (Ca)、Efferent coupling (Ce)、Relational Cohesion(H)、Instability (I)、Abstractness (A)、Distance from main sequence (D)
- 9个命名空间度量:NbLinesOfCode、NbLinesOfComment、PercentageComment、NbTypes、NbMethods、NbFields、Project level、Afferent coupling at namespace level (NamespaceCa)、Efferent coupling at namespace level (NamespaceCe)
- 16个类型度量:NbLinesOfCode、NbLinesOfComment、PercentageComment、NbMethods、NbFields、Type level、Type rank、Afferent coupling at type level (TypeCa)、Efferent coupling at type level (TypeCe)、LCOM、LCOM HS、Cyclomatic Complexity、Size of instance、ABC、NOC、DIT
- 11个方法度量:NbLinesOfCode、NbLinesOfComment、PercentageComment、Method level、Method rank、MethodCa、MethodCe、Cyclomatic Complexity、NbParameters、NbVariables、NbOverloads
- 2个字段度量: 实例大小、FieldCa
- 11 Halstead度量:Total Operators、Total Operands、Distinct Operators、Distinct Operands、Halstead Program Length、Halstead Program Volume、Halstead Program Level、Halstead Program Difficulty、Halstead Programming Effort、Halstead Programming Time、Halstead Intelligent Content
技术债务度量
自2017.1.0版本起,CppDepend提供 智能技术债务估算 代码库的。
基本上,每条 CppDepend 代码规则都会产生问题,对于每个问题,一些可定制的 C# 公式会估算 修复成本 这些问题以人时计。
此修复成本可视为 债务 团队所承担的:只要问题未修复,债务就未偿还,并且会以开发摩擦的形式产生利息。代码库的技术债务是所有这些债务估算的总和。
技术债务可视为 所有代码度量之母.
- 所有其他代码度量——代码行数、复杂度、代码覆盖率、耦合度……——都可以通过带阈值的代码规则来利用。当代码度量阈值被违反时,规则会生成问题。
- 对于每个问题,我们可以估算 修复成本 在 人时.
- 对于每个问题,我们还可以估算 严重性 在 因问题未修复而每年消耗的人工时间 后果。
下面您将找到 CppDepend 支持的每个代码指标的技术细节。技术债务估算有其专门的 文档页面.
代码度量可视化
CppDepend 附带一个仪表板,用于快速可视化所有应用程序指标。该仪表板在 Visual Studio 扩展和报告中均可用。
对于每个指标,仪表板显示自基线以来的差异。它还显示指标值是变好(绿色)还是变差(红色)。
每个值都可以点击以深入查看。例如,点击类型数量将列出代码库中的所有类型。

CppDepend 还通过彩色树状图提供一些特殊的度量可视化。这种可视化对于浏览代码库中方法或类的测试覆盖率特别有用。

应用程序度量
NbLinesOfCode
请注意,类型的 LOC 是其方法 LOC 的总和,命名空间的 LOC 是其类型 LOC 的总和,项目的 LOC 是其命名空间 LOC 的总和,应用程序的 LOC 是其项目 LOC 的总和。
- 抽象方法和枚举的 LOC 等于 0。计算 LOC 时只考虑实际执行的具体代码。
- 命名空间、类型、字段和方法的声明不被视为代码行,因为它们没有对应的序列点。
建议: NbLinesOfCode 高于 20 的方法难以理解和维护。
NbLinesOfComment
针对应用程序、项目、命名空间、类型、方法定义。
建议: 此指标对评估源代码质量没有帮助。我们更倾向于使用以下指标 PercentageComment.
PercentageComment
针对应用程序、项目、命名空间、类型、方法定义。
PercentageComment = 100*NbLinesOfComment / ( NbLinesOfComment + NbLinesOfCode)
建议: 注释比例低于 20% 的代码应该添加更多注释。然而,过度注释的代码(>40%)并不一定是好事,因为它可能被认为是对读者智力的侮辱。
NbProjects
针对应用程序定义 - 项目数量。
NbNamespaces
为应用程序和项目定义。命名空间的数量。匿名命名空间计为一个。如果一个命名空间定义在 N 个项目上,它将计为 N。框架项目中声明的命名空间不计算在内。
NbTypes
为应用程序、项目、命名空间定义。类型的数量。类型可以是抽象类或具体类、结构体或枚举。
NbMethods
为应用程序、项目、命名空间、类型定义。方法的数量。方法可以是抽象方法、虚方法或非虚方法、接口中声明的方法、构造函数、类构造函数、终结器、属性/索引器的 getter 或 setter、事件的添加或移除方法。
建议: NbMethods > 20 的类型可能难以理解和维护,但在某些情况下,NbMethods 值较高可能是合理的。
NbFields
针对应用程序、项目、命名空间、类型定义。字段数量。
建议: NbFields 高于 20 的类型可能难以理解和维护,但在某些情况下,NbFields 值较高可能是合理的。
项目度量
通过衡量应用程序中类型之间的耦合,CppDepend 评估每个项目的稳定性。如果一个项目的类型被许多其他项目的类型使用,则该项目被认为是稳定的(即稳定 = 难以修改)。如果一个项目包含许多抽象类型和很少的具体类型,则被认为是抽象的。 因此,CppDepend 帮助您检测哪些项目可能难以维护(即具体且稳定),哪些项目可能毫无用处(即抽象且不稳定)。
注意: 该理论和指标最早由这本优秀的著作提出 Agile Software Development: Principles, Patterns, and Practices in C# Robert C. Martin (Prentice Hall PTR, 2006)
传入耦合(Ca)
此项目外部依赖于此项目内部类型的类型数量。高传入耦合表明相关项目承担了许多职责。
传出耦合(Ce)
此项目内部依赖于此项目外部类型的类型数量。高传出耦合表明相关项目存在依赖。
关系内聚度(H)
每个类型的内部关系平均数。设 R 为此项目内部的类型关系数(即不连接到项目外部类型的关系)。设 N 为项目内的类型数。H = (R + 1)/ N。公式中额外的 1 可防止 N=1 时 H=0。关系内聚性表示此项目与其所有类型的关系。
建议: 由于项目内的类应该紧密相关,内聚性应该较高。另一方面,过高的值可能表明过度耦合。RelationalCohesion 的良好范围是 1.5 到 4.0。
不稳定性(I)
传出耦合(Ce)与总耦合的比率。I = Ce / (Ce + Ca)。此指标是包对变化的抵抗力的指示器。此指标的范围为 0 到 1,I=0 表示完全稳定的包,I=1 表示完全不稳定的包。
抽象度(A)
内部抽象类型数量与类型总数的比率。此指标的范围为 0 到 1,A=0 表示完全具体的项目,A=1 表示完全抽象的项目。
主序列距离(D)
项目到理想化直线 A + I = 1(称为主序列)的垂直归一化距离。此指标是项目在抽象性和稳定性之间平衡的指示器。范围为 0 到 1,D=0 表示与主序列重合的项目,D=1 表示尽可能远离主序列的项目。
建议: NormDistFromMainSeq 高于 0.7 的项目可能存在问题。
命名空间度量
命名空间级传入耦合(NamespaceCa)
特定命名空间的传入耦合(Afferent Coupling)是直接依赖它的命名空间数量。
命名空间级传出耦合(NamespaceCe)
特定命名空间的传出耦合(Efferent Coupling)是它直接依赖的命名空间数量。请注意,框架项目中声明的命名空间也会被计算在内。
级别
针对项目、命名空间、类型、方法定义。命名空间的 Level 值定义如下:
- Level = 0 : if the namespace doesn't use any other namespace.
- Level = 1 : if the namespace only uses directly namespace defined in tierce projects.
- Level = 1 + (Max Level over namespace it uses directly)
- Level = N/A : if the namespace is involved in a dependency cycle or uses directly or indirectly a namespace involved in a dependency cycle.
建议: 此指标有助于将项目、命名空间、类型和方法客观地分类为高层级、中层级或低层级。此指标还可用于发现应用程序中的依赖循环。
类型度量
类型排名
TypeRank值通过应用计算 Google PageRank 算法应用于类型依赖关系图。应用中心为 0.15 的位似变换,使 TypeRank 的平均值为 1。
建议: TypeRank 较高的类型应该更仔细地测试,因为此类类型中的错误可能会造成更严重的后果。
类型级传入耦合 (TypeCa)
特定类型的传入耦合(Afferent Coupling)是直接依赖它的类型数量。
类型级传出耦合 (TypeCe)
特定类型的传出耦合(Efferent Coupling)是它直接依赖的类型数量。请注意,框架项目中声明的类型也会被计算在内。
建议: TypeCe > 50 的类型是依赖过多其他类型的类型。它们很复杂,承担多个职责。它们是重构的良好候选对象。
方法内聚缺失(LCOM)
单一职责原则指出,一个类不应该有超过一个变更的理由。这样的类被称为高内聚的。较高的 LCOM 值通常表明类的内聚性较差。LCOM 的取值范围为 [0-1]。LCOM HS(HS 代表 Henderson-Sellers)的取值范围为 [0-2]。LCOM HS 值高于 1 应被视为警示信号。
CppDepend使用的算法:
- LCOM = 1 – (sum(MF)/M*F)
- LCOM HS = (M – sum(MF)/F)(M-1)
- 其中:M 是类中的方法数量,F 是类中的实例字段数量,MF 是访问特定实例字段的类方法数量。
建议: LCOM > 0.8 且 NbFields > 10 且 NbMethods > 10 的类型可能存在问题。应避免 LCOMHS > 1.0 且 NbFields > 10 且 NbMethods > 10 的类型。
圈复杂度 (CC)
为类型和方法定义。圈复杂度是一种流行的过程式软件度量,等于过程中可以做出的决策数量。具体来说,在 C++ 中,方法的 CC 为 1 + {方法体中找到的以下表达式的数量}:
计数: if | while | for | case | default | continue | goto | && | || | catch | ternary operator ?: | ??
不计数: else | do | switch | try | using | throw | finally | return | object creation | method call | field access
建议: CC 高于 15 的方法难以理解和维护。CC 高于 30 的方法极其复杂,应拆分为更小的方法(除非它们由工具自动生成)。
实例大小
为实例字段和类型定义。实例字段的实例大小定义为其类型实例的字节大小。静态字段的实例大小等于 0。
类或结构体实例的大小定义为其字段实例大小的总和加上其基类实例的大小。
建议: SizeOfInst 高于 64 的类型可能会降低性能并难以维护。
Association Between Class (ABC)
特定类或结构体的类间关联(Association Between Classes)度量是它在其方法体中直接使用的其他类型成员的数量。
子级数量(NOC)
类的子类数量是子类的数目(无论它们在继承树子分支中的位置如何)。接口的子类数量是实现它的类型数目。在这两种情况下,此指标的计算只统计在应用程序代码中声明的类型。
继承树深度(DIT)
类或结构的继承树深度(Depth of Inheritance Tree)是其基类的数量(包括 System.Object 类,因此 DIT >= 1)。
建议: DepthOfInheritance 高于 6 的类型可能难以维护。
方法度量
方法排名
MethodRank值通过应用计算 Google PageRank 算法应用于方法依赖关系图。应用中心为 0.15 的位似变换,使 MethodRank 的平均值为 1。
建议: MethodRank 较高的方法应该更仔细地测试,因为此类方法中的错误可能会造成更严重的后果。
方法级传入耦合(MethodCa)
特定方法的传入耦合(Afferent Coupling)是直接依赖它的方法数量。
方法级传出耦合(MethodCe)
特定方法的传出耦合(Efferent Coupling)是它直接依赖的方法数量。请注意,框架项目中声明的方法也会被计算在内。
NbParameters
方法的参数数量。Ref 和 Out 也会被计算在内。在 IL 中传递给实例方法的 this 引用不计为参数。
建议: NbParameters 高于 5 的方法可能难以调用并可能降低性能。
NbVariables
方法体中声明的变量数量。
建议: NbVariables 高于 8 的方法难以理解和维护。NbVariables 高于 15 的方法极其复杂,应拆分为更小的方法。
NbOverloads
方法的重载数量。如果方法没有重载,其 NbOverloads 值等于 1。此指标也适用于构造函数。
建议: NbOverloads 高于 6 的方法可能难以维护,并可能导致不必要的高耦合。
字段度量
字段级传入耦合(FieldCa)
特定字段的传入耦合(Afferent Coupling)是直接使用它的方法数量。
Halstead 度量
CppDepend 计算各种 Halstead 度量,这些度量由 Maurice H. Halstead 在《软件科学原理》(1977)中定义。Halstead 度量基于运算符和操作数的定义。
- 运算符: 算术('+')、相等/不等('<')、赋值('+=')、移位('>>')、逻辑('&&')和一元('*')运算符。用于指定控制点('while')和控制结构('else')、类型('double')和存储('extern')的保留字。函数调用、数组引用等。
- 操作数: 标识符、字面量、标签和函数名。每个字面量都被视为一个独立的操作数。
总运算符 (N1)
针对类型和方法定义。存在的运算符总数。
总操作数 (N2)
针对类型和方法定义。存在的操作数总数。
不同运算符 (n1)
针对类型和方法定义。存在的不同运算符数量。
不同操作数 (n2)
针对类型和方法定义。存在的不同操作数数量。如上所述,每个常量都被视为不同的。
Halstead程序长度 (N)
N = N1 + N2
Halstead 程序长度描述了从原始程序中移除除运算符和操作数之外的所有内容后获得的抽象程序的大小。
Halstead程序体积 (V)
V = N * log2(n1 + n2)
这模拟了存储长度为 N 的抽象程序所需的位数。
Halstead程序级别 (L)
L = (2/n1)*(n2/N2)
L 描述当前程序的体积 V 与同一算法最紧凑实现的体积 V* 之间的比率。
Halstead程序难度 (D)
D = (n1/2) * (N2/n2) = 1/L
Difficulty 是 Level 的倒数。Difficulty 随唯一运算符数量的增加而增加。
Halstead编程工作量 (E)
E = D * V
Halstead 关于编写(或理解)程序所需工作量的公式将工作量描述为与难度和体积都成正比。
Halstead编程时间 (T)
T = E/18秒
编程时间被认为与编程工作量成正比。
Halstead智能内容 (I)
I = V / D
Halstead 旨在将此指标作为衡量算法复杂度的语言无关度量。
