Martin Fowler 的持续集成

发表于:2012-12-21来源:博客园作者:无知者云点击数: 标签:持续集成
持续集成是一种软件开发实践,在实践中项目成员频繁地进行集成,通常每个成员每天都会做集成工作,如此,每天整个项目将会有多次集成。

  持续集成是一种软件开发实践,在实践中项目成员频繁地进行集成,通常每个成员每天都会做集成工作,如此,每天整个项目将会有多次集成。每次集成后都会通过自动化构建(包括测试)来尽快发现其中的错误。许多团队都发现这种方法大大地减少了集成问题并且能够快速地开发出高内聚性的软件。本文简要地总结了持续集成技术及其现状。

  我还清楚地记得我刚加入一个大型软件项目时的情形,那时我正在英国一个电子公司做暑期实习。我的经理(属于QA部门)领我参观了一个巨大并很压抑的仓库,里面堆满了大块头的主机。经理告诉我这个项目已经开发了有些年头,现在正在做集成,并且已经集成了好几个月了。经理还告诉我说,没有人真正知道完成集成工作需要多少时间。由此我学到了软件项目的一个通病:软件集成是一个漫长并且无法预测的过程。

  然而,软件集成不必像这样的。在ThoughtWorks的大多数项目还有世界上许多其它组织的软件项目中,软件集成并不是什么难事。每个开发人员离共享的工程状态只有咫尺之遥,并且可以在几分钟之内将自己的代码集成进去。任何集成错误都能被快速地发现并得到快速的修正。

  这种鲜明的对比并不是源自于后者有多么昂贵或复杂的工具,而关键在于每人都频繁集成这种简单实践,通常是每天向一个被管控的代码库集成。

  当我向人们阐述这种实践时,通常得到两种反应:“(在我们这里)行不通”和“无关紧要”。当人们尝试了这种实践之后,他们发现其实做起来比说起来简单,而且这样的实践对于开发“至关重要”。因此有了第三种反应:“是的,我们就是这么做的,不然该怎么活啊?”

  “持续集成”源自于极限编程(XP),并且是XP最初的12种实践之一。当我以咨询师的角色加入ThoughtWorks时,我鼓励我的团队使用这种技术。Matthew Foemmel将我的建议变成了实实在在的行动,由此软件集成从少有发生并且复杂的状态变成了一桩易事。Matthew和我将我们的经验写在了本文的第一版中,而本文也是我的个人网站上最受欢迎的文章之一。

  虽然持续集成并不需要使用特别的工具来部署,但是我们发现拥有一台持续集成服务器将大有益处,其中最著名的有开源的CruiseControl,该软件最初由ThoughtWorks的几个员工开发,现在由一个很大的社区维护着。后来几款其它的持续集成服务器也相继出现了,有开源的,也有商业化的,包括ThoughtWorks Studios的Cruise。

  在开发中使用持续集成

  对于我来说,解释持续集成及其工作原理最简单的方法便是以一个小的软件功能的开发为例来进行演示。假设我们需要向软件添加一点功能,至于是什么样的功能并不重要,我们假定它很小并且可以在几个小时内完成。

  首先我们需要在本地机器上保留一份当前已经处于集成状态的代码的拷贝。我通过代码管理系统在代码库的主线(mainline)上拉下(check out)一份工作代码拷贝。

  上一段文字主要针对使用代码控制系统的人,对于不使用代码控制系统的人来说便是胡言乱语了。因此,我将向后者解释一下。代码控制系统用于将项目所有的代码保存在一个代码库(repository)中,项目当前的状态通常被称为主线。任何时候开发人员都可以从主线上获得一份拷贝到本地机器,这被称为“checking out”。本地机器上的代码拷贝称为“working copy”。(多数时候,实际上你是在更新(update)本地代码到主线状态,实践中它们是一样的效果。)

  现在,为了完成软件的功能添加,我对本地代码进行修改,其中既包括修改产品代码,也包括添加自动化测试。持续集成非常看重测试,并且在软件代码本身中达到了测试自动化——我将其称为自测试代码,通常使用流行的XUnit测试框架的一个版本。

  当我完成了功能开发(或者在我开发过程的不同阶段),我将在本地开发机上完成自动化构建。构建过程将编译并链接本地代码,然后跑自动化测试。只有当构建和测试都没有错误时,该次构建才能算是好的构建。

  有了本地的成功构建,我便可以考虑将我修改的代码提交到代码库了。但是,在我提交之前,其他开发人员可能已经向主线提交了他们的修改,所以首先我需要将他们的修改更新到我本地并且重新构建。如果他人的修改与我的修改有冲突,那么在本地编译或者测试阶段将会发生错误,这种情况下,我需要负责修改本地代码直到与主线代码保持适当同步为止。

  当本地代码与主线代码同步之后,我便可以向主线提交自己的修改了,代码库也得以更新。

  然而,单是提交了修改并不表示我的工作就完成了。我需要再次构建,但这次是在一台拥有主线代码的集成机器上进行。只有这次构建成功了才表示我的任务完成。通常会出现这样的情况:我忘了提交本地机器上的一些东西,因此代码库并没有得到适当的更新。只有我提交的修改在集成机器上成功构建之后,我的工作才算完成。这样的集成构建可以由我手动完成,也可以由Cruise自动完成。

  当两个开发者的代码有冲突时,通常会在第二个开发者更新本地代码时捕获到,否则,集成构建应该会失败。在这两种途径中,错误都可以被快速地发现。在持续集成环境中,你决不应该使失败的集成构建保留太长时间。一个好的团队每天都应该有许多成功的构建。当然,失败的构建也会时常发生,但需要尽快的修复。

  这样做的结果是,我们总会得到一个稳定并且工作正常的软件。每个人都围绕着一个共享并稳定的基础代码库工作,绝不离基础代码库太远以至于需要很长的时间将自己的修改集成到基础代码库中。如此这般,我们花在找bug上的时间减少了,因为bug在频繁的集成中经常出现。

  持续集成实践

  上文只是关于持续集成的一个概要和它在日常开发中的工作原理。让所有这些都能很好的运作显然不止于此。现在,就让我们来看看有效持续集成所需的关键实践。

  维护一个单一的代码库

  软件项目需要大量的文件协同工作来构建出最终的产品。跟踪所有的文件需要大量的工作,尤其是在多个开发者参与的项目中。因此,我们可以并不惊奇的看到,不同的软件开发团队都在开发用于管理这些文件的工具——源代码管理工具,也叫配置管理,版本控制系统,代码库等。这些工具是多数软件项目不可分的组成部分。然而,令人伤心并吃惊的是,并不是所有的项目都使用了这样的工具。我的确见到(虽然很少)不使用这些工具的项目,它们使用本地和共享磁盘这种混乱的结合来共同工作。

原文转自:http://www.ltesting.net