.Net下的开源持续集成

谈到持续集成,不如先谈谈集成。软件开发中的集成,通俗地讲就是把各个相关部分的东西组合起来,形成一个可用的软件。比如一个软件项目由几个小组来负责完成,每个小组负责其中一部分功能的实现,比较典型的是在现在的网络游戏开发中,通常有负责引擎的小组,负责游戏逻辑的小组,负责美工的小组,这些小组开发出的东西必须结合在一起才能形成一个可用的游戏;而每个小组内部的每个成员,他们每天在写着不同部分的代码,这些开发人员必须将各自的成果组合起来,才能完成他们共同的目标。从这个意义上讲,从每天每个开发者的日常开发,到各个软件模块的组合拼接,软件集成无所不在,一个完整可用的软件,就是通过不断地集成每个开发人员的代码而形成的。

每个开发过软件的人都能体会到,软件开发绝非一帆风顺,每个人开发出来的代码绝对不会魔术般的自己组合在一起,当新的功能加入到原有软件中的时候,往往不小心破坏了原有的功能,引入了一些bug,当老的bug被修复的时候,又往往会导致其他bug的产生,更糟糕的是,这些bug往往在当时并不能及时被发现。当小组成员们完成了自己所负责的模块,等到最后来一起集成的时候,他们可能已经做好了修复集成问题的心理准备。所有的这一切,都是每个开发人员的切肤之痛。那么,问题到底出在哪了?

让我们不妨换一种思维,让我们不要停留在如何地去修复bug和集成过程中产生的问题,我们渴望的理想状况是,每当我们开发出新的代码并将他们加入原系统中的时候,如果我们能够被及时告知我们是否破坏了原有系统的功能,那么我就能够及时的作出反应,修复这些部分。如果这个过程的粒度足够的细、足够地频繁,我们就能期望每次新功能引入的时候所引起的破坏足够小,并且修复起来足够简单,如果每个开发人员都能够享受到如此的方便并且保证新加入的功能不会影响原有的功能,我们的整个软件过程就能够以一个稳步可靠的步伐,持续增量的向前行进,而不是不断地加入新的代码,然后等到后来bug被人发现的时候被动地去修复它。我想稳步可靠、持续增量的软件过程,是我们每个开发者心目中的理想过程。从开发者的角度来看,毕竟谁也不想经历那种当发现自己的修改破坏的原有的功能的时候的恼火的感受。

持续集成通俗地说就是持续地、频繁地进行集成,每当有新的修改加入的时候,修改的作者能够被及时地告知他的修改是否在引入新的功能的同时保证原有功能的完整。如果整个软件开发团队在一开始就采用这种方式,我们的软件就能被稳步可靠的构建起来。

你也许会有疑问:“你说的只是一种理想状况罢了,谁都希望自己在加入新的代码的时候得知自己的代码是否破坏了原有的功能,但是怎么能够做到这一点,谁有能力来及时地告诉我们哪里有问题?持续集成这个想法不错,但怎么样能够做到持续集成?”我想这些问题是非常好也是关键的问题,持续集成究竟是否可行,如果可行,又该如何执行?我们这里不妨来整理一下,看看究竟什么是持续集成的难点。持续集成的难点主要在于,在新的功能加入的时候,如何来判断整个系统功能仍然完整;出错或者成功,谁来告诉我,如何告诉我;当大家一起协作的时候,如何保证每个人都能够准确地被告知而不会发生混乱。让我们来一个个地分析这些问题。

首先,确保真个系统功能完整性的手段就是测试,如果我们对所有的功能都有完整的测试,那么当新的功能引入的时候,如果某些原有的测试失败,就说明新的修改破坏了原有的功能,而失败的测试就能准确地告诉我们新的修改破坏了哪些原有的功能。其次,持续集成工具将告诉我们集成是否成功,持续集成工具通过运行整个系统中的测试,根据测试的结果来通知开发者,哪些测试失败导致的集成失败。每个软件项目通常会使用版本控制工具例如SVN、CVS,每当有开发者将新的修改加入到系统的代码库中时,持续集成工具会check out出代码库中的最新版本,使用自动化的构建工具例如Ant、Rake等,自动地编译项目中的代码、部署整个应用、准备测试所需的环境和数据、运行所有的测试包括单元测试、功能测试、集成测试等,在整个过程结束后将结果报告出来,持续集成工具会指出任何一个过程中出现的错误,并且准确地报告给开发者。在多人协作的情况下,版本控制工具确保了每个开发者的修改被正确有序地保存,当每个开发者想要提交自己的修改的之前,必须首先确保上一个人所提交的修改被成功集成,才能提交自己的代码,当确保自己的代码被正确集成之后,自己的工作才算完成,否则,就必须修复错误,再次提交,如此反复,直到被成功集成。

开源社区已经为我们提供了非常优秀的持续集成工具,CruiseControl、CruiseControl .Net已成为广泛使用而且非常成熟的持续集成工具,而持续集成所需要的自动化构建工具和版本管理工具如Ant、NAnt、SVN也已经是非常成熟。在下面,我尝试在我的使用经验的感受的基础上,挑选一些比较成熟或者很有潜力的工具,结合自己的使用经验,给大家做一些介绍。

我们先从持续集成的核心工具入手,这些工具在持续集成的整个过程扮演了类似于中央处理器的角色,它们负责更新每个开发人员提交的代码,使用构建工具自动运行所有的测试,然后调用其他工具将结果报告给开发人员。这一类的工具包括CruiseControl、CruiseControl .Net以及新兴的DamageControl等。

CruiseControl & CruiseControl .Net

谈到持续集成工具就不能不谈谈CruiseControl(cruisecontrol.sourceforge.net),CruiseControl可谓持续集成工具中的龙头老大,也可以说是第一个成熟的开源持续集成工具。该工具由ThoughtWorks公司开发,并将其开源,同时提供了丰富的文档支持(http://confluence.public.thoughtworks.org/display/CC/Home)。

CruiseControl非常完美的实现了一个持续集成工具所需要具备的所有功能,它集成了包括SVN,CVS,VSS,StarTeam,ClearCase等在内的十几种版本管理工具,内建地支持了Ant,NAnt,Maven,Maven2等自动化构建工具,并且通过执行shell命令的方式间接支持几乎所有其他构建工具如make,jam等。你可以设置CruiseControl以多种方式运行系统的集成,既可以在每次有新的代码修改提交时自动运行,也可以让它定时运行。在运行完后,CruiseControl可用允许你使用各种方式报告运行的结果,包括发送电子邮件、使用ftp、rss、jabber、scp等工具报告结果,也可以让你自动化地在运行完后将整个系统打包、部署。它甚至允许你在运行完成后根据结果成功与否播放不同的音乐或电影,及时地告诉大家。

在实际开发过程中,开发人员可以将CruiseControl配置为每次有新的修改时运行所有集成工作,这样当你提交你的修改以后,CruiseControl会自动地将代码库中的新的修改更新到一个事先指定的地方,然后按照你的配置准备测试数据、编译、运行系统中的所有测试。开发人员可以通过web方式通过CruiseControl附带的一个web程序查看运行的结果,这个结果页面会告诉大家该次build是否成功或失败,如果失败,大家也可以看到失败的错误信息,也可以告诉你在某一段时间之内所运行的集成的统计信息。根据配置,CruiseControl可以显示几乎集成过程中每个环节出现的错误,例如编译错误、junit测试运行错误、checkstyle代码风格检查错误,以及功能测试、集成测试错误等。当其他人想要提交他们的修改之前,都应改事先查看CruiseControl的结果页面,如果当前CruiseControl没有在运行,并且上一次运行结果为成功,才能提交自己的修改,在提交后,还要保证新的一轮集成成功完成,才算完成了自己的工作。

CruiseControl具备很好的扩展能力,目前已经有很多为CruiseControl编写的插件。

CruiseControl是用java语言编写的,并且可以运行在各种平台上,然而,并不是只有java程序才能用它来进行持续集成,CruiseControl可以用来做任何语言编写的系统的持续集成,例如C++程序员就可以使用make或jam,配合svn或者cvs来进行持续集成,使用CppUnit、mockpp等工具编写测试。尽管如此,还是诞生了一些在特定平台上运行的持续集成工具,CruiseControl.Net就是其中一个例子。

CruiseControl.Net(http://ccnet.thoughtworks.com)运行在.Net平台上,采用.Net框架实现,在实现了几乎所有的CruiseControl的功能的基础上,提供了对于Windows平台和.Net编程更多更友好的支持。

CruiseControl.Net的一个特点是它集成了对Visual Studio .NET和MSBuild的支持。用户可以将Visual Studio .NET工程的sln文件指定给它,让它运行其中的build、rebuild和clean等功能。在NAnt出现之前,几乎所有开发人员在都是使用Visual Studio .NET来管理他们的.Net项目的。这样,CruiseControl.Net可以支持对原有Visual Studio .NET工程的持续集成,而用户也既可以使用NAnt或者Visual Studio .NET来管理整个项目的构建。MSBuild是Visual Studio 2005项目的标准格式,CruiseControl.Net对其的内建支持可以使大家很容易地将Visual Studio 2005的项目放到CruiseControl.Net中去。

CruiseControl.Net使用Web Dashboard来发布运行结果,它有点类似于CruiseControl中用来发布结果的web应用,不过是用.Net写成的。另外它还包含一个Windows托盘程序CCTray来方便用户随时查看build结果。

DamageControl

在Ruby成为一种新的流行时尚的今天, DamageControl(http://dev.buildpatterns.com/trac/wiki/DamageControl)的出现大概不会让大家感到奇怪,它是一个用ruby写成的持续集成工具,也是由ThoughtWorks公司开发的一个开源产品。DamageControl目前还处于开发阶段,但是已经实现了CruiseControl的绝大部分功能,包括对CVS和SVN的内建支持,同时支持多种自动化构建工具等。

DamageControl区别于CruiseControl的一个显著特性是它提供了一个用Ruby on Rails框架写成的web管理应用程序,用户可以很简单的使用这个web程序来配置持续集成项目。凭借着这个简单的web管理程序,用户可用方便的建立一个持续集成项目,并可以配置运行策略、版本管理、运行结果的查看方式等,而不用像在CruiseControl或CruiseControl.Net里面一样,需要手动修改一个xml配置文件来完成集成项目的配置。

尽管DamageControl目前还处于开发状态,它已经逐渐被广泛应用起来,由于它使用ruby写成的,所以自然会成为ruby项目的首选工具。它的安装也比较简单,用户可以直接从DamageControl项目的SVN代码库中check out出源代码,稍加配置就可以运行了。

DamageControl还实现了一个非常酷的功能: AppCasting。该功能能够让你将你运行完持续集成后得到的系统交付给对你的系统感兴趣的人。当某一次集成运行完毕后,DamageControl会使用一些工具如Ruby Gems, Apt, Maven repository等将你的系统打包,然后在它自己的RSS里面加上一条消息表明新的系统已经被成功构建了。这样,任何订阅了该RSS的人就可以及时的知道某一个项目的进展情况,并且在有新的集成成功运行完成后得到最新被构建的系统以及相关的发布信息。

谈完了这些持续集成工具,我们有必要来看看自动化构建工具,这些工具在持续集成中同样扮演着非常重要的角色,可以这么说,持续集成工具就像一个指挥,而真正完成工作需要依靠这些自动化的构建工具。正是这些工具的存在,是我们可以自动化的完成编译源码、运行测试、打包系统、部署应用等所有这些我们在集成中需要完成的工作。目前在这方面已经有很多非常成熟的开源工具,比如古老的Make,鼎鼎有名的Ant和它在.Net世界中的兄弟NAnt,用ruby写就的Rake等等。在下面的内容中,我将挑选其中的几个工具进行一些介绍。

Ant & NAnt

Ant可以说是非常有名的一个自动化构建工具了,其在.Net世界中的兄弟NAnt也已获得了广泛应用。Ant凭借其使用简单和良好的跨平台特性已经博得了诸多程序员的青睐。它不仅是java应用开发中的首选工具,用户也可以用它来是自己的工作自动化,例如转换DocBook文档、编译Tex文档等。有关Ant的介绍已经是数不胜数,我在这里也不想做过多重复。只是就项目中可能用到的Ant的一些特性做一些介绍。

在持续集成过程中,我们往往需要做以下一些工作:编译代码、代码风格检查、运行测试、打包应用、部署应用、运行功能和集成测试等。所有的这些工作都可以使用Ant来完成。开源社区已经为Ant贡献了数不清的Task来扩充Ant的功能。我们可以使用junit和testng任务来运行测试,通过checkstyle提供的任务来进行java代码风格检查,使用tomcat等提供的任务来自动化地启动和停止服务器并部署应用程序,或者用你自己实现的功能来进行数据库schema的自动构建和测试数据的刷新,进行数据库schema的迭代化升级,使用Ant,你还可以自动启动你的浏览器,并在上面运行用selenium或watir等工具写成的功能和集成测试。Ant对这些任务的自动化运行的支持,使得我们的自动化的持续集成成为可能。要知道,自动化是持续集成的一个非常重要的特性,项目构建的自动化也是实现持续集成的一个重要前提,毕竟,我们不可能期望每次都手动地在集成过程中执行某些工作,如此是不能保证我们能够反复快速并且持续地进行集成的。

目前的Ant已经很成熟,它在1.6版本中引入的macro、import、subant等特性进一步方便了我们组织自动化构建脚本,使我们的脚本更简单、清晰和有组织。NAnt作为.Net平台下的专有工具,对.Net平台下的开发提供了许多支持,有兴趣的朋友可以到它们各自的网站上面获得更详细的信息。

Rake

Rake是一个用ruby写就的自动化构建工具,目前已经逐渐被更多的人所了解,它其实是一个用ruby语言写成的DSL(领域专有语言)。Rake的构建脚本本身就是ruby程序,因此它能够充分利用ruby语言的强大功能,在Rake脚本中,你可以使用ruby语言的全部功能和程序库,来完成你的任务。

Ruby是一个非常强大而且易于使用的动态语言,并且拥有非常丰富的程序库。所以利用Rake,你几乎可用很方便的完成所有你碰到的任务,甚至包括使用计算机的串口进行通信,这样你就可以使用外部硬件来显示你的持续集成结果。Ruby内置的正则表达式支持和强大的文本处理能力使得某些工作可以变得非常简单,比如配置文件的管理等。

Rake不仅支持ruby项目的构建,也同时支持其他语言写成的项目的构建。Martin Fowler的个人网站上有一篇非常不错的文章介绍Rake: http://martinfowler.com/articles/rake.html。 借助于Ruby的程序库集中管理机制,Rake的安装也非常的简单,通过ruby的程序包管理软件gem,只要一行命令就能自动地从远程服务器上下载并安装最新的Rake。

除了持续集成工具和自动化构建工具以外,版本管理工具也是持续集成过程中的一个重要工具。比较流行的版本管理工具例如SVN和CVS我想大家都已经非常熟悉了,版本管理工具作为项目管理中的一个基础工具,它的重要性我想应该是不言而喻的。持续集成工具往往集成了对各种版本管理工具的支持,能够自动地监视代码库,一旦发现有新的修改加入,就会通知其他模块,决定是否需要开始新的一轮集成的运行。

小结

持续集成是现代软件工程中的一件利器,任何一个软件项目,不论是上百人的大项目还是个人项目,持续集成都能让你的软件开发过程更加稳定高效,提升软件的质量,减少不必要的人工操作。它也是敏捷开发方法中的一个非常重要的规则。我们在前面所讨论的这些开源软件,已经为我们实现持续集成提供了非常成熟的技术支持,相反,商业软件在这些领域中确极少有所建树。我想正是由于这些工具的诸多作者对程序开发过程需求的敏锐细致的把握,才导致了这些优秀的开源工具的诞生,而开源软件的免费、开发源代码本质更加凸现了这些工具的价值。我相信,随着软件开发过程的不断进步,会不断有更多更好的开源工具出现,使得我们可以更稳定、更快速地开发出高质量的满足人们需求的软件,让我们的生活变得更加美好。

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.