13
我们怎样组合使用 Scrum和XP
要说组合使用Scrum和XP(极限编程)可以带来累累硕果,这毫无争议。我在网上看到过的绝大多数资料都证实了这一点,所以我不会花时间去讨论为什么要这么做。
不过,我还是会提到一点。Scrum注重的是管理和组织实践,而XP关注的是实际的编程实践。这就是为什么它们可以很好地协同工作——它们解决的是不同领域的问题,可以互为补充,相得益彰。
所以,我在这里要向现有的实践证据中加上我自己的声音:组合使用Scrum和XP会有显著收获!
下面我会着重讲述XP中最有价值的一些实践,以及我们在每日工作中的应用方式。我们的团队并没有全都把所有的实践都试过一遍,但总的来说,在绝大多数层面上组合使用XP与Scrum,我们都已经尝试过了。有些XP实践直接被Scrum解决掉了,可以被视作二者的重叠。如“整体团队”,“坐在一起”,“故事”和“计划游戏”。在这些情况下我们就直接使用了Scrum。
结对编程
sprint之后,我已经有了很高的热情去指导其他团队进行试用。我们近来开始在一个团队中实施结对编程。效果相当好。虽然其他团队大多数还没有进行太多尝试,但在一个团队中使用了几个
下面是到目前为止有关结对编程的一些结论:
- 结对编程可以提高代码质量。
- 结对编程可以让团队的精力更加集中(比如坐在你后面的那个人会提醒你,“嘿,这个东西真的是这个sprint必需的吗?”)。
- 令人惊奇的是,很多强烈抵制结对编程的开发人员根本就没有尝试过,而一旦尝试之后就会迅速喜欢上它。
- 结对编程令人精疲力竭,不能全天都这样做。
- 常常更换结对是有好处的。
- 结对编程可以增进团队间的知识传播。速度快到令人难以想象。
- 有些人就是不习惯结对编程。不要因为一个优秀的开发人员不习惯结对编程就把他置之不理。
- 可以把代码审查作为结对编程的替代方案。
- “领航员”(不用键盘的家伙)应该自己也有一台机器。不是用来开发,而是在需要的时候稍稍做一些探索尝试、当“司机”(使用键盘的家伙)、遇到难题的时候查看文档,等等。
- 不要强制大家使用结对编程。鼓励他们,提供合适的工具,让他们按照自己的节奏去尝试。
测试驱动开发(TDD)
阿门!对我来说,它比Scrum和XP还要重要。你可以拿走我的房子、我的电视还有我的狗,但不要试着让我停止使用TDD!如果你不喜欢TDD,那就别让我进入你的地盘,不然我一定会想方设法来偷摸着干的:o)
下面是有关TDD的一个10秒钟总结:
测试驱动开发意味着你要先写一个自动测试,然后编写恰好够用的代码,让它通过这个测试,接着对代码进行重构,主要是提高它的可读性和消除重复。整理一下,然后继续。
人们对测试驱动开发有着各种看法:
- TDD很难。开发人员需要花上一定时间才能掌握。实际上,往往问题并不在于你用了多少精力去教学、辅导和演示——多数情况下,开发人员掌握它的唯一方式就是跟一个熟悉TDD的人一起结对编程,一旦掌握以后,他就会受到彻底的影响,从此再也不想使用其它方式工作。
- TDD对系统设计的正面影响特别大。
- 在新产品中,需要过上一段时间,TDD才能开始应用并有效运行,尤其是黑盒集成测试。但是回报来得非常快。
- 投入足够的时间,来保证大家可以很容易地编写测试。这意味着要有合适的工具、有经验的人、提供合适的工具类或基类,等等。
-
我们在测试驱动开发中使用了如下工具:
- jUnit / httpUnit / jWebUnit。我们正在考虑使用TestNG和Selenium.
- HSQLDB用作嵌入式的内存数据库,在测试中使用。
- Jetty用作嵌入式的内存Web容器,在测试中使用。
- Cobertura用来度量测试覆盖率。
- Spring框架用来织入不同类型的测试装置(带有mock、不带mock、带有外部数据库或带有内存数据库等等)。
在我们那些经验最丰富的产品中(从TDD的视角来看),都有自动化的黑盒验收测试。这些测试会在内存中启动整个系统,包括数据库和Web服务器,然后只通过系统的公共接口进行访问(例如HTTP)。
它会把开发-构建-测试这三者构成的循环变得奇快无比,同时还可以充当一张安全网,让开发人员有足够的信心频繁重构,伴随着系统的增长,设计依然可以保持整洁和简单。
我们在所有的全新开发过程中都使用TDD,即便这会在开始时延长项目配置时间(因为我们需要更多的工具,并为测试装备提供支在新代码上进行TDD
持等等)。其实用脚指头思考也可以知道,TDD带来的好处如此之大,还有什么理由可以不用它呢。
在旧代码上进行TDD
TDD是很难,但是在一开始没有用TDD进行构建的代码库上实施TDD......则是难上加难!为什么?嗯,实际上,就这个话题我可以写上许多页,所以我想最好到此为止。也许我会在我的下一个论文“硝烟中的TDD”中进行解释:o)
我们曾花了大量的时间,在一个比较复杂的系统上进行自动化集成测试,它的代码库已经存在很长时间了,处于极度混乱的状态,一丁点的测试代码都没有。
每次发布之前,都有一个由专门的测试人员组成的团队,来进行大批量的、复杂的回归测试和性能测试。那些回归测试大多数都是手工进行。我们的开发和发布周期就这样被严重延误了。我们的目标是将这些测试自动化,但是几个月的痛苦煎熬以后,仍然没有取得多少进展。
之后我们改变了方式。首先承认自己已经陷入了手工回归测试的泥潭,然后再来问自己:“怎么让手工回归测试消耗的时间更少呢?”当时开发的是一个赌博系统,我们意识到:测试团队在非常琐碎的配置任务上花费了大量的时间。例如浏览后台并创建牌局来测试,或者等待一个安排好的牌局启动。所以我们特地创建了一些实用工具。这些快捷方式和脚本很小,而且使用方便。它们可以完成那些乱七八糟的工作,让测试人员专注真正的测试。
这些付出确实收到了成效!实际上,我们的确应该从一开始就这样做。当初太急于将测试自动化了,都忘了应该一步一步走。刚开始应该想办法提高手工测试的效率。
学到的一课:如果你深陷手工回归测试的泥潭,打算让它自动化执行,最好还是放弃吧(除非做起来特别简单)。首先还是应该想办法简化手工回归测试。然后再考虑将真正的测试变成自动化执行。
增量设计
这表示一开始就应该保持设计简单化,然后不断进行改进;而不是一开始努力保证它的正确性,然后就冻结它,不再改变。
在这一点上我们做的相当好,我们用了大量的时间来做重构,改进既有设计,而几乎没用什么时间来做大量的预先设计。有时候我们当然也会出错,例如允许一个不稳定的设计“陷入”太深,以至于后来代码重构成了一个大问题。不过总体来看我们都是相当满意的。
持续的设计改进,这在很大程度上是TDD自动带来的成果。
持续集成
我们的大多数产品在持续集成方面都已经很成熟了,它们是基于Maven和QuickBuild的。这样做很管用,而且节省了我们大量时间。对于 “哎,它在我的电脑上没有问题”这样的老问题,持续集成也是终极解决方案。要判断所有代码库的健康状况,可以用持续构建服务器充当“法官”或是参考点。每次有人向版本控制系统中check in东西,持续构建服务器就会醒来,在一个共享服务器上从头构建一切,运行所有测试。如果出现问题,它就会向整个团队发送邮件告知大家构建失败,在邮件中会包括有哪些代码的变化导致构建失败的精确细节,指向测试报告的链接等。
每天晚上,持续构建服务器都会从头构建产品,并且向我们的内部文档门户上发布二进制文件(ears,wars等)、文档、测试报告、测试覆盖率报告和依赖性分析报告等等。有些产品也会被自动部署到测试环境中。
把这一切搭建起来需要大量工作,但付出的每一分钟都物有所值。
代码集体所有权
我们鼓励代码集体所有权,但并不是所有团队都采取了这种方式。我们发现:在结对编程中频繁交换结对,会自动把代码集体所有权提到一个很高的级别。我们已经证实,如果团队拥有高度的代码集体所有权,这个团队就会非常健壮,比如某些关键人物生病了,当前的sprint也不会因此嗝屁朝凉。
充满信息的工作空间
所有团队都可以有效利用白板和空的墙壁空间。很多房间的墙上都贴满了各种各样关于产品和项目的信息。这样做最大的问题,就是那些旧的作废信息也堆在墙上,也许我们应该在每个团队中引入一个“管家”的角色。
我们鼓励使用任务板,但是并不是所有团队都采用了它。参见“我们怎样布置团队空间”。
代码标准
不久前我们开始定义代码标准。它的用处很大,要是我们早就这样做就好了。引入代码标准几乎没花多少时间,我们只是一开始从简单入手,让它慢慢增长。只需要写下不是所有人都了如指掌的事情,并尽可能加上对外部资料的链接。
绝大多数程序员都有他们自己特定的编程风格。例如他们如何处理异常,如何注释代码,何时返回null等等。有时候这种差异没什么关系,但在某些情况下,系统设计就会因此出现不一致的现象,情况严重,代码也不容易看懂。这时代码标准的用处就会凸显,从造成影响的因素中就可以知道了。
下面是我们代码标准中的一些例子:
- 你可以打破这里的任一规则,不过一定要有个好理由,并且记录下来。
- 默认使用Sun的代码惯例:http://java.sun.com/docs/codeconv/html/CodeConvTOC.doc.html
- 永远,永远,永远不要在没有记录堆栈跟踪信息(stacktrace)或是重新抛出异常的情况下捕获异常。用log.debug()也不错,只要别丢失堆栈跟踪信息就行。
- 使用基于setter方法的依赖注入来将类与类解耦(当然,如果紧耦合可以令人满意的话就另当别论)。
- 避免缩写。为人熟知的缩写则可以,例如DAO。
- 需要返回Collections或者数组的方法不应该返回null。应该返回空的容器或数组,而不是null。
可持续的开发速度/精力充沛的工作
很多有关敏捷软件开发的书都声称:加班工作在软件开发中会降低生产率。
经过几次不情愿的试验之后,我完全拥护这种说法!
大约一年以前,我们中有一个团队(最大的团队)在疯狂加班。现存代码库的质量惨不忍睹,他们不得不投入绝大多数的时间来救火。测试团队(同样也在加班)根本没时间来认真地做质量保证工作。我们的用户很生气,小道流言也快把我们活活吞掉了。
几个月后,我们成功地把大家的工作时间缩短到了适当的范围。他们正常上下班(除了有时候在项目关键期要加班以外)。令人惊异的是,生产率和质量都取得了显著提高。
当然,减少工作时长绝不是带来改进的唯一因素,但我们都确信它的影响很大。