三步教你改善Java代码质量
本文讨论了如何以递进的方式使用Apache Ant来改善我们的代码质量。并按着三步走的原则给出了具体的实现步骤。
一、充分利用单元测试、代码覆盖
单元测试、代码覆盖是最容易被接受和实现的方式。事实上,大多数开发人员都知道单元测试对他们很重要。在我们开始讨论这些东西之前,先看一下Google研究院主管Peter Norvig的一段话:“如果你认为你们不需要对自己的代码进行单元测试,那么就写在纸上写一所有的原因,并且仔细研究这张纸,然后扔了它,继续测试自己的程序吧”。看来Google也是非常推崇进行单元测试的。那么谁又来测试那么测试者呢?也就是说,我们怎么能验证对程序做了足够的测试呢?这是一个非常有价值的问题,因为那些未通过测试的程序才是我们更应该关注的地方。这个问题的一个解决方案就是使用代码覆盖工具,这种工具将告诉我们我们到底测试了多少代码(也就是被测试代码的百分比),然后使用一般的综合处理来合并覆盖核对结果。如果覆盖核对失败,那么我们建立应用程序的过程也就失败了。
对了本文所讨论的递增代码策略选择了代码覆盖工具Cobertura,这是由于它非常容易使用,而且拥有良好的定义格式,以及四个Ant任务接口。这些任务之一就是cobertura-check,当代码不能完成我们要求的覆盖率时,它就会失败。如下面的代码显示如果覆盖率未达到80%,Ant在建立工程时就会失败:
<target name="coverage_check">
<cobertura-check totallinerate="80"/>
</target name="coverage_check">
除了使用硬编码来指定这个覆盖率外,我们还可能以使用一个更容易建立的结果作为当前核对的覆盖率。我们可以通过使用两个核心Ant任务连接一对Cobertura任务来完成这个任务。并不不用担心各种覆盖率的具体的值。我们的目标是完成可测量的代码改善,而不是设置一个绝对的代码覆盖率。
在建立用于测试和运行我们的代码的targets后,我们可以将用于核对我们的建立脚本的增量覆盖率。第一步是使用一个cobertura报吿任务建立一个XML格式的覆盖报表。代码如下:
<cobertura-report format="xml"/>
下面是由一个cobertura报表任务产生的
coverage.xml
<?xml version="1.0"?>
<!DOCTYPE coverage SYSTEM "http://cobertura.sourceforge.net/xml/coverage-02.dtd">
<coverage line-rate="0.43612334801762115" branch-rate="0.48344370860927155" version="1.8" timestamp="1181043899853">
<sources>
<source>./src/java</source>
</sources>
<packages>
……
</packages>
</coverage>
现在要确保将这个文件保存在某个硬盘上,因为我们在后面会需要这个文件。
二、从报表中取出覆盖率
一开始,我们可以试着使用Ant的XmlProperty任务来直接获得这个覆盖率,并给一个Ant属性。但是这个方法有以下两个问题:
1. 在coverage.xml中的覆盖率是一个小数,但当核对任务时需要一个整数百分比。
2. 在实际的项目中,coverage.xml的文件尺寸非常大,如果在Java中尝试使用XmlProperty任务时可能会出现Java OutOfMemoryError错误。而我们只想从coverage.xml文件中获得以下的内容:
<xslt in="coverage.xml" out="build/coverage.properties" style="src/xsl/coverage.xsl" />
上面的简单的XSL模板需要产生一个只包含我们需要的值的属性文件,内容如下:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" omit-xml-declaration="yes"/>
<xsl:template match="coverage">
total.line-rate=
<xsl:value-of select="floor(@line-rate*100)"/>
</xsl:template>
</xsl:stylesheet>
要注意的是方法floor(@line-rate*100),可以将小数覆盖率转换为整型覆盖率。最终结果是一个只包含下面一行的coverage.properties文件:
total.line-rate=44
现在我们可以使用Ant的属性任务来从coverage.properties读取这个Ant属性所需要的覆盖率:
<property file="build/coverage.properties" />
最后,我们可以将最初的"80"使用新的Ant属性替换,代码如下:
<cobertura-check totallinerate="${total.line-rate}"/>
三、将内容放到一起
最后的build.xml文件看上去的形似如下:
<target name="coverage_check" depends="check_against_previous_rate">
<antcall target="coverage_report"/>
</target>
<target name="coverage_report">
<cobertura-report format="xml" destdir="." />
</target>
<target name="check_against_previous_rate" depends="coverage_xml_to_properties">
<property file="build/coverage.properties" />
<cobertura-check totallinerate="${coverage.line-rate}" />
</target>
<target name="coverage_xml_to_properties">
<xslt in="coverage.xml" out="build/coverage.properties" style="src/xsl/coverage.xsl" />
</target>
要注意一个新的覆盖报告仅仅当覆盖核对被通过后才能被产生,也就是说,每次提高覆盖率后,都会比上一次建立的代码质量有所提高。
四、改善跟踪率的其他方法
还有一些递增地改善代码质量的方法是通过将覆盖率记录到文件中来跟踪代码改善率。我们可以通过Ant的echo任务建立如下的代码:
<target name="time">
<tstamp>
<format property="date.time" pattern="yyyy-MM-dd HH:mm"/>
</tstamp>
</target>
<target name="log" depends="time">
<echo file="${history.txt}" append="true">
${date.time};total.line-rate;${total.line-rate}
</echo>
</target>
五、结果可测量、改善可视化
经过对一个工程的测试,在这个工作使用本文所提供的策略后的一周内定,这个工程的代码质量改善了超过30%.而更另人兴奋的是以前开发人员都不需要对代码进行测试,而现在它们会为通过测试而使他们的代码质量的提高感到骄傲。
当然,我们不需要只停留在本文所介绍的方法和理论上。我们也可以将增量改善策略用在其他的代码规则中。因为大多数的代码核对工具都可以产生基于XML格式的输出,我们可以使用XSL模板来过滤出与之相关的代码规则,并将这些规则作为当前的代码核对工具的输入。
一、充分利用单元测试、代码覆盖
单元测试、代码覆盖是最容易被接受和实现的方式。事实上,大多数开发人员都知道单元测试对他们很重要。在我们开始讨论这些东西之前,先看一下Google研究院主管Peter Norvig的一段话:“如果你认为你们不需要对自己的代码进行单元测试,那么就写在纸上写一所有的原因,并且仔细研究这张纸,然后扔了它,继续测试自己的程序吧”。看来Google也是非常推崇进行单元测试的。那么谁又来测试那么测试者呢?也就是说,我们怎么能验证对程序做了足够的测试呢?这是一个非常有价值的问题,因为那些未通过测试的程序才是我们更应该关注的地方。这个问题的一个解决方案就是使用代码覆盖工具,这种工具将告诉我们我们到底测试了多少代码(也就是被测试代码的百分比),然后使用一般的综合处理来合并覆盖核对结果。如果覆盖核对失败,那么我们建立应用程序的过程也就失败了。
对了本文所讨论的递增代码策略选择了代码覆盖工具Cobertura,这是由于它非常容易使用,而且拥有良好的定义格式,以及四个Ant任务接口。这些任务之一就是cobertura-check,当代码不能完成我们要求的覆盖率时,它就会失败。如下面的代码显示如果覆盖率未达到80%,Ant在建立工程时就会失败:
<target name="coverage_check">
<cobertura-check totallinerate="80"/>
</target name="coverage_check">
除了使用硬编码来指定这个覆盖率外,我们还可能以使用一个更容易建立的结果作为当前核对的覆盖率。我们可以通过使用两个核心Ant任务连接一对Cobertura任务来完成这个任务。并不不用担心各种覆盖率的具体的值。我们的目标是完成可测量的代码改善,而不是设置一个绝对的代码覆盖率。
在建立用于测试和运行我们的代码的targets后,我们可以将用于核对我们的建立脚本的增量覆盖率。第一步是使用一个cobertura报吿任务建立一个XML格式的覆盖报表。代码如下:
<cobertura-report format="xml"/>
下面是由一个cobertura报表任务产生的
coverage.xml
<?xml version="1.0"?>
<!DOCTYPE coverage SYSTEM "http://cobertura.sourceforge.net/xml/coverage-02.dtd">
<coverage line-rate="0.43612334801762115" branch-rate="0.48344370860927155" version="1.8" timestamp="1181043899853">
<sources>
<source>./src/java</source>
</sources>
<packages>
……
</packages>
</coverage>
现在要确保将这个文件保存在某个硬盘上,因为我们在后面会需要这个文件。
二、从报表中取出覆盖率
一开始,我们可以试着使用Ant的XmlProperty任务来直接获得这个覆盖率,并给一个Ant属性。但是这个方法有以下两个问题:
1. 在coverage.xml中的覆盖率是一个小数,但当核对任务时需要一个整数百分比。
2. 在实际的项目中,coverage.xml的文件尺寸非常大,如果在Java中尝试使用XmlProperty任务时可能会出现Java OutOfMemoryError错误。而我们只想从coverage.xml文件中获得以下的内容:
<xslt in="coverage.xml" out="build/coverage.properties" style="src/xsl/coverage.xsl" />
上面的简单的XSL模板需要产生一个只包含我们需要的值的属性文件,内容如下:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" omit-xml-declaration="yes"/>
<xsl:template match="coverage">
total.line-rate=
<xsl:value-of select="floor(@line-rate*100)"/>
</xsl:template>
</xsl:stylesheet>
要注意的是方法floor(@line-rate*100),可以将小数覆盖率转换为整型覆盖率。最终结果是一个只包含下面一行的coverage.properties文件:
total.line-rate=44
现在我们可以使用Ant的属性任务来从coverage.properties读取这个Ant属性所需要的覆盖率:
<property file="build/coverage.properties" />
最后,我们可以将最初的"80"使用新的Ant属性替换,代码如下:
<cobertura-check totallinerate="${total.line-rate}"/>
三、将内容放到一起
最后的build.xml文件看上去的形似如下:
<target name="coverage_check" depends="check_against_previous_rate">
<antcall target="coverage_report"/>
</target>
<target name="coverage_report">
<cobertura-report format="xml" destdir="." />
</target>
<target name="check_against_previous_rate" depends="coverage_xml_to_properties">
<property file="build/coverage.properties" />
<cobertura-check totallinerate="${coverage.line-rate}" />
</target>
<target name="coverage_xml_to_properties">
<xslt in="coverage.xml" out="build/coverage.properties" style="src/xsl/coverage.xsl" />
</target>
要注意一个新的覆盖报告仅仅当覆盖核对被通过后才能被产生,也就是说,每次提高覆盖率后,都会比上一次建立的代码质量有所提高。
四、改善跟踪率的其他方法
还有一些递增地改善代码质量的方法是通过将覆盖率记录到文件中来跟踪代码改善率。我们可以通过Ant的echo任务建立如下的代码:
<target name="time">
<tstamp>
<format property="date.time" pattern="yyyy-MM-dd HH:mm"/>
</tstamp>
</target>
<target name="log" depends="time">
<echo file="${history.txt}" append="true">
${date.time};total.line-rate;${total.line-rate}
</echo>
</target>
五、结果可测量、改善可视化
经过对一个工程的测试,在这个工作使用本文所提供的策略后的一周内定,这个工程的代码质量改善了超过30%.而更另人兴奋的是以前开发人员都不需要对代码进行测试,而现在它们会为通过测试而使他们的代码质量的提高感到骄傲。
当然,我们不需要只停留在本文所介绍的方法和理论上。我们也可以将增量改善策略用在其他的代码规则中。因为大多数的代码核对工具都可以产生基于XML格式的输出,我们可以使用XSL模板来过滤出与之相关的代码规则,并将这些规则作为当前的代码核对工具的输入。