終端代碼重複率檢測實踐

背景

當一個項目在不斷開發迭代、功能累加的過程當中,重複代碼的出現幾乎是不可避免的。其出現的緣由不外乎如下兩點:javascript

  • 複製粘貼:這多是形成代碼重複的最大因素,其緣由也有不少種,多是跨項目的代碼拷貝,多是相似功能的代碼拷貝。不管如何,這都違背了集中管理的原則,給後續的代碼維護增長了比較大的負擔。
  • 對項目不瞭解:新人加入、業務輪轉等緣由會讓開發人員面對一個全新的項目。這種陌生的狀況下,許多開發人員就會產生重複造輪子的問題,只顧着本身開發的部分,徹底沒考慮到項目原先的代碼情況。

因此對項目按期進行代碼率檢測是一個頗有意義的事,能夠幫助開發人員發現冗餘代碼,進行代碼抽象和重構。php

本文將介紹代碼重複率檢測的基本概念以及前端、客戶端項目中代碼重複率檢測的實踐過程。css

基本概念

在《Software Clone Detection and Refactoring》一文中,對重複代碼的類型進行了定義:html

  • 徹底一致的代碼或者只修改了空格和評論
  • 結構上和句法上一致的代碼,例如只是修改了變量名
  • 插入和刪除了部分代碼
  • 功能和邏輯上一致的代碼,語義上的拷貝

很明顯越日後,重複代碼檢測難度越大。在實際狀況中,咱們的檢測要求只要大體能知足前二者就已經足夠了。前端

在技術上,重複代碼檢測主要有如下分類:vue

  • 基於代碼行的
  • 基於標識符(token)的
  • 基於度量(metrics)的
  • 基於抽象語法樹(Abstract Syntax Tree)的
  • 基於程序依賴圖(Program Dependence Graph)的

這些技術細節不是本文關注的重點,有興趣的讀者能夠查閱相關論文進行詳細瞭解。java

前端代碼重複率檢測

工具

因爲前端源代碼文件格式多樣,重複率檢測除了源碼檢測之外,還能夠從檢測打包文件和文件退化角度考慮。node

檢測前端代碼重複率的工具備jsinspectjscpd,PMD-CPD(PMD's Copy/Paste Detector)中也支持js文件的重複率檢測。python

  • jsinspect工具支持js和jsx格式的文件,基於抽象語法樹,能夠檢測出結構相似的代碼塊
  • jscpd工具支持文件格式普遍,如java、oc、js、jsx、vue、ts、less等。其重複率斷定依據爲必定長度標識符的MD5值是否相同
  • PMD-CPD工具支持js文件檢測,也能夠本身開發擴展包來解析指定的語言:官方介紹

每一個工具各有其優缺點,若只須要檢測js或jsx文件,且對檢測結果要求較高,能夠選擇jsinspect或者PMD-CPD工具,若考慮檢測工具的通用性,能夠選擇jscpc工具。linux

通過分析

  • 檢測打包文件方案,如有多個打包文件,沒法區分跨文件的重複代碼是源代碼重複仍是因爲打包生成的,所以不太適合。
  • 文件退化方案,jsx文件轉換成js文件能夠進行檢測,但vue或less等包含css的文件格式沒法檢測。退化成純文本的檢測工具備商業收費的simian。

爲了適應多種前端代碼文件,本團隊目前選擇jscpd做爲前端代碼重複率檢測工具。對於重複率要求較嚴格的項目,可使用jsinspect針對js(x)文件進行進一步檢測。

使用方法

jscpd工具能夠在本地使用,也能夠集成在gulp中。

本地檢測

  1. npm安裝
npm install jscpd -g
複製代碼
  1. 在項目目錄配置.cpd.yaml文件,配置參考
#.cpd.yaml
languages:
 - javascript
 - typescript
 - jsx
 - vue
 - css
files:
 - 'src/**'
 - 'less/**'
exclude:
 - 'dist/**'
 - 'dest/**'
 - 'neurons/**'
 - 'node_modules/**'
 - 'test/**'
 - 'data/**'
 - 'css/**'
 - 'entries/**'
reporter: xml
xsl-href: '/Users/dianping/dp/f2e-cpd/reporters-xslt/simple.xsl'
limit: 100
min-tokens: 70
min-lines: 5
output: '/Users/dianping/dp/f2e-cpd/report-ecom-70.xml'
複製代碼

其中languages值對應的文件後綴以下:

TokenizerFactory.prototype.LANGUAGES = {
  javascript: ['js', 'es', 'es6'],
  typescript: ['ts', 'tsx'],
  jsx: ['jsx'],
  haxe: ['hx', 'hxml'],
  coffeescript: ['coffee'],
  ruby: ['rb'],
  php: ['php', 'phtml'],
  python: ['py'],
  css: ['less', 'css'],
  sass: ['scss'],
  java: ['java'],
  csharp: ['cs'],
  go: ['go'],
  clike: ['cpp', 'c', 'm', 'h'],
  htmlmixed: ['html', 'htm'],
  yaml: ['yaml', 'yml'],
  erlang: ['erl', 'erlang'],
  swift: ['swift'],
  xml: ['xml', 'xsl', 'xslt'],
  puppet: ['pp', 'puppet'],
  twig: ['twig'],
  vue: ['vue']
};
複製代碼
  1. 命令行工具 全部配置參數也能夠直接在終端命令行中以參數形式附加。

  2. 查看結果 執行jscpd命令行,在終端能夠看到簡要的重複代碼位置,以及總的重複率計算結果。指定verbose參數,能夠看到重複代碼塊。

jscpd支持輸出xml和json兩種格式的報告文件,爲了便於查看重複代碼塊,建議輸出xml格式文件,配置xsl模板後在瀏覽器中具備較高的可讀性。

  • xml格式 執行jscpd命令後,如有配置 output 參數,將會在指定地址生成文件。可用瀏覽器查看。 爲了便於閱讀,能夠配置 xsl-href 參數,指定xsl模板,應用對應模板的xml文件在瀏覽器中具備較高的可讀性,效果以下:
    xsl模板能夠本身編寫,官方github也提供了一份簡單的xsl文件。

gulp集成

  1. 安裝
npm install gulp-jscpd
複製代碼
  1. 使用 在gulp.js中添加如下任務,配置參考
var jscpd = require('gulp-jscpd');
gulp.task('jscpd', function() {
    return gulp.src([path.join(__dirname, 'src/**'), path.join(__dirname, 'less/**')])
        .pipe(jscpd({
            'min-lines' : 5,
            'min-tokens': 70,
            reporter    : 'xml',
            languages   : ['javascript', 'jsx', 'css'],
            output      : '/Users/dianping/dp/f2e-cpd/report-ecom-70.xml',
            verbose     : false,
            debug       : false,
            silent      : false,
            failOnError : false,
            'xsl-href'  : '/Users/dianping/dp/f2e-cpd/reporters-xslt/simple.xsl'
        }));
});
複製代碼
  1. 值得注意的是,failOnError配置項指定檢查完畢後是否拋出錯誤,默認true,會終止打包流程。在CI中,若不但願重複率檢查中止正常打包,應指定爲false。

客戶端代碼重複率檢測

工具

對於客戶端代碼而言,因爲有iOS和Android兩個平臺,因此須要考慮工具的通用性,必須支持objective-C和java兩種語言。

基於以上緣由,最後選擇的工具是PMD-CPD(PMD's Copy/Paste Detector)。此工具使用的是Karp-Rabin字符串匹配算法,支持gui,支持命令行,輸出格式支持text、xml、csv等,能夠很好的配合腳本語言進行二次開發,對重複率數據進行統計。

使用方法

  1. 從官網下載PMD工具,其中已經包含CPD,下載地址:官網地址
  2. 解壓後能夠在bin文件夾下看到對應的工具
  3. 以linux爲例,使用如下命令就能夠打開CPD工具的gui。
./run.sh cpdgui
複製代碼
  1. 若是須要配合自定義腳本使用,能夠選擇命令行工具,能夠指定相應的參數,例如tokens、目錄、語言、輸出格式等等。詳細的參數列表請參考官方文檔
./run.sh cpd --minimum-tokens 100 --files /usr/local/java/src/java --language java --format xml
複製代碼

思考

工具的使用自己是比較簡單的,更多的是針對不一樣項目進行相應的定製。可能須要考量的點有以下幾個:

  • tokens和有效率的平衡: tokens是工具的一個參數,能夠理解爲對重複代碼長度定義的標準。因此當tokens越小,檢查到的重複代碼數量更多、覆蓋面越大,但相應的有效率就會下降,產生較多的誤報狀況。反之則有效率較高,但覆蓋率就會相應下降,會有所遺漏。對tokens的選擇依賴於項目的語言、框架等因素,在工具使用初期能夠進行屢次測試比較肯定合適的tokens值。

  • 腳本定製:使用其餘腳本語言例如python、ruby等進行相應的定製,把代碼重複率檢查包裝成爲一個自動化工具。重複率檢查工具例如PMD-CPD自己也不具有統計功能,因此腳本還能夠幫助把最後的檢查結果進行量化。

  • 重複率標準:對於比較獨立、規模不大的項目,剛開始檢查時,5%多是一個比較合適的值。固然重複率標準的制定須要參考的因素有不少,例如tokens、項目、架構、時間等等。

參考文獻

Fontana F A, Zanoni M, Ranchetti A, et al. Software Clone Detection and Refactoring[J]. Isrn Software Engineering, 2013, 2013(2013).

相關文章
相關標籤/搜索