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

目前市面上的前端代码质量评分中的代码可维护度是大都是基于 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.hqwc.cn/news/175738.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++二分查找算法:最大为 N 的数字组合

涉及知识点 二分查找 数学 题目 给定一个按 非递减顺序 排列的数字数组 digits 。你可以用任意次数 digits[i] 来写的数字。例如&#xff0c;如果 digits [‘1’,‘3’,‘5’]&#xff0c;我们可以写数字&#xff0c;如 ‘13’, ‘551’, 和 ‘1351315’。 返回 可以生成的…

【CASS精品教程】打开cass提示base.dcl未找到文件的解决办法

打开cass 7.1时提示base.dcl未找到文件的解决办法。 文章目录 一、问题描述二、解决办法 一、问题描述 系统上安装了cad2006cass7.1&#xff0c;cass软件可以正常打开&#xff0c;但是在使用屏幕菜单绘制地图时&#xff0c;选择一个工具&#xff0c;提示base.dcl未找到文件&am…

蓝桥杯每日一题2023.11.14

题目描述 题目分析 此题目的最终目标是将字母都填上数使等式符合条件&#xff0c;实际我们发现可以使用搜索将所有符合条件的进行判断&#xff08;答案&#xff1a;29&#xff09; 由于小数可能会出现错误故我们将其进行简单变化进行搜索 #include<bits/stdc.h> using…

leetcode二分查找算法题

目录 1.二分查找2.在排序数组中查找元素的第一个和最后一个位置3.x的平方根4.搜索插入位置5.山脉数组的峰顶索引6. 寻找峰值7.寻找旋转排序数组中的最小值8.8.0~n-1中缺失的数字 1.二分查找 二分查找 class Solution { public:int search(vector<int>& nums, int …

计算机毕设 机器学习股票大数据量化分析与预测系统 - python 计算机毕设

文章目录 0 前言1 课题背景2 实现效果UI界面设计web预测界面RSRS选股界面 3 软件架构4 工具介绍Flask框架MySQL数据库LSTM 5 最后 0 前言 &#x1f525; 这两年开始毕业设计和毕业答辩的要求和难度不断提升&#xff0c;传统的毕设题目缺少创新和亮点&#xff0c;往往达不到毕业…

高德地图系列(一):vue项目如何使用高德地图、入门以及基本控件使用

目录 第一章 前言 第二章 准备工作 2.1 账号注册 2.2 高德地图开发平台文档 2.3 创建应用 第三章 使用地图 3.1 地图使用步骤 3.2 理解几个地图基础控件 3.3 基础类理解 第一章 前言 小编都是在vue项目中使用高德地图的&#xff0c;每一个功能都会亲测可用之后才会…

Intellij IDEA 内存设置的问题 及解决

解决方案&#xff1a; 在IDEA上运行较大项目时&#xff0c;编译量很大&#xff0c;可能会报出 Error:java: java.lang.OutOfMemoryError: Java heap space 的错误&#xff0c;解决方法如下&#xff1a; java.lang.OutOfMemoryError是内存不足导致的&#xff0c;因此需要修改Id…

景联文科技:驾驭数据浪潮,赋能AI产业——全球领先的数据标注解决方案供应商

根据IDC相关数据统计&#xff0c;全球数据量正在经历爆炸式增长&#xff0c;预计将从2016年的16.1ZB猛增至2025年的163ZB&#xff0c;其中大部分是非结构化数据&#xff0c;被直接利用&#xff0c;必须通过数据标注转化为AI可识别的格式&#xff0c;才能最大限度地发挥其应用价…

Python-Python高阶技巧:HTTP协议、静态Web服务器程序开发、循环接收客户端的连接请求

版本说明 当前版本号[20231114]。 版本修改说明20231114初版 目录 文章目录 版本说明目录HTTP协议1、网址1.1 网址的概念1.2 URL的组成1.3 知识要点 2、HTTP协议的介绍2.1 HTTP协议的概念及作用2.2 HTTP协议的概念及作用2.3 浏览器访问Web服务器的过程 3、HTTP请求报文3.1 H…

stable diffusion comfyui的api使用教程

一、为什么要使用comfyui的api?对比webui的api&#xff0c;它有什么好处&#xff1f; 1、自带队列 2、支持websocket 3、无需关心插件是否有开放api接口&#xff0c;只要插件在浏览器中可以正常使用&#xff0c;接口就一定可以使用 4、开发人员只需关心绘图流程的搭建 5、切换…

机器学习入门案例(3)之使用决策树预测是否适合打网球

大家好&#xff0c;我是邵奈一&#xff0c;一个不务正业的程序猿、正儿八经的斜杠青年。 1、世人称我为&#xff1a;被代码耽误的诗人、没天赋的书法家、五音不全的歌手、专业跑龙套演员、不合格的运动员… 2、这几年&#xff0c;我整理了很多IT技术相关的教程给大家&#xff0…

【Kotlin精简】第8章 协程

1 简介 Kotlin 中的协程提供了一种全新处理并发的方式&#xff0c;您可以在 Android 平台上使用它来简化异步执行的代码。协程是从 Kotlin 1.3 版本开始引入&#xff0c;但这一概念在编程世界诞生的黎明之际就有了&#xff0c;最早使用协程的编程语言可以追溯到 1967 年的 Sim…