背景

当一个项目在不断开发迭代、功能累加的过程中,重复代码的出现几乎是不可避免的。其出现的原因不外乎以下两点:

复制粘贴:这可能是造成代码重复的最大因素,其原因也有很多种,可能是跨项目的代码拷贝,可能是类似功能的代码拷贝。无论如何,这都违背了集中管理的原则,给后续的代码维护增加了比较大的负担。

对项目不了解:新人加入、业务轮转等原因会让开发人员面对一个全新的项目。这种陌生的情况下,许多开发人员就会产生重复造轮子的问题,只顾着自己开发的部分,完全没考虑到项目原先的代码状况。

所以对项目定期进行代码率检测是一个很有意义的事,可以帮助开发人员发现冗余代码,进行代码抽象和重构。

本文将介绍代码重复率检测的基本概念以及前端、客户端项目中代码重复率检测的实践过程。

基本概念

在《Software Clone Detection and Refactoring》一文中,对重复代码的类型进行了定义:

完全一致的代码或者只修改了空格和评论

结构上和句法上一致的代码,例如只是修改了变量名

插入和删除了部分代码

功能和逻辑上一致的代码,语义上的拷贝

很明显越往后,重复代码检测难度越大。在实际情况中,我们的检测要求只要大致能满足前两者就已经足够了。

在技术上,重复代码检测主要有以下分类:

基于代码行的

基于标识符(token)的

基于度量(metrics)的

基于抽象语法树(Abstract Syntax Tree)的

基于程序依赖图(Program Dependence Graph)的

这些技术细节不是本文关注的重点,有兴趣的读者可以查阅相关论文进行详细了解。

前端代码重复率检测

工具

由于前端源代码文件格式多样,重复率检测除了源码检测以外,还可以从检测打包文件和文件退化角度考虑。

检测前端代码重复率的工具有jsinspect、jscpd,PMD-CPD(PMD's Copy/Paste Detector)中也支持js文件的重复率检测。

jsinspect工具支持js和jsx格式的文件,基于抽象语法树,可以检测出结构类似的代码块

jscpd工具支持文件格式广泛,如java、oc、js、jsx、vue、ts、less等。其重复率判定依据为一定长度标识符的MD5值是否相同

PMD-CPD工具支持js文件检测,也可以自己开发扩展包来解析指定的语言:官方介绍

每个工具各有其优缺点,若只需要检测js或jsx文件,且对检测结果要求较高,可以选择jsinspect或者PMD-CPD工具,若考虑检测工具的通用性,可以选择jscpc工具。

经过分析

检测打包文件方案,若有多个打包文件,无法区分跨文件的重复代码是源代码重复还是由于打包生成的,因此不太适合。

文件退化方案,jsx文件转换成js文件可以进行检测,但vue或less等包含css的文件格式无法检测。退化成纯文本的检测工具有商业收费的simian。

为了适应多种前端代码文件,本团队目前选择jscpd作为前端代码重复率检测工具。对于重复率要求较严格的项目,可以使用jsinspect针对js(x)文件进行进一步检测。

使用方法

jscpd工具可以在本地使用,也可以集成在gulp中。

本地检测

npm安装

npm install jscpd -g

复制代码在项目目录配置.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']

};

复制代码命令行工具

所有配置参数也可以直接在终端命令行中以参数形式附加。

查看结果

执行jscpd命令行,在终端可以看到简要的重复代码位置,以及总的重复率计算结果。指定verbose参数,可以看到重复代码块。

jscpd支持输出xml和json两种格式的报告文件,为了便于查看重复代码块,建议输出xml格式文件,配置xsl模板后在浏览器中具有较高的可读性。

xml格式

执行jscpd命令后,若有配置 output 参数,将会在指定地址生成文件。可用浏览器查看。

为了便于阅读,可以配置 xsl-href 参数,指定xsl模板,应用对应模板的xml文件在浏览器中具有较高的可读性,效果如下:

xsl模板可以自己编写,官方github也提供了一份简单的xsl文件。

gulp集成

安装

npm install gulp-jscpd

复制代码使用

在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'

}));

});

复制代码值得注意的是,failOnError配置项指定检查完毕后是否抛出错误,默认true,会终止打包流程。在CI中,若不希望重复率检查停止正常打包,应指定为false。

客户端代码重复率检测

工具

对于客户端代码而言,由于有iOS和Android两个平台,所以需要考虑工具的通用性,必须支持objective-C和java两种语言。

基于以上原因,最后选择的工具是PMD-CPD(PMD's Copy/Paste Detector)。此工具使用的是Karp-Rabin字符串匹配算法,支持gui,支持命令行,输出格式支持text、xml、csv等,可以很好的配合脚本语言进行二次开发,对重复率数据进行统计。

使用方法

从官网下载PMD工具,其中已经包含CPD,下载地址:官网地址

解压后可以在bin文件夹下看到对应的工具

以linux为例,使用以下命令就可以打开CPD工具的gui。

./run.sh cpdgui

复制代码如果需要配合自定义脚本使用,可以选择命令行工具,可以指定相应的参数,例如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).

代码重复率PHP,终端代码重复率检测实践相关推荐

  1. java代码如何降低重复率_影响网站跳出率的主要因素及如何降低网站跳出率?...

    网站跳出率和停留时间,也是百度作为综合数据考核的标准之一.通常情况下,网站的跳出率越低越好.那么今天就和大家分享一下"网站跳出率". 首先"影响网站跳出率的因素" ...

  2. (保守群组测试 非保守群组测试 二次重复测试 自适应二次重复测试)四种群体测试的C++代码

    目录 原理 保守组检测 非保守组检测 二次重复测试 自适应二次重复测试 四种测试方法的核心代码 保守群组测试 非保守群组测试 二次重复测试与自适应二次重复测试 测试代码 参考文献 原理 假设该病在人群 ...

  3. 顺序表删除重复元素(完整代码的实现)

    [问题描述] 设一顺序表有若干元素,编写程序实现删除表中值重复的元素,即重复元素只保留一个. [输入形式] 第一行输入一个N(N不大于100),表示顺序表的长度: 第二行输入N个整数,表示顺序表元素: ...

  4. java treeset 重复_TreeSet判断重复元素解析及代码示例

    TreeSet的底层是TreeMap的keySet(),而TreeMap是基于红黑树实现的,红黑树是一种平衡二叉查找树,它能保证任何一个节点的左右子树的高度差不会超过较矮的那棵的一倍. TreeMap ...

  5. JS流程控制语句 反反复复(while循环) 和for循环有相同功能的还有while循环, while循环重复执行一段代码,直到某个条件不再满足。...

    反反复复(while循环) 和for循环有相同功能的还有while循环, while循环重复执行一段代码,直到某个条件不再满足. while语句结构: while(判断条件) {循环语句} 使用whi ...

  6. 终于可以向重复的鉴权代码说byebye 了 -- (玩转 AOP和Annotation )

    缘起 最近在写代码时,不可避免的会写成出进行大量的鉴权逻辑. 如下面代码所示,每一个方法都要添加一个鉴权逻辑(样例只有4个方法,实际工作中会很多) class Action{public void g ...

  7. Excel中删除重复数据(用VBA代码)

    请仔细阅读并修改相关数据.我推荐使用第二种方法,是我修改的,很好用,第三种情况用得比较少.  第一种情况保留不重复的记录行,重复的只保留一行. 1.打开有重复数据的EXCEL 2.Alt+F11 打开 ...

  8. python广告刷量_用python实现刷点击率的示例代码

    背景 同事的老爸参加微信的一个活动,需要刷点击率,因此,写了一个程序助之. 准备 微信活动也是有真实地址的. 通过mitmproxy(man in the middle proxy)的方式,可以获取微 ...

  9. php mysql 重复提交数据_如何真正解决表单重复提交问题php代码

    如何真正解决表单重复提交问题php代码 过去一切时代的精华尽在书中.以下是小编为大家搜索整理的如何真正解决表单重复提交问题php代码,希望能给大家带来帮助!更多精彩内容请及时关注我们应届毕业生考试网! ...

最新文章

  1. 工业机器人发展现状:硬件制造大同小异,视觉感知绘新蓝图
  2. iframe内容 固定比例_允知研习|浅析固定总价合同的结算问题
  3. 转发高人文章:以前写的一些有关代码签名/时间戳数字证书的东东
  4. 最小割板子题——[USACO5.4]奶牛的电信
  5. spring容器的设值注入和构造注入
  6. 4g模块注册上网 移远_Openwrt支持移远4G模块过程记录
  7. 使用fetch封装请求_关于如何使用Fetch API执行HTTP请求的实用ES6指南
  8. 华为鸿蒙系统明年8月份,华为鸿蒙系统明年上线,力争第五大操作系统,能否成功?...
  9. linux 背光驱动程序,Linux驱动工程师成长之路 LCD背光控制RT9379B
  10. Domino中运用ajax判断帐号是否存在的简单例子
  11. 《全球科技通史》吴军老师-读书摘录
  12. python实现QQ空间自动点赞功能
  13. 织梦css分页样式写在哪,DEDECMS列表分页样式css代码
  14. Python机器学习:一元回归
  15. available: expected at least 1 bean which qualifies as autowire candidate
  16. 五行中的土在哪个方位_五行代表的方位
  17. 基础集合论 第一章 集合与集合的运算
  18. 易经八卦解释鸿蒙,易经入门:如何记住八卦的8个符号,理解意思之后,就会很简单...
  19. Python脚本爬取网站美女照片
  20. C语言静态链接库的制作和使用

热门文章

  1. 【收藏】详解FIR滤波器和IIR滤波器的区别
  2. 基于Java的超市管理系统源码,数据库MySQL(附加论文13000字)
  3. 国产运维工具Commander
  4. Redis-cli常用命令
  5. java八种基础数据结构_8种常见数据结构及其Javascript实现
  6. 【信号与系统】笔记(5-3)逆 z 变换
  7. 虚拟机中安装Ubuntu,详细教程
  8. AWVS 网页漏洞扫描工具安装使用(Linux)
  9. potplayer播放器没有声音、下载不了解码器?
  10. codeblock主题颜色配置