关于代码质量度量和分析的一些总结

最近团队做CMMI3认证,这期间涉及到了代码质量度量。花了点时间做了总结,分享给大家。

先看一张整体的图,然后逐个指标展开说明。

一、单元测试覆盖率
单元测试覆盖率(Coverage)是一个度量单元测试覆盖了多少代码的指标。它是一种衡量测试质量的方法,用来指示我们的测试用例覆盖了代码的多大部分。 覆盖率的计算方式通常包括以下几种: 行覆盖率(Line Coverage):测试覆盖了多少代码行。 分支覆盖率(Branch Coverage):测试覆盖了多少if、switch等决策点的所有可能路径。 函数覆盖率(Function Coverage):测试覆盖了多少个函数或方法。 语句覆盖率(Statement Coverage):测试覆盖了多少个语句。 覆盖率越高,表示的测试用例覆盖的代码越全面,代码的质量可能越好。但是,这并不意味着覆盖率100%就一定没有问题,因为覆盖率只是告诉我们测试了哪些代码,而不是告诉我们测试的质量如何。另外,有些代码可能很难达到高覆盖率,例如异常处理代码等。 一般来说,覆盖率应该尽可能的高,一般认为80%是一个比较好的目标。
二、代码复杂度
Cyclomatic Complexity(圈复杂度)和 Cognitive Complexity(认知复杂度) 都是软件度量中的复杂度度量指标。其中: 1. Cyclomatic Complexity圈复杂度在数量上表现为代码独立执行路径条数。 例如,每个"if"语句就会添加了一条额外的代码路径。圈复杂度越高,程序代码的判断逻辑就越复杂。此外,路径越多,就需要编写更多的测试用例来实现更高的代码覆盖率。 每个函数的平均圈复杂度是一个指标,可以比较程序之间的复杂性。 圈复杂度在一定程度上展示了程序代码的"可维护性"。 2. Cognitive Complexity(认知复杂度)是SonarQube提出的一种新的复杂度度量方法,它试图量化代码对人类理解的难度,而不仅仅是代码的结构复杂度。认知复杂度的计算考虑了程序的结构复杂度(如循环、判断分支等),以及程序的可读性(如代码的冗余性、是否遵守最佳实践等)。例如,一个包含嵌套循环和条件判断的函数,其认知复杂度会高于只包含顺序执行代码的函数。另一个例子是,使用了难以理解的短变量名或者包含冗长的函数和类,这些都会增加代码的认知复杂度。
三、代码重复度
代码重复度是指在代码库中有多少代码是重复的,也就是相似或完全相同的代码块出现的次数。 1. 代码重复通常是由于复制和粘贴编程(也称为"剪贴板编程")导致的,这种情况下,开发人员可能会复制一个函数或一段代码,然后稍作修改以满足新的需求。虽然这种方法可以快速解决问题,但它通常会导致维护困难和错误的增加。如果在原始代码中发现了一个错误,那么所有复制的代码都需要进行相同的修复。。 代码重复度 = (重复的代码行数 / 总代码行数) * 100% 这个比例越高,表示代码重复的程度越严重。 在防止代码重复方面,通常的最佳做法是使用函数或类来封装重复的代码,并在需要的地方调用这些函数或类。这样,如果需要修改代码,只需要在一个地方进行修改,而不需要在多个地方进行相同的修改。
四、代码坏味道
"Code Smells"或"代码坏味道"是一种代码质量度量,用来形容那些在代码中可能存在问题的代码片段。它并不一定表示代码有错误,而是表示代码的设计可能存在问题,这些问题可能会使得代码难以理解、难以维护、难以修改。 以下是一些常见的代码坏味道的例子: 复杂的条件逻辑:如果一个函数或方法中存在过多的if/else或switch语句,可能表示这个函数或方法承担了过多的责任,需要进行重构。 长方法:一个方法过长,可能难以理解和维护。一般来说,一个好的方法应该只做一件事情,并且做得好。 重复的代码:如同前面提到的代码重复度,代码重复是一种常见的代码坏味道,应该通过提取函数或类来消除。 神秘命名:如果变量、函数或类的命名不清楚,可能会导致理解和维护的困难。好的命名应该清晰表达其目的和用途。 过大的类或模块:如果一个类或模块过大,可能表示它承担了过多的责任,需要进行分解。
五、安全漏洞
Vulnerabilities或称为安全漏洞,是指在代码中可能存在的安全风险。这些风险可能被攻击者利用,从而对系统的数据和功能构成威胁。 SQL注入:如果代码中直接拼接SQL语句,而没有对用户输入进行适当的处理,那么攻击者可能会通过输入恶意数据来篡改SQL语句,从而进行非法查询或修改数据。 跨站脚本(XSS):如果网站直接输出用户的输入,而没有进行适当的转义或过滤,那么攻击者可能会通过输入包含JavaScript代码的数据,从而在其他用户的浏览器中执行这些代码。 路径遍历:如果代码中使用了用户的输入来构造文件路径,那么攻击者可能会通过输入特殊的路径(如"../")来访问到不应该被访问的文件。 不安全的反序列化:如果代码接受并反序列化了用户提供的数据,那么攻击者可能会通过提供恶意的数据来执行任意代码。 ......
六、技术债务
Technical Debt,或称为技术债务,是一个比喻,用来描述因为选择了快速或简单的解决方案,而非最佳的解决方案,从而在未来需要付出更多的工作来解决这些问题的情况。这就像财务债务一样,如果不及时偿还,随着时间的推移,"利息"会越来越多。 技术债务是一个重要的度量指标,用来估算修复所有代码坏味道所需的时间。例如,如果一个代码坏味道需要花费30分钟来修复,那么这个代码坏味道就会产生30分钟的技术债务。所有代码坏味道的技术债务累加起来,就是整个项目的技术债务。 技术债务可以帮助团队理解和量化代码质量问题的影响,从而做出更好的决策。团队可以基于技术债务来决定是否需要对某部分代码进行重构,或者在新功能开发和技术债务偿还之间做出权衡。 需要注意的是,技术债务并非都是坏事,有时候为了满足业务需求,适当的接受一些技术债务是可以接受的。关键在于,团队需要意识到技术债务的存在,并且制定计划来及时偿还技术债务,防止其无限制的增长。
七、阿里、微软、Google这些世界级软件公司的代码质量度量值
从公开的编程实践和代码质量标准中得到一些启示。这些公司通常都非常重视代码质量,并采取各种措施来保证代码质量,例如严格的代码审查流程、强制的单元测试和代码覆盖率要求、详细的编程规范和最佳实践等。此外,他们还经常使用自动化的代码质量检查工具,如静态代码分析工具,来自动检测代码中的问题。 单元测试覆盖率:这些公司通常都要求代码有良好的测试覆盖率。例如,Google在其测试博客上提到,他们的一些项目要求代码的单元测试覆盖率达到80%以上。 对于代码复杂度,一般来说,每个函数或方法的复杂度应该尽可能的低。有些组织可能会设定一个具体的阈值,例如,圈复杂度不得超过10。这意味着每个函数或方法的控制流程不应该有超过10个不同的路径。但是,这并不是绝对的,有时候为了实现复杂的功能,函数或方法的复杂度可能会较高。 对于代码重复度,一般来说,应该尽可能的低。有些组织可能会设定一个具体的阈值,例如,代码重复度不得超过5%。这意味着在所有代码中,不应该有超过5%的代码是重复的。但是,这也并不是绝对的,有时候为了代码的可读性和维护性,可能会有一些必要的代码重复。
对于代码坏味道,它是一种主观的度量,取决于团队对什么是"好的"代码的看法。一般来说,代码坏味道的数量应该尽可能地少。有些团队可能会设定一个阈值,例如,每1000行代码中不应该有超过10个代码坏味道。然而,这并不是绝对的,有时候为了满足特定的需求,可能会接受一些代码坏味道。 对于技术债务,它是一种估算修复所有代码坏味道所需的时间。一般来说,技术债务应该尽可能地低。有些团队可能会设定一个阈值,例如,每1000行代码的技术债务不应该超过10小时。然而,这也并不是绝对的,有时候为了快速交付功能,可能会接受一些技术债务。
八、研发度量指标大全

九、业内做代码扫描和度量分析的专业软件

SonarQube is a self-managed, automatic code review tool that systematically helps you deliver Clean Code. As a core element of our Sonar solution, SonarQube integrates into your existing workflow and detects issues in your code to help you perform continuous code inspections of your projects. The product analyses 30+ different programming languages and integrates into your Continuous Integration (CI) pipeline of DevOps platforms to ensure that your code meets high-quality standards.

代码质量阀

十、Azure Devops中集成SonarQube代码分析和上报

当然,代码质量阀是可以定义的