前端代碼質(zhì)量-圈復(fù)雜度原理和實(shí)踐
寫程序時(shí)時(shí)刻記著,這個(gè)將來(lái)要維護(hù)你寫的程序的人是一個(gè)有嚴(yán)重暴力傾向,并且知道你住在哪里的精神變態(tài)者。
1. 導(dǎo)讀
你們是否也有過(guò)下面的想法?
- 重構(gòu)一個(gè)項(xiàng)目還不如新開發(fā)一個(gè)項(xiàng)目...
 - 這代碼是誰(shuí)寫的,我真想...
 
你們的項(xiàng)目中是否也存在下面的問(wèn)題?
- 單個(gè)項(xiàng)目也越來(lái)越龐大,團(tuán)隊(duì)成員代碼風(fēng)格不一致,無(wú)法對(duì)整體的代碼質(zhì)量做全面的掌控
 - 沒(méi)有一個(gè)準(zhǔn)確的標(biāo)準(zhǔn)去衡量代 碼結(jié)構(gòu)復(fù)雜的程度,無(wú)法量化一個(gè)項(xiàng)目的代碼質(zhì)量
 - 重構(gòu)代碼后無(wú)法立即量化重構(gòu)后代碼質(zhì)量是否提升
 
針對(duì)上面的問(wèn)題,本文的主角 圈復(fù)雜度 重磅登場(chǎng),本文將從圈復(fù)雜度原理出發(fā),介紹圈復(fù)雜度的計(jì)算方法、如何降低代碼的圈復(fù)雜度,如何獲取圈復(fù)雜度,以及圈復(fù)雜度在公司項(xiàng)目的實(shí)踐應(yīng)用。
2. 圈復(fù)雜度
2.1 定義
圈復(fù)雜度 (Cyclomatic complexity) 是一種代碼復(fù)雜度的衡量標(biāo)準(zhǔn),也稱為條件復(fù)雜度或循環(huán)復(fù)雜度,它可以用來(lái)衡量一個(gè)模塊判定結(jié)構(gòu)的復(fù)雜程度,數(shù)量上表現(xiàn)為獨(dú)立現(xiàn)行路徑條數(shù),也可理解為覆蓋所有的可能情況最少使用的測(cè)試用例數(shù)。簡(jiǎn)稱 CC 。其符號(hào)為 VG 或是 M 。
圈復(fù)雜度 在 1976 年由 Thomas J. McCabe, Sr. 提出。
圈復(fù)雜度大說(shuō)明程序代碼的判斷邏輯復(fù)雜,可能質(zhì)量低且難于測(cè)試和維護(hù)。程序的可能錯(cuò)誤和高的圈復(fù)雜度有著很大關(guān)系。
2.2 衡量標(biāo)準(zhǔn)
代碼復(fù)雜度低,代碼不一定好,但代碼復(fù)雜度高,代碼一定不好。
| 圈復(fù)雜度 | 代碼狀況 | 可測(cè)性 | 維護(hù)成本 | 
|---|---|---|---|
| 1 - 10 | 清晰、結(jié)構(gòu)化 | 高 | 低 | 
| 10 - 20 | 復(fù)雜 | 中 | 中 | 
| 20 - 30 | 非常復(fù)雜 | 低 | 高 | 
| >30 | 不可讀 | 不可測(cè) | 非常高 | 
3. 計(jì)算方法
3.1 控制流程圖
控制流程圖,是一個(gè)過(guò)程或程序的抽象表現(xiàn),是用在編譯器中的一個(gè)抽象數(shù)據(jù)結(jié)構(gòu),由編譯器在內(nèi)部維護(hù),代表了一個(gè)程序執(zhí)行過(guò)程中會(huì)遍歷到的所有路徑。它用圖的形式表示一個(gè)過(guò)程內(nèi)所有基本塊執(zhí)行的可能流向, 也能反映一個(gè)過(guò)程的實(shí)時(shí)執(zhí)行過(guò)程。
下面是一些常見的控制流程:
3.2 節(jié)點(diǎn)判定法
有一個(gè)簡(jiǎn)單的計(jì)算方法,圈復(fù)雜度實(shí)際上就是等于判定節(jié)點(diǎn)的數(shù)量再加上1。向上面提到的:if else 、switch case 、 for循環(huán)、三元運(yùn)算符等等,都屬于一個(gè)判定節(jié)點(diǎn),例如下面的代碼:
- function testComplexity(*param*) {
 - let result = 1;
 - if (param > 0) {
 - result--;
 - }
 - for (let i = 0; i < 10; i++) {
 - result += Math.random();
 - }
 - switch (parseInt(result)) {
 - case 1:
 - result += 20;
 - break;
 - case 2:
 - result += 30;
 - break;
 - default:
 - result += 10;
 - break;
 - }
 - return result > 20 ? result : result;
 - }
 
上面的代碼中一共有1個(gè)if語(yǔ)句,一個(gè)for循環(huán),兩個(gè)case語(yǔ)句,一個(gè)三元運(yùn)算符,所以代碼復(fù)雜度為 4+1+1=6。另外,需要注意的是 || 和 && 語(yǔ)句也會(huì)被算作一個(gè)判定節(jié)點(diǎn),例如下面代碼的代碼復(fù)雜為3:
- function testComplexity(*param*) {
 - let result = 1;
 - if (param > 0 && param < 10) {
 - result--;
 - }
 - return result;
 - }
 
3.3 點(diǎn)邊計(jì)算法
- M = E − N + 2P
 
- E:控制流圖中邊的數(shù)量
 - N:控制流圖中的節(jié)點(diǎn)數(shù)量
 - P:獨(dú)立組件的數(shù)目
 
前兩個(gè),邊和節(jié)點(diǎn)都是數(shù)據(jù)結(jié)構(gòu)圖中最基本的概念:
P代表圖中獨(dú)立組件的數(shù)目,獨(dú)立組件是什么意思呢?來(lái)看看下面兩個(gè)圖,左側(cè)為連通圖,右側(cè)為非連通圖:
- 連通圖:對(duì)于圖中任意兩個(gè)頂點(diǎn)都是連通的
 
一個(gè)連通圖即為圖中的一個(gè)獨(dú)立組件,所以左側(cè)圖中獨(dú)立組件的數(shù)目為1,右側(cè)則有兩個(gè)獨(dú)立組件。
對(duì)于我們的代碼轉(zhuǎn)化而來(lái)的控制流程圖,正常情況下所有節(jié)點(diǎn)都應(yīng)該是連通的,除非你在某些節(jié)點(diǎn)之前執(zhí)行了 return,顯然這樣的代碼是錯(cuò)誤的。所以每個(gè)程序流程圖的獨(dú)立組件的數(shù)目都為1,所以上面的公式還可以簡(jiǎn)化為 M = E − N + 2 。
4. 降低代碼的圈復(fù)雜度
我們可以通過(guò)一些代碼重構(gòu)手段來(lái)降低代碼的圈復(fù)雜度。
重構(gòu)需謹(jǐn)慎,示例代碼僅僅代表一種思想,實(shí)際代碼要遠(yuǎn)遠(yuǎn)比示例代碼復(fù)雜的多。
4.1 抽象配置
通過(guò)抽象配置將復(fù)雜的邏輯判斷進(jìn)行簡(jiǎn)化。例如下面的代碼,根據(jù)用戶的選擇項(xiàng)執(zhí)行相應(yīng)的操作,重構(gòu)后降低了代碼復(fù)雜度,并且如果之后有新的選項(xiàng),直接加入配置即可,而不需要再去深入代碼邏輯中進(jìn)行改動(dòng):
4.2 單一職責(zé) - 提煉函數(shù)
單一職責(zé)原則(SRP):每個(gè)類都應(yīng)該有一個(gè)單一的功能,一個(gè)類應(yīng)該只有一個(gè)發(fā)生變化的原因。
在 JavaScript 中,需要用到的類的場(chǎng)景并不太多,單一職責(zé)原則則是更多地運(yùn)用在對(duì)象或者方法級(jí)別上面。
函數(shù)應(yīng)該做一件事,做好這件事,只做這一件事。 — 代碼整潔之道
關(guān)鍵是如何定義這 “一件事” ,如何將代碼中的邏輯進(jìn)行抽象,有效的提煉函數(shù)有利于降低代碼復(fù)雜度和降低維護(hù)成本。
4.3 使用 break 和 return 代替控制標(biāo)記
我們經(jīng)常會(huì)使用一個(gè)控制標(biāo)記來(lái)標(biāo)示當(dāng)前程序運(yùn)行到某一狀態(tài),很多場(chǎng)景下,使用 break 和 return 可以代替這些標(biāo)記并降低代碼復(fù)雜度。
4.4 用函數(shù)取代參數(shù)
setField 和 getField 函數(shù)就是典型的函數(shù)取代參數(shù),如果么有 setField、getField 函數(shù),我們可能需要一個(gè)很復(fù)雜的 setValue、getValue 來(lái)完成屬性賦值操作:
4.5 簡(jiǎn)化條件判斷 - 逆向條件
某些復(fù)雜的條件判斷可能逆向思考后會(huì)變的更簡(jiǎn)單。
4.6 簡(jiǎn)化條件判斷 -合并條件
將復(fù)雜冗余的條件判斷進(jìn)行合并。
4.7 簡(jiǎn)化條件判斷 - 提取條件
將復(fù)雜難懂的條件進(jìn)行語(yǔ)義化提取。
5. 圈復(fù)雜度檢測(cè)方法
5.1 eslint規(guī)則
eslint提供了檢測(cè)代碼圈復(fù)雜度的rules:
我們將開啟 rules 中的 complexity 規(guī)則,并將圈復(fù)雜度大于 0 的代碼的 rule severity 設(shè)置為 warn 或 error 。
- rules: {
 - complexity: [
 - 'warn',
 - { max: 0 }
 - ]
 - }
 
這樣 eslint 就會(huì)自動(dòng)檢測(cè)出所有函數(shù)的代碼復(fù)雜度,并輸出一個(gè)類似下面的 message。
- Method 'testFunc' has a complexity of 12. Maximum allowed is 0
 - Async function has a complexity of 6. Maximum allowed is 0.
 - ...
 
5.2 CLIEngine
我們可以借助 eslint 的 CLIEngine ,在本地使用自定義的 eslint 規(guī)則掃描代碼,并獲取掃描結(jié)果輸出。
初始化 CLIEngine :
- const eslint = require('eslint');
 - const { CLIEngine } = eslint;
 - const cli = new CLIEngine({
 - parserOptions: {
 - ecmaVersion: 2018,
 - },
 - rules: {
 - complexity: [
 - 'error',
 - { max: 0 }
 - ]
 - }
 - });
 
使用 executeOnFiles 對(duì)指定文件進(jìn)行掃描,并獲取結(jié)果,過(guò)濾出所有 complexity 的 message 信息。
- const reports = cli.executeOnFiles(['.']).results;
 - for (let i = 0; i < reports.length; i++) {
 - const { messages } = reports[i];
 - for (let j = 0; j < messages.length; j++) {
 - const { message, ruleId } = messages[j];
 - if (ruleId === 'complexity') {
 - console.log(message);
 - }
 - }
 - }
 
5.3 提取message
通過(guò) eslint 的檢測(cè)結(jié)果將有用的信息提取出來(lái),先測(cè)試幾個(gè)不同類型的函數(shù),看看 eslint 的檢測(cè)結(jié)果:
- function func1() {
 - console.log(1);
 - }
 - const func2 = () => {
 - console.log(2);
 - };
 - class TestClass {
 - func3() {
 - console.log(3);
 - }
 - }
 - async function func4() {
 - console.log(1);
 - }
 
執(zhí)行結(jié)果:
- Function 'func1' has a complexity of 1. Maximum allowed is 0.
 - Arrow function has a complexity of 1. Maximum allowed is 0.
 - Method 'func3' has a complexity of 1. Maximum allowed is 0.
 - Async function 'func4' has a complexity of 1. Maximum allowed is 0.
 
可以發(fā)現(xiàn),除了前面的函數(shù)類型,以及后面的復(fù)雜度,其他都是相同的。
函數(shù)類型:
- Function :普通函數(shù)
 - Arrow function : 箭頭函數(shù)
 - Method : 類方法
 - Async function : 異步函數(shù)
 
截取方法類型:
- const REG_FUNC_TYPE = /^(Method |Async function |Arrow function |Function )/g;
 - function getFunctionType(message) {
 - let hasFuncType = REG_FUNC_TYPE.test(message);
 - return hasFuncType && RegExp.$1;
 - }
 
將有用的部分提取出來(lái):
- const MESSAGE_PREFIX = 'Maximum allowed is 1.';
 - const MESSAGE_SUFFIX = 'has a complexity of ';
 - function getMain(message) {
 - return message.replace(MESSAGE_PREFIX, '').replace(MESSAGE_SUFFIX, '');
 - }
 
提取方法名稱:
- function getFunctionName(message) {
 - const main = getMain(message);
 - let test = /'([a-zA-Z0-9_$]+)'/g.test(main);
 - return test ? RegExp.$1 : '*';
 - }
 
截取代碼復(fù)雜度:
- function getComplexity(message) {
 - const main = getMain(message);
 - (/(\d+)\./g).test(main);
 - return +RegExp.$1;
 - }
 
除了 message ,還有其他的有用信息:
- 函數(shù)位置:獲取 messages 中的 line 、column 即函數(shù)的行、列位置
 - 當(dāng)前文件名稱:reports 結(jié)果中可以獲取當(dāng)前掃描文件的絕對(duì)路徑 filePath ,通過(guò)下面的操作獲取真實(shí)文件名:
 
- filePath.replace(process.cwd(), '').trim()
 
- 復(fù)雜度等級(jí),根據(jù)函數(shù)的復(fù)雜度等級(jí)給出重構(gòu)建議:
 
| 圈復(fù)雜度 | 代碼狀況 | 可測(cè)性 | 維護(hù)成本 | 
|---|---|---|---|
| 1 - 10 | 清晰、結(jié)構(gòu)化 | 高 | 低 | 
| 10 - 20 | 復(fù)雜 | 中 | 中 | 
| 20 - 30 | 非常復(fù)雜 | 低 | 高 | 
| >30 | 不可讀 | 不可測(cè) | 非常高 | 
| 圈復(fù)雜度 | 代碼狀況 | 
|---|---|
| 1 - 10 | 無(wú)需重構(gòu) | 
| 11 - 15 | 建議重構(gòu) | 
| >15 | 強(qiáng)烈建議重構(gòu) | 
6.架構(gòu)設(shè)計(jì)
將代碼復(fù)雜度檢測(cè)封裝成基礎(chǔ)包,根據(jù)自定義配置輸出檢測(cè)數(shù)據(jù),供其他應(yīng)用調(diào)用。
上面的展示了使用 eslint 獲取代碼復(fù)雜度的思路,下面我們要把它封裝為一個(gè)通用的工具,考慮到工具可能在不同場(chǎng)景下使用,例如:網(wǎng)頁(yè)版的分析報(bào)告、cli版的命令行工具,我們把通用的能力抽象出來(lái)以 npm包 的形式供其他應(yīng)用使用。
在計(jì)算項(xiàng)目代碼復(fù)雜度之前,我們首先要具備一項(xiàng)基礎(chǔ)能力,代碼掃描,即我們要知道我們要對(duì)項(xiàng)目里的哪些文件做分析,首先 eslint 是具備這樣的能力的,我們也可以直接用 glob 來(lái)遍歷文件。但是他們都有一個(gè)缺點(diǎn),就是 ignore 規(guī)則是不同的,這對(duì)于用戶來(lái)講是有一定學(xué)習(xí)成本的,因此我這里把手動(dòng)封裝代碼掃描,使用通用的 npm ignore 規(guī)則,這樣代碼掃描就可以直接使用 .gitignore這樣的配置文件。另外,代碼掃描作為代碼分析的基礎(chǔ)能力,其他代碼分析也是可以公用的。
-  基礎(chǔ)能力
    
- 代碼掃描能力
 - 復(fù)雜度檢測(cè)能力
 - ...
 
 -  應(yīng)用
    
- 命令行工具
 - 代碼分析報(bào)告
 - ...
 
 
7. 基礎(chǔ)能力 - 代碼掃描
本文涉及的 npm 包和 cli命令源碼均可在我的開源項(xiàng)目 awesome-cli中查看。
awesome-cli 是我新建的一個(gè)開源項(xiàng)目:有趣又實(shí)用的命令行工具,后面會(huì)持續(xù)維護(hù),敬請(qǐng)關(guān)注,歡迎 star。
代碼掃描(c-scan)源碼:https://github.com/ConardLi/a...
代碼掃描是代碼分析的底層能力,它主要幫助我們拿到我們想要的文件路徑,應(yīng)該滿足我們以下兩個(gè)需求:
- 我要得到什么類型的文件
 - 我不想要哪些文件
 
7.1 使用
- npm i c-scan --save
 - const scan = require('c-scan');
 - scan({
 - extensions:'**/*.js',
 - rootPath:'src',
 - defalutIgnore:'true',
 - ignoreRules:[],
 - ignoreFileName:'.gitignore'
 - });
 
7.2 返回值
符合規(guī)則的文件路徑數(shù)組:
7.3 參數(shù)
-  extensions
    
- 掃描文件擴(kuò)展名
 - 默認(rèn)值:**/*.js
 
 
-  rootPath
    
- 掃描文件路徑
 - 默認(rèn)值:.
 
 -  defalutIgnore
    
- 是否開啟默認(rèn)忽略(glob規(guī)則)
 - glob ignore規(guī)則為內(nèi)部使用,為了統(tǒng)一ignore規(guī)則,自定義規(guī)則使用gitignore規(guī)則
 - 默認(rèn)值:true
 - 默認(rèn)開啟的 glob ignore 規(guī)則:
 
 
- const DEFAULT_IGNORE_PATTERNS = [
 - 'node_modules/**',
 - 'build/**',
 - 'dist/**',
 - 'output/**',
 - 'common_build/**'
 - ];
 
-  ignoreRules
    
- 自定義忽略規(guī)則(gitignore規(guī)則)
 - 默認(rèn)值:[]
 
 -  ignoreFileName
    
- 自定義忽略規(guī)則配置文件路徑(gitignore規(guī)則)
 - 默認(rèn)值:.gitignore
 - 指定為null則不啟用ignore配置文件
 
 
7.4 核心實(shí)現(xiàn)
基于 glob ,自定義 ignore 規(guī)則進(jìn)行二次封裝。
- /**
 - * 獲取glob掃描的文件列表
 - * @param {*} rootPath 跟路徑
 - * @param {*} extensions 擴(kuò)展
 - * @param {*} defalutIgnore 是否開啟默認(rèn)忽略
 - */
 - function getGlobScan(rootPath, extensions, defalutIgnore) {
 - return new Promise(resolve => {
 - glob(`${rootPath}${extensions}`,
 - { dot: true, ignore: defalutIgnore ? DEFAULT_IGNORE_PATTERNS : [] },
 - (err, files) => {
 - if (err) {
 - console.log(err);
 - process.exit(1);
 - }
 - resolve(files);
 - });
 - });
 - }
 - /**
 - * 加載ignore配置文件,并處理成數(shù)組
 - * @param {*} ignoreFileName
 - */
 - async function loadIgnorePatterns(ignoreFileName) {
 - const ignorePath = path.resolve(process.cwd(), ignoreFileName);
 - try {
 - const ignores = fs.readFileSync(ignorePath, 'utf8');
 - return ignores.split(/[\n\r]|\n\r/).filter(pattern => Boolean(pattern));
 - } catch (e) {
 - return [];
 - }
 - }
 - /**
 - * 根據(jù)ignore配置過(guò)濾文件列表
 - * @param {*} files
 - * @param {*} ignorePatterns
 - * @param {*} cwd
 - */
 - function filterFilesByIgnore(files, ignorePatterns, ignoreRules, cwd = process.cwd()) {
 - const ig = ignore().add([...ignorePatterns, ...ignoreRules]);
 - const filtered = files
 - .map(raw => (path.isAbsolute(raw) ? raw : path.resolve(cwd, raw)))
 - .map(raw => path.relative(cwd, raw))
 - .filter(filePath => !ig.ignores(filePath))
 - .map(raw => path.resolve(cwd, raw));
 - return filtered;
 - }
 
8. 基礎(chǔ)能力 - 代碼復(fù)雜度檢測(cè)
代碼復(fù)雜度檢測(cè)(c-complexity)源碼:https://github.com/ConardLi/a...
代碼檢測(cè)基礎(chǔ)包應(yīng)該具備以下幾個(gè)能力:
- 自定義掃描文件夾和類型
 - 支持忽略文件
 - 定義最小提醒代碼復(fù)雜度
 
8.1 使用
- npm i c-complexity --save
 - const cc = require('c-complexity');
 - cc({},10);
 
8.2 返回值
- fileCount:文件數(shù)量
 - funcCount:函數(shù)數(shù)量
 -  result:詳細(xì)結(jié)果
    
- funcType:函數(shù)類型
 - funcName;函數(shù)名稱
 - position:詳細(xì)位置(行列號(hào))
 - fileName:文件相對(duì)路徑
 - complexity:代碼復(fù)雜度
 - advice:重構(gòu)建議
 
 
8.3 參數(shù)
-  scanParam
    
- 繼承自上面代碼掃描的參數(shù)
 
 -  min
    
- 最小提醒代碼復(fù)雜度,默認(rèn)為1
 
 
9. 應(yīng)用 - 代碼復(fù)雜度檢測(cè)工具
代碼復(fù)雜度檢測(cè)(conard cc)源碼:https://github.com/ConardLi/a...
9.1 指定最小提醒復(fù)雜度
可以觸發(fā)提醒的最小復(fù)雜度。
- 默認(rèn)為 10
 - 通過(guò)命令 conard cc --min=5 自定義
 
9.2 指定掃描參數(shù)
自定義掃描規(guī)則
- 掃描參數(shù)繼承自上面的 scan param
 - 例如: conard cc --defalutIgnore=false
 
10. 應(yīng)用 - 代碼復(fù)雜度報(bào)告
部分截圖來(lái)源于我們內(nèi)部的項(xiàng)目質(zhì)量監(jiān)控平臺(tái),圈復(fù)雜度作為一項(xiàng)重要的指標(biāo),對(duì)于衡量項(xiàng)目代碼質(zhì)量起著至關(guān)重要的作用。
代碼復(fù)雜復(fù)雜度變化趨勢(shì)
定時(shí)任務(wù)爬取代碼每日的代碼復(fù)雜度、代碼行數(shù)、函數(shù)個(gè)數(shù),通過(guò)每日數(shù)據(jù)繪制代碼復(fù)雜度和代碼行數(shù)變化趨勢(shì)折線圖。
通過(guò) [ 復(fù)雜度 / 代碼行數(shù) ] 或 [ 復(fù)雜度 / 函數(shù)個(gè)數(shù) ] 的變化趨勢(shì),判斷項(xiàng)目發(fā)展是否健康。
- 比值若一直在上漲,說(shuō)明你的代碼在變得越來(lái)越難以理解。這不僅使我們面臨意外的功能交互和缺陷的風(fēng)險(xiǎn),由于我們?cè)诰哂谢蚨嗷蛏傧嚓P(guān)功能的模塊中所面臨的過(guò)多認(rèn)知負(fù)擔(dān),也很難重用代碼并進(jìn)行修改和測(cè)試。(下圖1)
 - 若比值在某個(gè)階段發(fā)生突變,說(shuō)明這段期間迭代質(zhì)量很差。(下圖2)
 
- 復(fù)雜度曲線圖可以很快的幫你更早的發(fā)現(xiàn)上面這兩個(gè)問(wèn)題,發(fā)現(xiàn)它們后,你可能需要重構(gòu)代碼。復(fù)雜性趨勢(shì)對(duì)于跟蹤你的代碼重構(gòu)也很有用。復(fù)雜性趨勢(shì)的下降趨勢(shì)是一個(gè)好兆頭。這要么意味著您的代碼變得更簡(jiǎn)單(例如,把 if-else 被重構(gòu)為多態(tài)解決方案),要么代碼更少(將不相關(guān)的部分提取到了其他模塊中)。(下圖3)
 - 代碼重構(gòu)后,你還需要繼續(xù)探索復(fù)雜度變化趨勢(shì)。經(jīng)常發(fā)生的事情是,我們花費(fèi)大量的時(shí)間和精力來(lái)重構(gòu),無(wú)法解決根本原因,很快復(fù)雜度又滑回了原處。(下圖4)你可能覺(jué)得這是個(gè)例,但是有研究標(biāo)明,在分析了數(shù)百個(gè)代碼庫(kù)后,發(fā)現(xiàn)出現(xiàn)這種情況的頻率很高。因此,時(shí)刻觀察代碼復(fù)雜度變化趨勢(shì)是有必要的。
 
代碼復(fù)雜度文件分布
統(tǒng)計(jì)各復(fù)雜度分布的函數(shù)數(shù)量。
代碼復(fù)雜度文件詳情
計(jì)算每個(gè)函數(shù)的代碼復(fù)雜度,從高到低依次列出高復(fù)雜度的文件分布,并給出重構(gòu)建議。
實(shí)際開發(fā)中并不一定所有的代碼都需要被分析,例如打包產(chǎn)物、靜態(tài)資源文件等等,這些文件往往會(huì)誤導(dǎo)我們的分析結(jié)果,現(xiàn)在分析工具會(huì)默認(rèn)忽略一些規(guī)則,例如:.gitignore文件、static目錄等等,實(shí)際這些規(guī)則還需要根據(jù)實(shí)際項(xiàng)目的情況去不斷完善,使分析結(jié)果變得更準(zhǔn)確。



































 
 
 









 
 
 
 