实践的一小步-代码质量的一大步

实践的一小步-代码质量的一大步
作者:Steven Hale December 14, 2007
翻译:ZhangV 2008-2-18
原文出自:DevX.com
原文链接:http://www.devx.com/Java/Article/36231/0/page/1

假设持续整合是你开发过程中很重要的一部,你也很想把代码覆盖检查并入你的自动构建过程.但是如何设定覆盖率目标呢?经验丰富的代码覆盖支持者会建议你75%,85%甚至100%.

通过对项目中的代码分析,我意识到需要设定比上述数据低得多的目标.我不想成为团队中的Cathcart上校(Josef Heller的小说<<第22条军规>>中的人物,因为每当部下已经达到当前的飞行任务次数时,他就会设定更高的任务次数,虽然Yossarian不断地完成飞行任务,但却似乎永远都无法完成这个总在变化的次数,小说中最后Yossarian开小差逃到瑞典-译者).

我选择增量改进的策略而不是专制的设定更高的目标.为了成功的执行这个策略,每次构建都必须达到比之前构建更高的覆盖率.通过每次一小步的提升,来最终提升代码质量.

以下介绍如何使用Cobertura和Apache Ant来实现这个增量改进.

单元测试,代码覆盖,持续整合
这三个概念已经被广泛的接受为最佳实践.事实上,大多数程序员知道他们必须要单元测试.如果你还不知道,让我来引用Google研发总监Peter Norvig的名言:

“如果你觉得不需要写单元测试,把所有原因写下来到一张纸上.仔细的揣摩这张纸.然后,扔掉这张纸开始写单元测试.”

但是谁来测试测试人员呢? 也就是说,你怎么来确认你写了足够的测试呢?这些是非常宝贵的信息,因为那些没有被测试覆盖到的代码正是最耗费你经历的地方.一个解决办法是使用代码覆盖工具,它们会告诉你有被测试代码的百分比,然后加入一个代码覆盖检查到你的持续构建过程.如果你的覆盖检查不通过,那么构建也该被认定为失败.

在我的增量改进策略中,我选择Cobertura是因为她4个定义完整而简单的ant任务扩展.其中之一 cobertura-check,当代码覆盖率没有达到要求是会认定构建失败.例如下面这个例子,当覆盖率小于80%时,Ant会认为构建是失败的:

<target name=”coverage_check”>
<cobertura-check totallinerate=”80″/>
</target name=”coverage_check”>

但是,你可以使用之前的覆盖率来作为当前检查的标准.通过几个Cobertura的任务以及两个核心的ant任务,你就可以达到这个目标.而不需要担心是否应该考量 代码行率(line rate),分支率(branch rate)或者其他的覆盖数据.你的目标是改进,而不是一个绝对的硬性指标.

创建一个XML格式的代码覆盖报表
创建好ant任务后,你可以加入增量覆盖率检查到你的构建脚本中,第一步是用cobertura-report任务创建一个覆盖率报表:

<cobertura-report format=”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任务来直接获取代码行率(line rate).但是这种做法有几个问题:
1.Cobertura的行率(line-rate)是十进制小鼠,但是cobertura-check是用整数形式的百分率
2.在一个实际的项目里,coverage.xml可能会很大,使用XmlProperty可能会造成内存不足的错误

我建议使用Ant的XSLT任务来获取你所需要的数据

<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的property任务读入这个属性文件中唯一的值total.line-rate:

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

注意:新的覆盖报表只有在覆盖检查通过时才生成.(覆盖率必须要高于前一次的构建)

记得要先执行coverage_report,然后执行coverage_check.实际开发中,你应该加入另一个covertura-report任务来生成HTML的报表.

跟踪改进率
一个附加的好处是你可以通过记录覆盖率数据到一个文件来跟踪改进率.通过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%.可喜的是,那些之前不情愿写测试的程序员现在也很自豪地看到项目的覆盖率提升.

敏捷开发的民主精神在于,每一个团队成员都可以为整个团队提出目标 – 通过写单元测试. 没有专制的目标,没有cathcart上校.

你也可以更进一步.把这种增量式改进策略用到其他的地方.

作者Steven Hale,工作与瑞典的Omegapoint AB咨询公司.有超过20年的系统开发经验.

关于”敏捷”

今天看到javaeye上的关于敏捷开发的讨论.大家还是没有一个共识,然后根据自己的背景和理解去互相驳斥. – 盲人摸象的感觉. – 这也是大多数国内大多数技术讨论区的情况.

有一句话记得比较清楚:对于一个项目,个体交互胜过过程规范
这应该是敏捷的粉丝说的,但是这句看似简单的话却包含很复杂的背景.
项目:什么规模的项目?
个体:什么样的个体?对个体有什么样的期望?
交互:什么类型的交互,怎样有效交互?
过程:那到底有还是没有?
规范:那到底是要还是不要?

简单的表示: 项目=ax个体+bx交互+cx过程+dx规范
而a,b,c,d就是每个人对上面那些问题的经验和理解.所以有的人是:

成功项目=超人个体+无交互+无过程+无规范

有的人是:
失败项目=超人个体+无效交互+cmmi+iso2000
或者
失败项目=普通个体+有效交互+agile+无规范

那失败到底是因为agile呢?还是cmmi?还是团队?总不能说,agile的时候就一定捆绑了超人程序员和有效交互吧,那还要agile干什么,我自己发明个process怕也照样成功.

敏捷本来就是从传统制造业的精益(lean)衍生到软件工程的概念.可能只是一个过程创新,可是却又很多人把它当成救命稻草,期望”以后敏捷了,就可以天天吃饺子了”…

关于敏捷开发我的经验是0.

Powered by ScribeFire.