typhonjs-escomplex 代码可读性 可维护度探索

news2024/12/25 0:57:31

目前市面上的前端代码质量评分中的代码可维护度是大都是基于 typhonjs-escomplex 这个库扫描而来,但是这个库的官方文档并没有介绍相关指标数据的计算规则,不知道规则如何提升指标数据呢?所以本文对 typhonjs-escomplex 源码进行探索,探索其关键指标计算逻辑。

使用方式

使用方式很简单,引用后调用 analyze 方法传入需要检测的源代码即可。

import escomplexModule from 'typhonjs-escomplex-module';

const ast = <some parsed AST>;

const report = escomplexModule.analyze(ast);

analyze 的第二个参数可以传入相关配置项。

commonjs: true,
logicalor: true,
newmi: true,

但此库只支持js文件的检测,对应像vue这类文件无法检测,我们可以通过以下方式提取script中的内容后进行检测。

const fs = require('fs');
const doc = fs.readFileSync('test.vue', 'utf-8');
const escomplex = require('typhonjs-escomplex');

const srcs = doc.match(/(?<=<script>)[\s\S]*?(?=<\/script>)/g);
srcs.map((src) => {
  const report = escomplex.analyzeModule(src); 
});

调用analyzeModule返回的report即是代码的相关检测指标数据。

需要注意的是此库已经5年没有更新了,由于这方面的库比较少加上本身的能力也比较强大,就算过去了5年没有维护的情况下现在的每周下载仍在1万+的数量。

VSCode插件

在VScode中可以安装插件 FE Doctor 或 AppWorks 的 Doctor
FE Doctor这个插件可以帮你一键生成质量报告,且执行速度很快。
Doctor 可以在一次扫描中快速检测到应用程序和基础库代码中的各种安全漏洞和质量问题,你可以一键修复所有报告的问题,或者点击定位到源代码逐条来修复。

Doctor

FE Doctor

FE Doctor

这两款插件底层都是基于typhonjs-escomplex库扫码代码,只是UI交互有些不一样,有兴趣的可以安装试试看,看看你的代码能打多少分。

关键指标

typhonjs-escomplex执行检测完返回的report的数据如下,有所删减:

ModuleReport {
  lineEnd: 21,
  lineStart: 1,
  maintainability: 63.213,
  methods: [],
  aggregateAverage: MethodAverage {
    cyclomatic: 3,
    cyclomaticDensity: 30,
    halstead: HalsteadAverage {
      bugs: 0.053,
      difficulty: 8.182,
      effort: 1293.737,
      length: 36,
      time: 71.874,
      vocabulary: 21,
      volume: 158.123,
      operands: [Object],
      operators: [Object]
    },
    paramCount: 0,
    sloc: { logical: 10, physical: 21 }
  },

}

需要重点关注的有以下几个数据,后续计算需要用到:

  • cyclomatic: 代码圈复杂度
  • halstead.difficulty: 代码可读性
  • halstead.effort: 代码工作量(volume与difficulty的乘积)
  • sloc.logical: 源代码行数
  • maintainability: 代码可维护度

这里着重解释一下代码圈复杂度代码可读性代码可维护度是基于前面的几个值进一步计算而来。

代码圈复杂度

代码圈复杂度(cyclomatic)是一种度量代码复杂性的指标,它用于衡量程序中的单个方法或函数的复杂程度。

圈复杂度常用的计算公式如下:

圈复杂度 = E - N + 2P
  • E表示程序中的边(一条边表示一条语句或条件语句等控制流转换)的数量;
  • N表示程序中的节点(基本块,即一组顺序执行的语句)的数量;
  • P表示程序中的组件(子程序或函数)的数量。

简单来说圈复杂度技术公式的含义:圈复杂度等于边的数量减去节点的数量,再加上两个控制流图的起点和终点。

较高的代码圈复杂度意味着代码逻辑较为复杂,难以理解和维护,也意味着代码中存在潜在的错误和缺陷。建议控制代码圈复杂度在一个可管理的范围内,一般上限为10-15之间,以提高代码的质量和可读性。

详细解析可参考维基百科:https://en.wikipedia.org/wiki/Cyclomatic_complexity

代码可读性

上面report中的halstead对象相关指标是指霍尔斯特德复杂度测量(Halstead complexity measures),代码可读性是halstead中的difficulty字段。

霍尔斯特德复杂度测量是由霍尔斯特德在1977年提出的一种软件度量方法,是有关软件开发经验科学的论文中的一部分。 霍尔斯特德观察到软件度量应该要反映在不同编程语言中算法实现的方式,但又要独立于使用的平台及语言。这些度量要可以由静态代码中计算而得。

相关指标计算公式如下,详细解析可参考维基百科:https://en.wikipedia.org/wiki/Halstead_complexity_measures

维基百科

从公式可以看出核心计算的基础主要是以下数值:

  • η 1 \eta_1 η1 为不同运算子的个数。
  • η 2 \eta_2 η2 为不同算子的个数。
  • N 1 N_1 N1 为所有运算子合计出现的次数。
  • N 2 N_2 N2 为所有算子合计出现的次数。
    上述的运算子包括传统的运算子及保留字,算子包括变数及常数。依上述数值,可以计算以下的量测量:
  • 程式词汇数(Program vocabulary): η = η 1 + η 2 \eta = \eta _1+\eta_2 η=η1+η2
  • 程式长度(Program length): N = N 1 + N 2 N=N_1+N_2 N=N1+N2

程式词汇数可以理解为代码中的不同操作符和操作数的总数,较大数值意味着程序中使用了更多不同的操作符和操作数,可能需要更多的理解和维护工作。

程序长度是指程序中操作符和操作数的总数。突出程序的规模和复杂性,较长的程序长度意味可能需要更多的时间和资源来开发和维护。

知道其计算逻辑后我们的代码优化可以考虑以下几个方向:

  • 识别并减少代码中不同操作符和操作数的数量。可以通过简化复杂表达式、删除不必要的变量或函数,以及使用更多的内置函数来实现

  • 删除冗余或重复的代码,重构代码、消除不必要代码带来的复杂性。使用高效的算法和数据结构,来减少程序长度。

  • 复杂任务分解为更小、更易管理的函数或模块来实现。

  • 使用更高级的控制结构和抽象代码,提高程序水平。使代码更易读、易于维护和理解。

代码可维护度

report 中的 maintainability 代表代码可维护度数值,1991年,保罗·奥曼(Paul Oman)和杰克·哈格迈斯特(Jack Hagemeister)在爱达荷大学设计了这个度量标准,该度量标准是根据其他三个度量标准的平均值在整个程序或模块级别上计算的,使用以下公式:

171 -
(3.42 * ln(mean effort)) -
(0.23 * ln(mean cyclomatic complexity)) -
(16.2 * ln(mean logical LOC))

最终取值范围从负无穷到171,较大的数值表示更高的可维护性水平。在他们的原始论文中,奥曼和哈格迈斯特确定65是一个程序应被视为难以维护的阈值。

由此公式可以看出想要获取较大的数值需要让后面的减数足够小,那么我们就需要优化代码可读性,减小代码复杂度以及文件中代码的行数。

核心源码实现

接下来根据返回的report查阅其源码找到maintainability的计算代码如下:

function calculateMaintainabilityIndex(report, settings, averageCyclomatic, averageEffort, averageLoc) {
  report.maintainability = 
    171 - 
    3.42 * Math.log(averageEffort) - 
    (0.23 * averageCyclomatic === 0 ? 0 : Math.log(averageCyclomatic)) - 
    16.2 * Math.log(averageLoc);
  if (report.maintainability > 171) {
    report.maintainability = 171;
  }
  if (settings.newmi) {
    report.maintainability = Math.max(0, report.maintainability * 100 / 171);
  }
}

calculateMaintainabilityIndex 函数用于计算代码的可维护度数据,核心计算和上面提到的公式一致。另外如果settings对象的newmi属性为真,那么将maintainability更新为其与171的比值的百分比,并确保其最小值为0且最大值为100,方便日常查看理解。

根据代码调用往上找到代码可读性halstead相关属性的计算逻辑,和上面维基百科截图中的计算一致。

function calculateHalsteadMetrics(halstead) {
    halstead.length = halstead.operators.total + halstead.operands.total;

    if (halstead.length === 0) {
       halstead.reset();
    } else {
       halstead.vocabulary = halstead.operators.distinct + halstead.operands.distinct;
       halstead.difficulty = halstead.operators.distinct / 2 * (halstead.operands.distinct === 0 ? 1 : halstead.operands.total / halstead.operands.distinct);
       halstead.volume = halstead.length * (Math.log(halstead.vocabulary) / Math.log(2));
       halstead.effort = halstead.difficulty * halstead.volume;
       halstead.bugs = halstead.volume / 3000;
       halstead.time = halstead.effort / 18;
    }
}

从这段代码可以看出整个计算都是基于 halstead.operatorshalstead.operands 这两个数值,为了方便理解,扫码以下代码断点查看所影响的具体内容。

export const bType = {
  0: '全部',
  1: '淘宝',
  2: '天猫',
  3: '京东'
}

export const selectList = [
  {
    name: '今日',
    id: 0
  },
  {
    name: '近7日',
    id: 1
  },
  {
    name: '本月',
    id: 2
  }
]

以下是调试截图,可以看到 halstead.operators 最终的数据是代码中的操作符,而 halstead.operands 则是代码中的相关变量名称和对应的值。通过这两个数值可以看出要精简代码,简化复杂表达式、删除不必要的变量或函数才能提高相关数值。

总结

通过查阅代码圈复杂度和代码可读性的计算方法,并分析扫描库 typhonjs-escomplex 的源代码的实现逻辑,想要基于此扫码库提升代码质量以及相关指标数据可以从以下几个方面进行:

  1. 减少操作符和操作数的种类,尽量使用简单、常见的操作符和操作数,避免过于复杂或冗余的语言特性,以及使用更多的内置函数来实现。

  2. 模块化或组件复用,将代码分解为独立的模块或组件,每个模块负责特定的功能,这样可以减少重复的代码也会提示代码可维护度。

  3. 简化复杂逻辑,分解更小、更易管理的函数或模块来实现,避免过多的条件判断和嵌套循环,从而降低代码的复杂度。

  4. 代码重构:定期审查和重构代码,使其更加清晰、简洁,并符合良好的代码设计原则。

优化代码质量目标是减少代码的复杂性和冗余,提高代码的可读性和可维护性。但在实际优化过程中也需要权衡对代码的改造是否存在过大的风险和需要更多的投入回归测试。如果你对代码质量的要求高,那么这是一件需要长期要去做的事情,需要定期审查过往代码是否存在优化提升的空间。


看完本文如果觉得有用,记得点个赞支持,收藏起来说不定哪天就用上啦~

专注前端开发,分享前端相关技术干货,公众号:南城大前端(ID: nanchengfe)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1209082.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

NI和EttusResearchUSRP设备之间的区别

NI和EttusResearchUSRP设备之间的区别 概述 USRP&#xff08;通用软件无线电外设&#xff09;设备是业界领先的商软件定义无线电&#xff08;SDR&#xff09;。全球数以千计的工程师使用USRPSDR来快速设计、原型设计和部署无线系统。它们以两个不同的品牌进行营销和销售&…

机器学习线性代数知识补充

线性代数知识补充 正交矩阵与正交变换方阵特征值与特征向量相似矩阵对角化二次型正定二次型 正交矩阵与正交变换 方阵特征值与特征向量 相似矩阵 对角化 二次型 正定二次型

如何在Jupyter Lab中安装不同的Kernel

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

50.批处理脚本(2/2)

目录 一、批处理命令。 &#xff08;1&#xff09;net use 连接共享文件夹或查看。 &#xff08;1.1&#xff09;连接共享文件夹。 &#xff08;1.2&#xff09;断开连接。 &#xff08;1.3&#xff09;显示当前连接。 &#xff08;1.4&#xff09;查看电脑的共享文件夹。…

[文件读取]cuberite 文件读取 (CVE-2019-15516)

1.1漏洞描述 漏洞编号CVE-2019-15516漏洞类型文件上传漏洞等级⭐⭐⭐漏洞环境VULFOCUS攻击方式 描述: Cuberite是一款使用C语言编写的、轻量级、可扩展的多人游戏服务器。 Cuberite 2019-06-11之前版本中存在路径遍历漏洞。该漏洞源于网络系统或产品未能正确地过滤资源或文件路…

计算机操作系统—经典同步问题

经典同步问题 1.生产者与消费者问题 1.1.问题概述 在现实生活中&#xff0c;当我们缺少某些生活用品时&#xff0c;就会到超市去购买。当你到超市时&#xff0c;你的身份就是消费者&#xff0c;那么这些商品又是哪里来的呢&#xff0c;自然是供应商&#xff0c;那么它们就是生…

Python基础入门----如何使用 Pipenv 在项目目录中创建虚拟环境

文章目录 引言Pipenv 简介安装 Pipenv在项目目录中创建虚拟环境1. 进入你的项目目录2. 设置环境变量3. 创建虚拟环境4. 激活虚拟环境结论引言 在Python开发中,使用虚拟环境是一种良好的实践,它可以帮助开发者管理项目的依赖,并避免不同项目间的依赖冲突。Pipenv 是一个流行…

MySQL8 绿色版安装

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; MySQL学习 ✨特色专栏&#xff1a; My…

SAP:解决函数CONNE_IMPORT_WRONG_COMP_DECS CX_SY_IMPORT_MISMATCH_ERROR错误

用户反馈报表中取数异常&#xff0c;经检查发现SE37执行取数函数ZLY_R_CWFX03报以下错误。 Category ABAP Programming Error Runtime Errors CONNE_IMPORT_WRONG_COMP_DECS Except. CX_SY_IMPORT_MISMATCH_ERROR ABAP Program ZLY_R_CWFX03FT Application Component Not Assig…

springboot整合minio步骤

springboot整合minio步骤 springboot整合minio十分的简单&#xff0c;接下来使用springboot整合一下minio。 一、导入依赖 首先需要导入minio的依赖。 <!--maven引入minio排除okhttp依赖并添加高版本的okhttp依赖--><dependency><groupId>io.minio</g…

KT148A语音芯片的下载用的是串口,测试可以直接串口发指令控制吗

一、问题简介 KT148A语音芯片的下载用的是串口&#xff0c;那我实际测试是不是可以直接串口发指令测试控制&#xff1f;就不用单独写程序去模拟一线串口的时序了 详细描述 首先看一下KT148A芯片的参考设计原理图&#xff1a;其中芯片的2脚和3脚就是串口&#xff0c;注意下载语…

走向边缘智能,美格智能携手阿加犀成功在高算力AI模组上运行一系列大语言模型

近日&#xff0c;美格智能发挥软硬件一体协同开发能力&#xff0c;融合阿加犀卓越的AI优化部署技术&#xff0c;在搭载高通QCS8550平台的高算力AI模组上&#xff0c;成功运行了一系列大语言模型&#xff0c;包括LLaMA-2、通义千问Qwen、百川大模型、RedPajama、ChatGLM2、Vicun…

Vue 小黑记事本组件版

渲染功能&#xff1a; 1.提供数据&#xff1a; 提供在公共的父组件 App.vue 2.通过父传子&#xff0c;将数据传递给TodoMain 3.利用 v-for渲染 添加功能&#xff1a; 1.收集表单数据 v-model 2.监听事件&#xff08;回车点击都要添加&#xff09; 3.子传父&#xff0c;讲…

【电子通识】USB端口颜色编码标识

不知道你有没有发现 USB 口有不同的颜色&#xff0c;黑色、蓝色、紫色、红色、黄色等等&#xff0c;你知道不同颜色的 USB 口各代表什么意思吗&#xff1f; 这些颜色不是USB规范所要求的&#xff0c;设备制造商之间也不一致。例如&#xff0c;Intel使用橙色表示充电端口&#…

【java面试题】Integer对象输出结果是?

/** Copyright (c) 2006, 2023, webrx.cn All rights reserved.**/package cn.webrx;/*** <p>Project: wxbili2mp4 - Test* <p>Powered by webrx On 2023-11-14 20:28:46* <p>描述&#xff1a;<p>** author webrx [webrx126.com]* version 1.0* since …

计算机毕业设计 基于SpringBoot的在线考试系统的研究与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…

C 语言递归

C 语言递归 在本教程中&#xff0c;您将借助示例学习使用C语言编程编写递归函数。 调用自身的函数称为递归函数。并且&#xff0c;这种技术称为递归。 递归如何工作&#xff1f; void recurse() {... .. ...recurse();... .. ... }int main() {... .. ...recurse();... .. …

在 Electron上安装better-sqlite3出错

错误问题 一直卡npm install --global windows-build-tools --vs2015 这一步 解决 安装&#xff1a;pnpm install better-sqlite3 --save安装命令 pnpm i -D electron-rebuild 手动运行&#xff1a;node_modules/.bin/electron-rebuild -f -w better-sqlite3 我直接在packa…

餐饮业数字化革命:抖音小程序团购功能的开发与优化

本文将聚焦于餐饮业数字化的前沿&#xff0c;着眼于抖音小程序团购功能的开发与优化&#xff0c;探讨如何借助这一功能实现餐饮业的蓬勃发展。 一、数字化浪潮下的餐饮业 传统餐饮业面临的挑战在于如何更好地适应快节奏生活和消费者多元化需求。数字化浪潮为餐饮业提供了解决方…

信息检索与数据挖掘 | 【实验】检索评价指标MAP、MRR、NDCG

文章目录 &#x1f4da;实验内容&#x1f4da;知识梳理&#x1f4da;实验步骤&#x1f407;前情提要&#x1f407;MAP评价指标函数&#x1f407;MRR 评价指标函数&#x1f407;NDCG评价指标函数&#x1f407;调试结果 &#x1f4da;实验内容 实现以下指标评价&#xff0c;并对…