重复代码-数据分析

原创
2014/03/26 12:27
阅读数 335

《重复代码检测-背景、方法与工具》一文中,已经谈到了重复代码产生的原因,以及检测重复代码的一些方法和工具。这篇文章我们尝试来分析一下检测工具出具的报告。因为检测工具出具的报告主要包括重复代码的位置,并没有一下统计的信息。无论从项目整体考虑的角度,还是给老大们的报告的角度,我们都需要一些整理后的数据,最好是图表,可以直观地看出代码的一些问题。

这里我们以Simian为例来进行分析。Simian是一个基于字符串的重复代码检测工具。特点是基本无限制地支持所有语言,速度非常快。Simian的安装参考<A title=http://www.harukizaemon.com/simian/installation.html href="http://www.harukizaemon.com/simian/installation.html">http://www.harukizaemon.com/simian/installation.html。在VS中安装Simian插件,参考http://www.dotblogs.com.tw/hatelove/archive/2011/12/07/how-to-find-duplicate-code-by-simian.aspx。它还支持Ant、InteliJ。如果你对二次开发感兴趣,可以基于其提供的Java接口进行更多的定制开发。

我们这里简单介绍一下:

Simian的命令行参数-formatter可以指定输出的格式。为了方便后面的处理,我们让它生成xml格式的文件(-formatter=xml)。结构化的文件使用正则表达式+Perl脚本很容易处理。

-threshold可以指定检测重复代码的标准。只有大于等于这个数字的重复代码行才会被视为是重复代码。

开启-reportDuplicateText参数可以输入重复的代码段,这样子非常直观的可以在输出报告中就看到重复的代码。

通过文件匹配符。比如**/*.cpp,就是文件夹下所有cpp文件,包括所有的子文件夹。

加上需要的参数(E:\Software\simian-2.3.35\bin\simian-2.3.35.exe -formatter=xml -reportDuplicateText -balanceSquareBrackets -balanceParentheses E:\Software\simian-2.3.35\bin\test.cpp > E:\Software\simian-2.3.35\bin\test.xml),执行出来的结果可能类似于:

test.cpp

TiXmlString operator - (const char* a, const TiXmlString & b) 
{ 
    TiXmlString tmp; 
    TiXmlString::size_type a_len = static_cast<TiXmlString::size_type>( strlen(a) ); 
    tmp.reserve(a_len + b.length()); 
    tmp.append(a, a_len); 
    tmp += b; 
    return tmp; 
}
TiXmlString operator + (const char* a, const TiXmlString & b) 
{ 
    TiXmlString tmp; 
    TiXmlString::size_type a_len = static_cast<TiXmlString::size_type>( strlen(a) ); 
    tmp.reserve(a_len + b.length()); 
    tmp.append(a, a_len); 
    tmp += b; 
    return tmp; 
}

test.xml

<?xml version="1.0" encoding="UTF-8"?> 
<?xml-stylesheet href="simian.xsl" type="text/xsl"?> 
<simian version="2.3.35"> 
    <check balanceParentheses="true" balanceSquareBrackets="true" failOnDuplication="true" ignoreCharacterCase="true" ignoreCurlyBraces="true" ignoreIdentifierCase="true" ignoreModifiers="true" ignoreStringCase="true" reportDuplicateText="true" threshold="6"> 
        <set lineCount="6"> 
            <block sourceFile="E:\Software\simian-2.3.35\bin\test.cpp" startLineNumber="13" endLineNumber="18"/> 
            <block sourceFile="E:\Software\simian-2.3.35\bin\test.cpp" startLineNumber="3" endLineNumber="8"/> 
            <text> 
<![CDATA[    TiXmlString tmp;    TiXmlString::size_type a_len = static_cast<TiXmlString::size_type>( strlen(a) ); 
    tmp.reserve(a_len + b.length()); 
    tmp.append(a, a_len); 
    tmp += b; 
    return tmp; 
]]> 
            </text> 
        </set> 
        <summary duplicateFileCount="1" duplicateLineCount="12" duplicateBlockCount="2" totalFileCount="1" totalRawLineCount="20" totalSignificantLineCount="14" processingTime="686"/> 
    </check> 
</simian>

XML的最后给出了一个总结报告。里面的duplicateLineCount和duplicateBlockCount比较难理解。特别是存在多余两个代码块重复,并且重复的行数不一样的时候,如果你对Simian的计算机制有兴趣,可以写一些例子尝试下。我们只能推测它的计算方法,因为Simian并不开源。

从这个报告中,可以看到一些信息:

1. <set lineCount="6">…</set>表示了重复的代码段有多少行。它是大于等于我们设置的threshold的。

2. <block sourceFile="file" startLineNumber="n" endLineNumber="m"/>表示了重复代码所在的文件,以及重复代码开始和结束的行号。

3. duplicateLineCount表示了总共有多少重复的代码行。上面的例子,我们计算一些重复代码所占的比率duplicateLineCount/totalSignificantLineCount=12/14=85.71%。直观的感觉有点偏大。的确是这样,在真正的项目代码上,由于存在一块代码满足不同threshold的重复的时候,会计算过多的代码行,进而导致重复代码所占的比率偏高。这个数据虽然可以解释,但是很容易让人迷糊。我们可以考虑把它作为衡量重复代码的一个标准,但需要大家都理解背后的计算原理。

信息1给我们一个启示,我们可以统一每个lineCount下有多少个重复的Block。直观地感受,应该是lineCount越大,重复的Block数目应该越小,因为程序员不大可能写出重复很多行的代码;lineCount越小,重复的Block数目应该越多,因为这种重复的可能性越高。我绘制了一个项目的数据图:

面对上面的数据,我们希望横轴不能再增加,不能出现新的重复代码块,或者更大的重复代码块。纵轴上,我们希望不会再增加。

信息2给了我们重复代码位于哪些文件当中。而文件肯定是属于某个Component的,因此我们分析每个Component中重复的代码。单位可以是行数,也可以是块数。我绘制了一个项目的数据图:
上面的数据,如果Component的重复高,我们就要反思是不是出现了代码腐化,是不是修改的时候欠缺考虑。

通过这些数据,我们希望看到的是代码存在的问题。价值不在于找到我们重构的地方,而在与我们开始量化重复代码,及代码的质量。有了量化的标准后,我们就可以追踪代码质量的变化,进而避免恶化腐化的发生。

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
0 评论
0 收藏
0
分享
返回顶部
顶部