一次有趣的开发经历
周五下午和同事Pavan一起结对编程,为Cruise 1.2增加svn external的支持。几个小时过后,我们提交的代码漂亮地通过了所有的单元/集成/验收测试。在这个过程中,我觉得有一些很有趣的细节非常能体现出我们的工作方式,所以现在把它们列出来:
集体重构
我们的修改是以前一段时间项目里大伙凑在一起做的一些修改为基础而进行的。在Cruise项目上,我们有一个不成文的习惯,就是隔一段时间大伙就凑在会议室里,拿一台笔记本连上投影仪,找出一段写的不好的代码做集体重构。每次开始的时候会有人负责提出一个问题,例如一段写的很糟糕的代码,或者一个看上去很牵强的设计,然后大家一起集思广议想解决办法,并由一个人拿着电脑对着投影仪直接修改。在这个过程中有时候写代码的人思路会中断,这时就会有人抢过电脑来继续写。这种方法的效果非常不错,特别是当大伙不断对一个问题追问“为什么”的时候,往往会让我们原本非常狭窄的思路一下子拓宽起来。
分布式版本控制
Cruise选择Mercurial做为版本控制系统。大家在集体写了svn external的初始代码之后,在一台笔记本上留下了一个patch。我和Pavan要做的第一件事就是把这个patch迁移到我们工作所用的pair station上来。方法非常简单:首先把那个patch通过scp拿到本地来,然后运行hg qimport指定patch文件的存储路径就可以了。当然,还可以用hg pull把那台笔记本上的修改都pull过来,或者利用hg transplant把那个指定的版本pull过来。这几种方法都可以达到我们的目的。前一种操作多一些,但会把拿过来的patch加入到本地的 queue中,是我个人最习惯的用法;第二种操作很简单,但是有可能pull过来的修改过多;第三种操作简便,效率理想,只是并不会把拿来的patch加入到queue里,我们平时会穿插着使用。
工欲善其事,必先利其器
我们必须要在本地创建相应的测试环境才能验证svn external功能,但是我们并不想每次都手动地去svn co, svn propset, svn ci, svn up, svn propget…。这些重复的操作应该而且也非常适合加以自动化。解决办法非常有趣:我们在本地创建了一个新的目录,在里面写了几个shell脚本。第一个用于创建svn external环境,其中包括复制出一个用于测试的svn repository,把它check out到一个指定的客户端目录,在客户端目录里执行svn propset/ci来创建svn external,以及执行svn up来更新客户端目录。第二个脚本用来启动Cruise Server和Agent。第三个脚本用来停止Cruise Server和Agent。有了这几个脚本,我们就能非常方便高效地运行测试了。当然,我们没有忘记把这些脚本都提交到Cruise的 repository里去。
说到工具,我还要顺便提一下我们的开发环境。Cruise团队里的每一个pair除了各自拥有公司配发的笔记本以外,还共同拥有一台非常强大的开发机器(Core 2 Quad CPU * 4, 4G RAM),采用双24寸液晶显示器。操作系统用的是Ubuntu,开发工具用的是IntelliJ。这些强大而灵活的工具让我们能够最大程度地激发工作热情,提高工作效率。
测试,测试
我和Pavan在测试过程中发现了一个bug,凭经验我们很快找到了导致bug产生的一个方法。不过,我们并没有急于把它消灭掉,而是给现有的方法增加了一个测试。当然,这个测试是不通过的,所以我们接下来的目标就是改正代码,让测试通过。几分钟过后,我们消灭了bug,并且使得系统的测试覆盖率又小小地增加了一点。:)
持续集成与及时反馈
当我们通过了本地的所有单元和集成测试以后,就信心满满地把本地的提交push到了汇总的mercurial repository里,很快,我们自己UAT环境里的Cruise Server就检测出了这次代码提交,并且开始进行集成。我们的第一个stage是在Linux和Windows平台下并行运行所有的单元测试,然而这个 stage中的一个Windows job却在几分钟后失败了。通过阅读Cruise给出的失败信息,我们发现刚刚提交的代码没有考虑带空格的URI这一种情况,而这种情况在Windows 下非常常见。获得了这个反馈,我们接下来的工作就是在本地增加一个处理带空格的URI这种情况的测试,看它运行失败,然后修复,提交。不一会的功夫, Cruise显示所有测试全部通过!