(本文发表于《程序员》2006年第6期)
也许由于软件行业固有的“高科技”特性(或者说,软件人固有的顾影自怜),软件项目的管理和过程控制中从来就不缺少形形色色的工具。在一些大型的、“正规的”软件企业中,配置管理要通过ClearCase,软件设计要使用Rose画出一大堆精美的图形,压力测试要用LoadRunner来跑……当软件公司的老板们痴迷于“形式化管理”与漂亮的报表和文档时,这些昂贵的商业工具着实在他们那里得到了不少的青睐。
幸运的是,越来越多的软件开发者和老板开始意识到,软件项目采用的方法没有一定之规,不同的项目、不同的团队需要选择不同的开发方法。而工具,则如同三棱镜般折射出方法学的身影——用着微软的TeamSystem就很难不遵循微软推荐的最佳实践,同样RUP在没有Rational工具支持的情况下也难以实施。于是,选择开发过程工具,很大程度上就成了选择开发方法的一个副产品。
对于身处激烈需求变更风暴之中的企业应用开发者,如何步步紧跟客户的真实需求、如何确保时刻为客户提供最大价值是他们每天冥思苦想的问题。此时注重交流反馈、以客户价值为驱动的各种敏捷开发方法就成为了他们自然而然的选择。而有趣的是,开源的过程工具也大多与敏捷方法最为适应。看似偶然,其实却有其道理:开源项目更少受到种种政治因素的影响,生存的环境又有更多的不确定性,因此也更加强调时刻保证最大化的客户价值。而这种思路,与敏捷方法是不谋而合的。再加上,推崇敏捷方法的那些“实用主义程序员”们往往也正是开源社群的积极分子,所以适用于敏捷项目的开源过程工具尤其容易找到也就不足为奇了。
敏捷的开发者们是幸福的,因为他们拥有众多优秀的开源工具可供选择;敏捷的开发者们又是痛苦的,因为他们必须在乱花渐欲迷人眼的工具丛中找出适合自己的一组工具栈,并将它们与自己的管理策略糅合成一个完整的开发过程。本文将为读者介绍ThoughtWorks公司常用的一组过程工具,以及在敏捷项目中使用这些工具的些许经验,希望能帮助读者略微缓解这种痛苦。
作为一个程序员,笔者对过程工具的关注也更多地集中在技术层面上。从我的角度看来,敏捷方法最为重要、也最立竿见影的部分当属测试驱动与持续集成,我们的工具之旅就从这两件事情开始。
单元测试:JUnit(以及mock)
在敏捷开发的工具箱里,JUnit很可能是最广为人知、也最受到重视的一个,当然它也当得起这样的殊荣。若论出身,JUnit是由Kent Beck与Erich Gamma两人共同创造的。若论影响,由它引入的“红条/绿条”更是影响深远。
<!--[if gte vml 1]><v:shapetype id="_x0000_t75" coordsize="21600,21600"
o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f"
stroked="f">
<v:stroke joinstyle="miter" />
<v:formulas>
<v:f eqn="if lineDrawn pixelLineWidth 0" />
<v:f eqn="sum @0 1 0" />
<v:f eqn="sum 0 0 @1" />
<v:f eqn="prod @2 1 2" />
<v:f eqn="prod @3 21600 pixelWidth" />
<v:f eqn="prod @3 21600 pixelHeight" />
<v:f eqn="sum @0 0 1" />
<v:f eqn="prod @6 1 2" />
<v:f eqn="prod @7 21600 pixelWidth" />
<v:f eqn="sum @8 21600 0" />
<v:f eqn="prod @7 21600 pixelHeight" />
<v:f eqn="sum @10 21600 0" />
</v:formulas>
<v:path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect" />
<o:lock v:ext="edit" aspectratio="t" />
</v:shapetype><v:shape id="_x0000_s1026" type="#_x0000_t75" style='position:absolute;
margin-left:0;margin-top:0;width:225pt;height:210.75pt;z-index:-1'
wrapcoords="-72 0 -72 21523 21600 21523 21600 0 -72 0">
<v:imagedata src="file:///C:\DOCUME~1\jxiong\LOCALS~1\Temp\msohtml1\01\clip_image001.png"
o:title="" />
<w:wrap type="square" />
</v:shape><![endif]--><!--[if !vml]--><!--[endif]--><!--[if gte vml 1]><v:shape
id="_x0000_i1025" type="#_x0000_t75" style='width:162.75pt;height:189pt'>
<v:imagedata src="file:///C:\DOCUME~1\jxiong\LOCALS~1\Temp\msohtml1\01\clip_image003.png"
o:title="" />
</v:shape><![endif]--><!--[if !vml]--><!--[endif]-->
<!--[if gte vml 1]><v:shape id="_x0000_i1026" type="#_x0000_t75"
style='width:409.5pt;height:150pt'>
<v:imagedata src="file:///C:\DOCUME~1\jxiong\LOCALS~1\Temp\msohtml1\01\clip_image005.png"
o:title="" />
</v:shape><![endif]--><!--[if !vml]--><!--[endif]-->
<!--[if gte vml 1]><v:shape id="_x0000_i1027" type="#_x0000_t75"
style='width:378pt;height:202.5pt'>
<v:imagedata src="file:///C:\DOCUME~1\jxiong\LOCALS~1\Temp\msohtml1\01\clip_image007.png"
o:title="" />
</v:shape><![endif]--><!--[if !vml]--><!--[endif]-->
<!--[if gte vml 1]><v:shape
id="_x0000_i1028" type="#_x0000_t75" style='width:342pt;height:240pt'>
<v:imagedata src="file:///C:\DOCUME~1\jxiong\LOCALS~1\Temp\msohtml1\01\clip_image009.png"
o:title="" />
</v:shape><![endif]--><!--[if !vml]--><!--[endif]-->
图1:各种各样的Green Bars
“红条/绿条”不仅仅是一个测试成功与失败的标记,它们构成了敏捷开发中最基本的韵律:“编写测试 – 红条 – 编写代码 – 绿条 – 重构”,这五个简单的步骤确保了每一个思绪都有单元测试作为记录,每一段代码都有单元测试保证它的质量,整个软件项目始终朝着价值最大化、质量最优化的方向前进。而红条与绿条,则清晰直观地指出你当前所在的位置,以及下一步应该做的工作。一个醒目的红条/绿条对于开发者的心理有着如此重要的暗示作用,以至于当微软在Visual Studio 2005的单元测试工具中没有放置这样一个醒目的标志时,竟引来了开发者的一片怨声载道。
当我说JUnit的时候,我意指的是整个xUnit家族——覆盖了从Java/.NET直到C/C++再到Haskell/Eiffel最后到JavaScript/Ruby/Python的大家族。虽然运行在不同平台、不同语言,它们拥有同一组无法错认的特征:红条/绿条、TestCase/TestSuite……这也让开发者们无论走到哪里总可以感到放心。在开始编写你的任何一段代码之前,先为它写上一段测试;尽可能频繁地运行所有的测试。你可以立刻感受到TDD带来的帮助。
不过还有一个催化剂可以让这种化学变化来得更加强烈,那就是mock框架。以EasyMock和JMock为代表的mock框架,其作用是模拟被测对象之外的相关对象,从而实现对象之间的解耦合,达到真正意义上的“单元测试”。奇妙的是,当你把mock框架放入测试驱动实践中时,开发过程就会引导着你得到低耦合、模块化的设计,因为你很难为一组紧密耦合的类编写测试,而mock框架则让你愿意采用IoC模式分离出更多的类来承担各自的责任。在.NET和Ruby等主要平台上,也有类似的mock框架可供选择。
功能测试:Selenium
抛开所有的技术考量,单凭直觉来说,我个人认为Selenium最大的优点在于它的震撼性:成百上千个test case运行起来,只见web页面不断地在屏幕上闪过,模拟着各种各样的用户操作,最后生成一张庞大的报表,背景是令人平静愉悦的淡绿色。即便对于全然对于不懂技术的管理者或客户,这一过程的心理效果也是不言而喻的。
<!--[if gte vml 1]><v:shape id="_x0000_i1029" type="#_x0000_t75"
style='width:6in;height:152.25pt'>
<v:imagedata src="file:///C:\DOCUME~1\jxiong\LOCALS~1\Temp\msohtml1\01\clip_image011.png"
o:title="02" />
</v:shape><![endif]--><!--[if !vml]--><!--[endif]-->
图2:Selenium也采用了红条/绿条的界面设计
在没有使用Selenium之前,很多人都认为web界面是无法测试驱动、也无需测试驱动的。但此时我们就常常遇到这样的困境:客户认为页面上的一句话应该这样写,开发者却认为客户三天前的意见是另一样,认真回想起来却又没人能记得三天前到底说过什么。如果说JUnit单元测试记录了开发者对于软件的设计思路,那么Selenium就记录了客户对于软件功能的要求,并时时验证客户的要求仍然得到满足。
Selenium的用法有很多种。你可以把它放在构建流程之外,由客户定期检验软件的功能是否符合需求;你也可以让它作为构建流程的一部分,用它来驱动功能的开发,形成一个更大范围的“红-绿-重构”循环。除了编写HTML格式的测试脚本之外,Selenium还支持编程驱动的模式,可以用程序代码来编写可复用的测试案例。而且整个Selenium是用JavaScript和HTML编写的,这也就意味着你可以轻松地将其融入任何一个web应用,不管开发这个应用的平台是J2EE还是.NET或者Rails。
Selenium的名字还有一个有趣的由来:在Selenium出现之前,最著名的web应用功能测试工具当属Mercury Quanlity Center,但那是一个商业工具,功能强大却也价格不菲,常常让开发者们又爱又恨。所以,自己动手开发开源功能测试工具的ThoughtWorker们把这个工具叫做Selenium——“mercury”有“水银”的意思,而“selenium”(硒元素)恰好是专解汞中毒的特效药。
构建脚本:Ant vs. Maven
现在你已经用JUnit记下了所有设计思路,也用Selenium记下了所有功能需求。你还需要让所有测试案例都能自动运行,这样才能频繁地验证所有测试仍然顺利通过。这时Ant就来到了你的手边。由Apache组织开发,又有多年的实践检验,Ant已经积累了大量实用的插件,几乎所有常用的任务都有对应的插件可以完成。而且在Ant脚本中可以直接调用Java类(.NET平台下的NAnt更是可以直接在脚本中插入C#代码),也就是说你实际上可以用Ant来做任何事。
不过最通常的用法,还是用Ant来完成整个构建流程:从编译源代码,到打包应用,到部署服务器,到初始化数据库,再到执行测试并生成测试报告,只需要一个指令就可以全部完成。类似的构建工具在C/C++的世界里早已存在,那就是著名的make,不过Ant来得更加简单易用而已。
作为后起之秀的Maven比之Ant最大的优势在于它内建了更多对J2EE项目(尤其是web项目)的支持,以及更多项目管理相关的功能。像单元测试、创建报表等在Ant中用插件实现的功能,在Maven中都有内建的支持。甚至很多开源项目的网站都是用Maven直接生成的。但以笔者愚见,Maven强大的功能更适合开源软件这样组织松散的项目,对于一般的企业应用Ant已经足够了。
不过在进入了Ruby/Rails的世界之后,笔者感觉Ant和Maven都有一个共同的缺陷:它们的构建脚本都采用XML编写,因此代码量相当巨大,并且也不易理解。相比之下,Rake直接用Ruby来编写构建脚本,反倒显得更加简洁易用。也许相比于XML,我们还需要找到另一种更适合描述“软件构建”这一任务的领域专用语言。
版本控制:CVS vs. Subversion
任何一个多人开发的项目都必须有版本控制系统——即便一个人开发,也需要版本控制系统来提供备份和恢复的支持。由于有全面的测试作为保障,敏捷方法提倡采用“所有人拥有所有代码”的代码所有权形式,这也就意味着时常会出现两个人同时修改一份文件的情况,在一些配置文件上这种情况出现得更加频繁。因此,敏捷开发所使用的版本控制系统最好不要采用文件级的锁定——这正是VSS缺省的锁定方式,不过我们也可以通过配置来改变锁定方式。而开源的选择,则是CVS与Subversion(简称SVN)。
CVS与SVN存在着一些差异,不过作为开发者的我们通常不必介意这些区别。值得注意的一点是,当出现文件冲突时,SVN会强迫用户首先消解冲突,然后才能将文件提交到代码库。另外,每当有人成功提交新文件之后,SVN会为整个项目生成一个新的修订版本(revision),而不是像CVS那样为每个文件单独记录修订版本,这也让版本控制变得更加容易。
在一个敏捷项目中,每个开发pair每隔15分钟到半小时(最多不超过1小时)就会提交自己最新的代码,一个项目组每天通常会生成数十个修订版本。即便不算其中无法成功构建的版本,通常每周也能收获上百个构建版本。察看每个构建版本对应的报表,就是项目管理者有效掌握项目进度的最佳途径。
持续集成:CruiseControl
我们刚才已经提到,在开发者不断提交的修订版本中,有一部分是无法成功构建的,原因就是在版本控制系统上运行着一个忠实的看门人:持续集成工具。它们的代表就是由ThoughtWorks员工开发和维护的CruiseControl。
CruiseControl的任务非常简单:每当有人提交了新的文件到代码库,它就把整个项目签出(check-out)到一个测试环境,然后执行项目的构建脚本,完成整个构建流程,并运行所有测试。如果这一切都顺利通过,CruiseControl就会生成一个新的构建版本;否则,构建失败,所有人都不允许再签出或提交任何代码,直到造成破坏失败的人把问题解决掉,让构建重新成功为止。
一个能够成功构建的代码库代表着项目的健康。保持项目健康是如此重要,因此CruiseControl必须以最引人注目的方式告诉整个团队:我们的项目现在怎么样了。为此,各个团队想出了种种办法。我们可以用一个客户端工具来监控CruiseControl的构建情况,然后让这个客户端在发现构建失败时调用别的程序:唱一段歌,发出怪叫,或者点亮一盏灯……总之,让大家都知道。
<!--[if gte vml 1]><v:shape
id="_x0000_i1030" type="#_x0000_t75" style='width:297.75pt;height:134.25pt'>
<v:imagedata src="file:///C:\DOCUME~1\jxiong\LOCALS~1\Temp\msohtml1\01\clip_image013.png"
o:title="" />
</v:shape><![endif]--><!--[if !vml]--><!--[endif]-->
图3:红灯/绿灯,构建结果一目了然
知识共享:Wiki,尤其是TiddlyWiki
“敏捷宣言”中清楚地写着:“个体与交互胜于过程与工具”。对于一个敏捷团队来说,最重要的事情莫过于建立有效的交流渠道。在ThoughtWorks,每个项目都有自己的wiki,开发者、项目经理、客户……所有的项目涉众都会把自己的收获与心得记录在wiki上,以便大家分享和交流。
开源的wiki很容易找到,我在这里不必多说。我唯一想要介绍的,是这个叫做TiddlyWiki的小东西。这是一个完全用HTML和JavaScript编写的wiki,使用它甚至不需要服务器,你只要在本地打开这个HTML文件,就可以开始写你的wiki了。你所写的内容同样会被保存在这个HTML文件中,并且还提供了修改跟踪的能力。使用这个wiki,你可以把整个文档放到你的版本控制系统中,不需要为它做任何额外的配置。
另外,别忘了一个最重要的工具:纸卡片——你可以随便写,用任何颜色写,可以画任何你想画的图,可以用任何顺序来排列粘贴它们,可以任意移动,可以随时加上注释,谁都知道怎么使用它们。你甚至还可以撕掉它们,优质的纸卡片撕起来有一种特别的手感……好吧,纸卡片不是软件,通常也不免费,但你知道怎么得到它们。
<!--[if gte vml 1]><v:shape
id="_x0000_i1031" type="#_x0000_t75" alt="" style='width:375pt;height:281.25pt'
o:button="t">
<v:imagedata src="file:///C:\DOCUME~1\jxiong\LOCALS~1\Temp\msohtml1\01\clip_image015.jpg"
o:href="http://static.flickr.com/40/110457843_4b1b9c36a5.jpg?v=0" />
</v:shape><![endif]--><!--[if !vml]--><!--[endif]-->
图4:ThoughtWorks——值得信赖的全球纸卡片提供商
写在最后
介绍了我们常用的工具之后,相信读者已经知道:要实践敏捷开发,可以从哪些工具开始入手。最后我还有一个忠告要给我亲爱的读者:不要被工具绑住你的手脚。每个项目、每个团队都是独一无二的,它们需要自己独一无二的方法,而你需要针对项目和团队的情况选择适当的工具和适当的使用方式。这不是一件容易的事,但愿这篇小文能给你提供一个好的起点。
分享到:
相关推荐
在敏捷开发过程中,开源安全治理是一项至关重要的任务。随着开源软件在软件开发中的广泛应用,确保其安全性成为保障整个系统安全的基础。本篇文章将探讨敏捷开发中的开源安全治理,包括其价值、所需能力和实现方式,...
开源式敏捷开发是一种融合了敏捷开发原则与开源软件开发方法论的新型软件开发模式。在这种模式下,开发团队不仅遵循敏捷的原则进行快速迭代和持续集成,还积极地将项目代码贡献到开源社区,通过社区的力量加速软件的...
- **利用开源工具**:减少在工具上的开支,更多地依赖免费或低成本的开源解决方案。 - **加强团队协作**:通过建立高效的合作机制,提高团队整体的工作效率。 - **培养内部教练**:鼓励员工成为敏捷实践的推动者,...
为什么我们要在数据中台前加上“敏捷”呢?了解我们的朋友都知道我所在的团队是宜信敏捷大数据团队,...从中间件工具到平台介绍宜信是如何设计建设敏捷数据中台的。结合典型案例介绍宜信敏捷数据中台支持哪些数据方面的
该项目为基于多语言支持的wiseflow开源敏捷信息提取与分类工具,设计源码包含111个文件,涵盖29个JavaScript文件、20个React组件文件、19个Python脚本、16个Markdown文档、5个Shell脚本、3个JSON配置、2个Git忽略...
在廖湘科院士的演讲中,他可能分享了开源芯片项目在实际操作中的挑战与成功案例,讨论了如何利用开源工具链进行设计验证,以及如何构建敏捷开发团队以应对快速变化的技术环境。他还可能提到了如何协调全球的开源社区...
fulcrum, 敏捷项目规划工具 支点支点是为敏捷开发团队提供基于用户故事的backlog管理系统的应用程序。 有关详细信息,请参见项目页 。 参与支点仍然在早期开发中,所以现在是在项目上做标记的时候了。支点有几种通信...
总结来说,宜信的数据中台建设实践展示了如何结合开源工具构建一个敏捷、高效的数据基础设施,以支持企业的数据驱动决策和业务创新。这一实践对于其他希望构建数据中台的企业具有重要的参考价值,特别是那些在金融、...
它的核心理念体现在《敏捷宣言》中:“个体和交互胜过过程和工具;可以工作的软件胜过面面俱到的文档;客户合作胜过合同谈判;响应变化胜过遵循计划。”这些原则鼓励团队快速适应变化,重视人的因素,并通过持续交付...
1. **敏捷开发理念**:敏捷开发是一种强调迭代、快速反馈和灵活调整的软件开发方法论,它主张在项目过程中不断适应变化,提高团队的响应能力和项目成功率。书中深入解析了敏捷开发的核心原则,如用户故事、迭代开发...
以下是对文中提到的10款开源工具的详细解释: 1. **JIRA**:由Atlassian开发的JIRA是一款广泛应用于敏捷开发中的错误追踪和项目管理工具。它支持Scrum和Sprint等敏捷方法,帮助团队创建迭代周期,跟踪项目进度,并...
在这个框架中,开发者可以利用ASP.NET Core的模块化设计,快速构建可扩展的应用,同时结合持续集成和持续部署(CI/CD)工具,实现敏捷开发的目标。 "MinkeCore2.2"可能是这个框架的一个版本名称,它可能包含了ASP...
为了克服这些不足,需要继续推动开源工具链的发展,增强硬件描述语言的功能,建立更完善的开源硬件生态,并完善知识产权保护机制。 总的来说,开源芯片、RISC-V与敏捷开发是当前芯片产业变革的重要推动力,它们正在...
- **自动化工具**:利用开源工具如CruiseControl、Hudson等进行自动化测试,提高测试效率。 - **测试环境**:确保测试环境稳定可靠,便于重复测试。 - **测试实践**:采用最佳实践,如持续集成、持续部署等,提高...
5. **敏捷开发实践**:介绍敏捷开发的方法和工具,如Scrum和XP(极限编程),并提供团队协作和项目管理的建议。 通过阅读这本书,开发者不仅可以掌握Ruby on Rails的使用,还能深入理解敏捷开发的理念,从而提高...
- **数据库重构**:Rails支持在开发过程中灵活地修改数据库结构,这在敏捷开发中尤为重要,因为需求的变化可能会导致数据模型的调整。 - **代码生成器**:Rails提供了强大的代码生成工具,帮助开发者快速搭建起...
标题中的“Web开发敏捷之道--应用Rails进行敏捷Web开发 之 Depot代码”表明这是一个关于使用Ruby on Rails框架进行敏捷Web开发的示例项目,名为Depot。Ruby on Rails(简称Rails)是一个开源的Web应用程序框架,它...