持续集成

持续集成是一种软件开发实践,团队成员经常集成他们的工作,通常每个人至少每天进行一次整合——导致每天进行多次整合。每个集成都通过一个自动构建(包括测试)进行验证,以尽快检测集成错误。许多团队发现这种方法会显著减少集成问题,并允许团队更快地开发具有凝聚力的软件。本文简要介绍了连续集成技术及其当前的应用。

01 May 2006

发现 类似物品通过查看这些标签: 流行的· 敏捷的· 连续输水· extreme programming

For more information on this,以及相关主题,看看我的指南页交货。

ThoughtWorks,我的雇主,offers consulting and support around Continuous Integration.CruiseControl第一台持续集成服务器,was originally created at ThoughtWorks.ThoughtWorks工作室,our products group,创建-用于持续集成和交付的开源服务器。它支持并行,部署多个项目的管道,一个时髦的仪表盘,以及对自动化部署的支持。这是一个商业工具,但可免费用于小型设备。

我清楚地记得我第一次看到一个大型软件项目。我在一家英国大型电子公司做暑期实习。我的经理,质量保证小组的一部分,给了我一张地图,我们进入了一个巨大而压抑的仓库,里面堆满了立方体。我听说这个项目已经开发了好几年了,目前正在进行整合。几个月了。我的向导告诉我,没有人真的知道完成集成需要多长时间。从中我学到了一个软件项目的共同故事:集成是一个漫长且不可预测的过程。

但这不一定是方法。我同事做的大多数项目都是经过深思熟虑的,世界各地的许多人,将治疗整合为非事件。任何单个开发人员的工作距离共享项目状态只有几个小时的路程,并且可以在几分钟内恢复到该状态。任何集成错误都能迅速发现并能迅速修复。

这种对比不是昂贵和复杂工具的结果。它的本质在于团队中每个人的简单实践,经常整合,通常每天与受控的源代码存储库相对应。

当我向人们描述这种做法时,我通常会发现两种反应:“它不起作用(这里)”和“这样做不会产生很大的差异”。人们在尝试时发现它比听起来更粘,这对发展产生了巨大的影响。因此,第三个常见的反应是“是的,我们这样做——没有它,你怎么能活下去?”

术语“持续整合”起源于肯特·贝克的极限编程development process,作为其最初的第十二种做法之一。当我开始思考的时候,作为顾问,我完成了我正在合作的项目,使用技术。MatthewFoemmel把我含糊不清的劝告变成了坚定的行动,我们看到这个项目从稀罕和复杂的转变为我描述的非事件。马修和我在这篇论文的原版中写下了我们的经历,这是我网站上最受欢迎的报纸之一。

尽管持续集成是一种需要无关节工具部署的实践,we've found that it is useful to use aContinuous Integration server.最著名的服务器是CruiseControl,一个开放源码工具,最初由几个人构建,现在由一个广泛的社区维护。从那时起,出现了其他几个CI服务器,开源和商业-包括巡航来自ThoughtWorks工作室。


构建具有持续集成的功能

对于我来说,解释什么是CI以及它如何工作的最简单的方法是展示一个快速的示例,说明它如何与AsMall功能的开发一起工作。假设我必须对一个软件做点什么,不管任务是什么,因为妈妈会认为它很小,可以在几个小时内完成。(我们将探索更多的任务,and other issues later on.)

我首先将当前集成源的副本复制到本地开发机器上。我通过使用源代码管理系统从主线中签出一个工作副本来实现这一点。

以上段落对使用源代码控制系统的人来说是有意义的,但对那些不爱说话的人来说,你得胡说八道。Solet me quickly explain that for the latter.源代码控制系统将项目的所有源代码保留在一个位置。系统的当前状态通常被称为“主线”。任何时候,开发人员都可以将主线的受控副本复制到自己的计算机上,这叫做“退房”。开发人员机器上的拷贝称为“工作拷贝”。(大多数情况下,您实际上将工作副本更新到主线上——实际上,这是相同的事情。)

现在我拿着我的工作副本,做我需要做的任何事情来完成我的任务。This will consist of both altering theproduction code,以及添加或更改自动测试。持续集成假定有一个高度的测试,这些测试可以自动进入软件:我调用的一个设施自检代码.Often these use a version of the popularXUnit testing frameworks.

一旦我完成了工作(通常在我工作的各个阶段),我就在我的开发机器上执行一个自动化的构建。这将获取我工作副本中的源代码,编译并将其链接到可执行文件中,运行自动测试。只有在所有构建和测试都没有错误的情况下,所有构建才被认为是好的。

有了好身材,然后我可以考虑将更改提交到存储库中。扭曲,当然,是其他人可以,通常有,在我有机会提交之前对主线进行了更改。因此,首先我用它们的更改更新我的工作副本并重新生成。如果他们的变化和我的变化一样,它将在编译或测试中表现为失败。在这种情况下,我有责任修复这个问题并重复,直到我可以构建一个与主线正确同步的工作副本。

一旦我构建了一个正确同步的工作副本,我就可以最终将我的更改提交到主线,然后主线会更新存储库。

However my commit doesn't finish my work.在这一点上,webuild再次,but this time on an integration machine based onthe mainline code.只有当这个构建成功时,我们才能说我的更改已经完成。我总是有可能在我的机器上遗漏了一些东西,并且存储库没有得到适当的更新。只有当我提交的更改在集成上成功构建时,我的工作才完成。这个集成构建可以由我手动执行,or done automatically by Cruise.

如果两个开发商之间发生冲突,当第二个开发人员创建更新的工作副本时,通常会捕获到它。否则,集成构建将失败。无论哪种方法,都可以快速检测到错误。在这一点上,最重要的任务是修复它,让建筑再次正常运转。在持续集成环境中,您不应该让失败的集成构建长期失败。一个好的团队一天应该有很多正确的构建。不好的构建经常发生,但应该尽快解决。

这样做的结果是,有一个稳定的软件可以正常工作,并且包含很少的错误。每个人都会发展出一个共享的稳定的基础,并且永远不会从这个基础中脱离出来,以至于需要很长的时间才能与之融合。花更少的时间去寻找错误,因为它们很快就会出现。


持续集成实践

上面的故事是对词及其在日常生活中的作用的概述。让所有这些工作顺利进行显然比这更重要。我现在将重点介绍构成有效CI的关键实践。

维护单个源存储库。

软件项目涉及许多需要协调在一起以构建产品的文件。Keeping track of all ofthese is a major effort,尤其是当涉及多个人时。因此,多年来软件开发团队已经构建了管理所有这些的工具,这并不奇怪。这些工具称为源代码管理工具,configuration management,versioncontrol systems,repositories,或其他各种名称-是大多数开发项目的一个整体部分。令人伤心和惊奇的是,他们不是全部的项目。这是罕见的,但是我遇到的项目并没有使用这样的系统,而是使用一些本地和共享驱动器的messycombination。

因此,作为一个简单的基础,确保您得到一个体面的源代码管理系统。Cost isn't an issue as good quality open-sourcetools are available.当前选择的开放源码存储库是颠覆.(OlderOpen源工具并行版本系统仍然被广泛使用,比什么都没有要好得多,但颠覆是现代的选择。)有趣的是,在我和开发人员交谈时,我知道大多数商业源代码管理工具比颠覆更受欢迎。我一直听到人们说的唯一值得花钱的工具是贯通.

一旦你得到了一个源代码管理系统,make sure itis the well known place for everyone to go get sourcecode.没人应该问“foo whiffle文件在哪里?”所有东西都应该在存储库中。

尽管许多团队使用存储库,但我看到的一个常见错误是他们没有将所有内容都放在存储库中。如果人们使用一个,他们会把代码放进去,但是,构建所需的一切都应该包含在内:测试脚本,属性文件,数据库,安装脚本,第三方图书馆。我已经知道了将他们的编译器检查到存储库的项目(在早期的C++编译器中很重要)。基本的经验法则是你应该能够用一台处女机器走到项目的前面,做阿切科特,能够全面构建系统。只有一小部分的东西应该在原始机器上-通常是大的东西,安装复杂,稳定的。操作系统,Java开发环境或者基本数据库系统就是典型的例子。

必须将生成所需的所有内容放入源代码管理系统中,不过,你也可以把人们通常使用的其他东西放在里面。IDE配置是很好的,因为这样人们很容易共享相同的IDE设置。

版本控制系统的一个特点是可以创建多个分支,处理不同的发展流程。这是一个有用的,不重要,功能-但它经常被过度使用,让人们变得难以抗拒。尽量减少使用分支。特别是A主线:当前正在开发的项目的单个分支。几乎每个人都应该在大多数时候离开这条主线。(合理的分支是对以前的产品发布和临时实验的错误修复。)

一般来说,您应该在源代码管理中存储所有需要构建的东西,但你实际上没有建造什么。有些人确实将构建产品保存在sourcecontrol中,但我认为这是一种气味-一个更深层次的问题的迹象,通常无法可靠地重新创建构建。

自动生成

把源代码转换成一个运行的系统可能会导致一个涉及编译的复杂过程,移动文件,将模式加载到数据库中,等等。然而,就像软件开发的这一部分中的大多数任务一样,它可以被自动化——结果应该是自动化的。要求人们输入奇怪的命令或点击对话框是浪费时间和滋生错误的温床。

用于构建的自动化环境是系统的一个常见特性。Unix世界已经创造了几十年,Java社区开发的蚂蚁,.NET社区已经有了nant,现在有了msbuild。请确保可以使用这些脚本通过单个命令来构建和启动系统。

一个常见的错误是不要将所有内容都包含在自动构建中。构建应该包括将数据库架构从存储库中取出,并在ExecutionEnvironment中启动它。我将详细阐述我先前的经验法则:任何人都应该能够引进一台处女机器,检查存储库的源代码,发出一个命令,在他们的机器上有一个运行系统。

构建脚本有各种各样的风格,对于平台或社区来说是特别的,但是它们不是必须的。虽然我们的大多数Java项目都使用Ant,有些人使用了Ruby(TheRubyRake系统是一个非常好的构建脚本工具)。我们从使用Ant实现早期的微软COM项目自动化中获得了很多价值。

大型建筑往往需要时间,you don't want to do all ofthese steps if you've only made a small change.因此,一个好的构建工具会分析作为流程一部分需要更改的内容。The commonway to do this is to check the dates of the source and object filesand only compile if the source date is later.依赖关系然后gettricky:如果一个对象文件更改了依赖它的那些文件,那么它也可能被重建。编译器可以处理这种事情,或者他们可能不会。

取决于你需要什么,你可能需要建造不同种类的东西。您可以使用或不使用测试代码,或使用不同的测试集来构建系统。有些组件可以单独构建。构建脚本应该允许您为不同的情况构建可选的目标。

我们中的许多人使用IDES,大多数IDE都有某种构建管理过程。然而,这些文件始终是IDE的专有文件,而且往往很脆弱。此外,他们还需要自己的东西来工作。对于IDE用户来说,可以设置自己的项目文件并将其用于个人开发。但是,有必要在服务器上使用一个主构建,并且可以从其他脚本运行。因此,在Java项目中,开发人员在IDE中构建是可以的。but the master build uses Ant to ensure it can be run onthe development server.

进行构建自我测试

传统上,构建意味着编译,linking,以及让程序执行所需的所有附加内容。程序可能会运行,但这并不意味着它做了正确的事情。现代静态类型语言可以捕获许多错误,但更多的人会从网上溜走。

一种更快、更有效地捕获错误的好方法是在构建过程中包含自动化测试。当然,测试并不完美,但是它可以捕获很多错误——足够有用。特别是极限编程(XP)和测试驱动开发(TDD)的兴起,极大地促进了自测试代码的普及,使许多人看到了这种技术的价值。

我作品的老读者会知道我是TDD和XP的狂热爱好者,不过,我想强调的是,这两种方法都不是获得自测试代码好处所必需的。这两种方法都在编写使它们通过的代码之前就要编写一个测试点-在这种模式下,测试与错误捕获一样,都是关于探索系统设计的。bet188足球这是件好事,but it's not necessary for thepurposes of Continuous Integration,where we have the weakerrequirement of self-testing code.(尽管TDD是我生成自我测试代码的首选方法。)

对于自测试代码,您需要一套自动测试,它可以检查代码库的大部分是否存在错误。The tests needto be able to be kicked off from a simple command and to beself-checking.运行测试套件的结果应指示是否有任何测试失败。对于要进行自我测试的生成,测试失败应导致生成失败。

在过去的几年里,TDD的兴起使XUnit家族开放源码工具,是这种测试的理想选择。XUnit工具在思想工作中对我们非常有价值,我总是建议人们使用它们。These tools,pioneered by Kent Beck,使您很容易建立一个完整的自我测试环境。

XUnit工具无疑是进行代码自检的起点。您还应该了解其他关注更多端到端测试的工具,目前有很多这样的工具,包括合身萨希Watir菲尼斯,还有很多其他的我不想在这里全面列出的。

当然,你不能指望考试能找到一切。正如人们常说的那样:测试不能证明没有错误。然而,每一个完美并不是你得到回报的唯一一个点,在自我测试构建。不完全试验,频繁运行,比从未写过的完美测试要好得多。

Everyone Commits To the Mainline Every Day

集成主要是关于通信。集成允许开发人员告诉其他开发人员他们所做的更改。频繁的交流使人们能够随着变化的发展而迅速了解。

开发人员提交到主线的一个先决条件是他们可以正确地构建代码。这个,当然,包括通过构建测试。As with any commitcycle the developer first updates their working copy to matchthe mainline,解决与主线的任何冲突,然后在本地机器上进行构建。如果构建通过,然后他们就可以自由地向主线承诺了。

经常这样做,开发人员很快就会发现两个开发人员之间是否存在冲突。The key to fixingproblems quickly is finding them quickly.随着开发人员每隔几个小时提交一次冲突,可以在冲突发生后的几个小时内检测到冲突,在这一点上,没有太多的散列,很容易解决。持续数周检测到的冲突可能很难解决。

更新工作副本时生成的事实意味着您检测到编译冲突和文本冲突。因为构建是自测试的,您还可以检测代码运行中的冲突。后一种冲突是特别难发现的错误,如果它们在代码中存在很长一段时间而没有被发现的话。因为提交之间只有几个小时的变化,只有这么多地方可以隐藏问题。此外,由于没有太多变化,您可以使用差异调试帮你找到虫子。

我的一般经验法则是,每个开发人员都应该每天向存储库提交数据。在实践中,如果开发人员比这更频繁地提交,这是很有意义的。你承诺的频率越高,你越不必去寻找冲突错误,你解决冲突的速度越快。

Frequent commits encourage developers to break down theirwork into small chunks of a few hours each.这个帮助跟踪进度并提供进度感。通常人们一开始就觉得自己不能在短短的几分钟内做出有意义的事情,但是我们发现指导和练习可以帮助他们学习。

每个提交都应该在集成机上构建主线

使用每日提交,团队经常得到测试构建。This ought to mean that the mainline stays in ahealthy state.在实践中,然而,事情还是有问题。一个原因是纪律,没有在提交之前执行更新和生成的人。另一个是开发人员机器之间的环境差异。

因此,您应该确保常规的构建发生在集成机器上,并且只有当这个集成构建成功时,才应该考虑提交。既然承诺的开发人员对此负责,开发人员监视主线构建,以便在主线构建中断时修复它。由此产生的一个推论是,在主线构建完成之前,您不应该回家,因为您在当天晚些时候做出了任何承诺。

我看到了两种主要的方法来确保这一点:使用一个构建或一个持续集成服务器。

手动构建方法是最简单的描述方法。从本质上讲,这与开发人员在提交到本地构建之前所做的类似。开发人员进入集成机器,检查主线的头部(现在容纳了他的最后一个提交),并启动集成构建。He keeps an eyeon its progress,如果建造成功,他就完成了他的承诺。(Also see Jim Shore's描述.)

一个持续的集成服务器充当对该站点的监视器。每次针对存储库的提交完成服务器时,都会自动签出集成计算机上的源,启动构建,并将生成的结果通知提交者。提交人在收到通知之前并不是不知道——通常是一封电子邮件。

经过深思熟虑,我们是持续集成服务器的忠实粉丝——事实上,我们引领了巡航控制CruiseControl.net网站,广泛使用的开源CI服务器。从那以后,我们还建了这个广告巡航CI服务器。我们几乎在每个项目上都使用一个CI服务器,并且对结果非常满意。

并非每个人都喜欢使用CI服务器。Jim Shore gave a有充分理由的描述为什么他更喜欢手动操作。我同意他的观点,即CI不仅仅是为了安装一些软件。All the practices here need to bein play to do Continuous Integration effectively.但是Equalymany团队很好地完成了CI,他们会发现CI服务器是一个有用的工具。

Many organizations do regular builds on a timed schedule,such as every night.This is not the same thing as acontinuous build and isn't enough for continuousintegration.持续集成的关键是尽快发现问题。夜间构建意味着,在任何人发现它们之前,一整天都没有发现虫子。Once they are in the system that long,查找和删除它们需要很长时间。

立即修复损坏的生成

进行连续构建的一个关键部分是,如果主线构建失败,它需要马上修复。使用CI的关键是,您总是在已知的稳定基础上进行开发。这对主线建设来说不是坏事,尽管它一直在发生,但它表明人们在提交之前对本地更新和构建不够谨慎。当主线建设中断时,然而,很重要的一点是要尽快修好。

我记得KentBeck使用的一个短语是“没有人比修复构建有更高的优先级任务”。这并不意味着团队中的每个人都必须停止他们正在做的事情来修复构建,通常只需要几个人就可以让事情恢复正常。它确实意味着有意识地将构建修复作为紧急的优先级,high priority task.

通常修复构建的最快方法是从主线还原最新的提交,将系统恢复到上一个已知的良好版本。当然,团队不应该尝试在断开的主线上进行任何调试。除非破碎的原因很明显,只需恢复主线并在开发工作站上调试问题。

为了避免破坏主线,您可以考虑使用未决水头.

当团队引入CI时,通常这是最难解决的问题之一。Early on a team can struggle toget into the regular habit of working mainline builds,particularly if they are working on an existing codebase.耐心和稳定的应用似乎经常会有这种效果,所以不要泄气。

保持快速构建

持续集成的关键是提供快速反馈。没有什么比长时间的构建更能吸取CI活动的血液了。Here I must admit acertain crotchety old guy amusement at what's considered tobe a long build.我的大多数同事认为一个建筑需要一个小时才能完全不合理。我记得有个团队正在努力让他们尽快得到它——偶尔韦斯特会遇到这样的情况,在这种情况下很难让建造达到这样的速度。

For most projects,然而,十分钟构建的xp指南是完全合理的。我们的大多数现代项目都能做到这一点。值得全力以赴去实现它,因为每减少一分钟的构建时间都会为每个开发人员在每次提交时节省一分钟。由于CI要求频繁提交,这会增加很多时间。

如果你盯着一个小时的建造时间,那么,加快建造速度似乎是一个令人望而生畏的前景。It can evenbe daunting to work on a new project and think about how tokeep things fast.对于企业应用程序,at least,我们发现通常的瓶颈是测试——尤其是涉及数据库等外部服务的测试。

可能最关键的一步是开始建立部署管道。背后的想法部署管道(also known as建造管道分阶段构建)实际上,有多个构建是按顺序完成的。提交到主线会触发第一个构建——我称之为提交构建。这个commitbuild是指当有人向主线承诺时所需要的构建。提交构建是必须快速完成的构建,因此,它需要一些快捷方式来降低检测错误的能力。技巧是平衡bugfinding和速度的需求,这样一个好的提交构建就足够稳定,可以让其他人继续工作。

一旦提交构建良好,其他人就可以自信地在代码上工作。However there are further,慢一点,你可以开始做的测试。其他机器可以在构建上运行需要更长时间的进一步测试例程。

一个简单的例子是两阶段部署管道。第一阶段将进行编译和运行测试,这些测试是更本地化的单元测试,数据库完全断开。这样的测试可以运行得非常快,保持在十分钟之内。然而,任何涉及更大规模交互的bug,尤其是那些涉及真实数据库的,不会被发现。第二阶段构建运行了一个不同的测试套件,这些测试会命中真实的数据库并涉及更多的端到端行为。这间套房可能要花几个小时的时间。

在这个场景中,人们使用第一阶段作为commitbuild,并将其作为主要的CI周期。第二阶段构建在它可以运行的时候运行,从最新的good commitbuild中提取可执行文件以进行进一步测试。如果此辅助生成失败,那么这可能不具有相同的“停止一切”质量,但是团队的目标是尽快修复这些错误,保持提交生成运行。在这个例子中,后期的构建通常是纯粹的测试,因为现在通常是测试导致了速度缓慢。

如果二次生成检测到错误,这标志着提交构建可以用另一个测试完成。尽可能多地确保任何后期失败都会导致提交构建中的新测试捕获错误,所以这个bug在提交构建中稳定地修复了。这样,只要有什么东西通过了提交测试,它们就会得到加强。有些情况下,现在没有办法构建一个快速运行的测试来暴露这个bug,因此,您可以决定在第二个构建中只测试该条件。大多数时候,幸运的是,您可以向提交构建添加适当的测试。

这个例子是一个两级管道,但基本原理可以扩展到任何数量的后期阶段。提交构建之后的构建也可以并行完成,因此,如果您有两个小时的二级测试,您可以通过让两台机器运行一半的测试来提高响应性。By using parallel secondary builds like this you canintroduce all sorts of further automated testing,包括性能测试,进入常规构建过程。

在生产环境的克隆中进行测试

测试的重点是冲洗,在受控条件下,系统在生产过程中出现的任何问题。其中一个重要的部分是生产系统运行的环境。如果你在不同的环境中测试,每种差异都会导致一种风险,即在测试中发生的事情在生产中不会发生。

因此,您希望将测试环境设置为与可能的生产环境完全类似。使用相同的数据库软件,同样的情况下,使用相同版本的操作系统。将产品环境中的所有适当库放入测试环境中,即使系统实际上没有使用它们。使用相同的IP地址和端口,在相同的硬件上运行它。

好,实际上,这是有限制的。如果您正在编写桌面软件,那么用不同用户正在运行的所有第三方软件对每个可能的桌面进行克隆测试是不可行的。同样,一些生产环境的复制成本可能高得令人望而却步(尽管我经常遇到不复制中等成本环境的错误经济)。尽管有这些限制,您的目标仍然是尽可能多地复制生产环境,为了了解测试和生产之间的每一个差异所带来的风险。

如果你的设置非常简单,没有太多笨拙的通信,you may be able to run your commit build in amimicked environment.经常,然而,你需要使用测试双倍因为系统响应缓慢或间歇。因此,为了进行速度测试,通常会有一个非常人工的环境,并使用生产克隆进行二次测试。

我注意到,越来越多的人对使用虚拟化来简化测试环境的组合感兴趣。虚拟化的机器可以与所有必要的元素一起保存到虚拟化中。安装最新的构建和运行测试是相对直接的。此外,这可以让您在一台机器上运行多个测试,或在一台计算机上模拟网络中的多台计算机。随着虚拟化的性能降低,这个选项越来越有意义。

使任何人都可以轻松获取最新的可执行文件

软件开发中最困难的部分之一就是确保构建正确的软件。我们发现很难预先说明你想要什么并加以纠正;人们发现,看到一些不太正确的事情,并说出需要如何改变,要容易得多。敏捷开发过程明确地期望并利用这部分人类行为。

为了帮助实现这一目标,任何参与软件项目的人都应该能够获得最新的可执行文件并能够运行它:为了演示,探索性测试,或者只是看看这周发生了什么变化。

这样做非常简单:确保有一个众所周知的地方,人们可以在那里找到最迟的可执行文件。将多个可执行文件放入这样的存储中可能很有用。For the very latest you should put the latestexecutable to pass the commit tests - such an executableshould be pretty stable providing the commit suite isreasonably strong.

如果您遵循一个定义良好的迭代过程,通常最好也将迭代构建的结尾放在那里。示威游行,特别地,需要功能熟悉的软件,因此,这通常是值得牺牲的最新的东西,演示者知道如何操作。

每个人都能看到发生了什么

持续整合就是沟通,因此,您希望确保每个人都能轻松地看到系统的状态以及对其所做的更改。

One of the most important things to communicate is thestate of the mainline build.如果你使用的是CruiseThere的一个内置网站,它会告诉你是否有Abuild正在进行中,以及最后一个主线构建的状态。Many teams like to make this even more apparent byhooking up a continuous display to the build system - lightsthat glow green when the build works,or red if it fails arepopular.特别常见的是红色和绿色。拉瓦朗普-这些不仅表示构建的状态,但是它在那种状态下有多久了。Bubbles on a red lampindicate the build's been broken for too long.每个团队在这些构建传感器上都有自己的选择-很高兴能与你的选择保持一致(最近我看到有人在试验跳舞的兔子)。

如果您使用的是手动CI流程,这种可见度是至关重要的。物理构建机器的监视器显示主线构建的状态。Often you have abuild token to put on the desk of whoever's currently doingthe build (again something silly like a rubber chicken is agood choice).Often people like to make a simple noise on goodbuilds,就像敲钟一样。

CI servers' web pages can carry more information than this,of course.克鲁斯提供的不仅仅是谁在建造,但是他们做了什么改变。克鲁斯还提供了一个变化的历史,允许团队成员对项目最近的活动有很好的了解。我认识团队领导,他们喜欢用这个来了解人们在做什么,并了解系统的变化。

使用网站的另一个好处是,那些不在同一地点的人可以了解项目的状态。一般来说,我更喜欢让每个人都积极地坐在一起讨论这个项目,但经常有外围的人喜欢关注事物。它还可用于Groupsto聚合来自多个项目的构建信息-提供不同项目的简单和自动化状态。

良好的信息显示不仅仅是计算机屏幕上的显示。One of my favorite displays was for a project thatwas getting into CI.它有很长的历史,无法建立稳定的建筑物。我们在墙上挂了一张日历,上面写满了一年,每天都有一个小正方形。如果Qagroup每天收到一个通过提交测试的稳定版本,那么他们就会在当天贴上一个绿色标签,否则就是一个红色方块。随着时间的推移,日历显示了构建过程的状态,显示出一个稳定的改进,直到绿色方块如此常见,日历消失了——它的目的实现了。

自动化部署

To do Continuous Integration you need multipleenvironments,一个运行提交测试,运行一个或多个辅助测试。因为您一天要在这些环境之间移动多次可执行文件,你会想自动完成的。因此,重要的是要有能够让您轻松地将应用程序部署到任何环境中的脚本。

这样做的一个自然结果是,您还应该拥有允许您以类似的方式部署到生产中的脚本。您可能不会每天都部署到生产中(尽管我遇到过这样的项目)。但自动化部署有助于加快进程并减少错误。It's also a cheap option since it just uses the samecapabilities that you use to deploy into test environments.

如果部署到生产环境中,您应该考虑的一个额外的自动化能力是自动回滚。坏事时常发生,如果发臭的眉毛碰到旋转的金属,能够迅速回到最后一个已知的良好状态是很好的。能够自动恢复也减少了许多部署的紧张,encouraging people to deploy more frequently andthus get new features out to users quickly.(RubyonRailsCommunity开发了一个名为卡皮斯特拉诺这是一个很好的例子,一个工具可以做这种事情。)

In clustered environments I've seen rolling deploymentswhere the new software is deployed to one node at a time,gradually replacing the application over the course of a fewhours.

我在公共Web应用程序中遇到的一个特别有趣的变化是将心房构建部署到用户的一个子集上。然后,在决定是否将其部署到完整的用户群之前,团队将了解如何使用初始构建。这允许您在提交最终选择之前测试新功能和用户界面。自动部署,与良好的CI纪律联系在一起,做这件事很重要。


持续集成的好处

总的来说,我认为持续整合的最大和最广泛的好处是降低风险。我的思想仍然回到我在第一段中提到的早期软件项目。他们在那里完成了他们希望的项目,然而,他们不知道还要多久才能完成任务。

延迟集成的问题是很难预测它需要多长时间才能完成,更糟糕的是,很难看到你在这个过程中走了多远。结果就是你将自己置身于一个项目中最紧张的部分之一的一个完全的盲点中——即使你是一个不迟到的稀有群体。

Continuous Integration completely finesses thisproblem.没有长期的整合,你完全消除了盲点。在任何时候你都知道你在哪里,什么起作用,什么不起作用,您的系统中的突出错误。

臭虫-这些是破坏信心,扰乱日程和名誉的讨厌的事情。已部署软件中的错误会让用户对您生气。Bugs in work in progress get in yourway,making it harder to get the rest of the software working correctly.

Continuous Integrations doesn't get rid of bugs,但这确实使它们更容易被发现和移除。在这方面,它就像是一个自动测试代码。如果您引入了一个bug并快速检测它,那么很容易摆脱它。因为你只改变了系统的一小部分,你没什么好看的。因为这个系统就是你刚用过的,它在你的记忆中是新鲜的-再次使它更容易找到虫子。您也可以使用扩散调试-将系统的当前版本与没有bug的早期版本进行比较。

错误也是累积的。你的虫子越多,硬汉要把每一个都拆下来。这部分是因为你有错误的互动,故障显示为多重故障的结果-使每个故障更难找到。这也是一种心理现象——当有很多错误的时候,人们没有足够的精力去发现和清除它们——这种现象被广大的程序员称为破窗综合征.

因此,具有持续集成的项目往往具有显著更少的错误,生产和在制品。不过,我要强调的是,这种好处的程度直接关系到您的测试套件有多好。您应该发现构建一个具有显著差异的测试套件并不太困难。通常,然而,一个团队真正达到他们有可能达到的低级别的bug需要一段时间。到达那里意味着不断的工作和提高你的测试。

如果你有持续的整合,它消除了频繁部署的最大障碍之一。频繁部署很有价值,因为它允许您的用户更快地获得新功能,为了对这些功能提供更快速的反馈,在开发周期中,通常会变得更加协作。这有助于打破客户和开发之间的障碍——我认为这是成功软件开发的最大障碍。


引入持续集成

所以你想尝试持续集成-从哪里开始?我上面概述的全套实践为您提供了全部好处——但您不需要从所有的实践开始。

There's no fixed recipe here - much depends on the nature ofyour setup and team.但我们可以从中获得一些东西来推动事情的发展。

第一步是使构建自动化。在源代码管理中获取您需要的一切,这样您就可以用一个命令构建整个系统。对于许多项目来说,这不是一个小的任务——但它对于其他任何事情都是必不可少的。最初,你只能偶尔根据需要进行构建,或者只是做一个自动的夜间构建。虽然这些不是持续集成,但每晚自动构建是一个很好的步骤。

在构建中引入一些自动化测试。试着找出出问题的主要区域,并自动测试以暴露这些故障。尤其是在一个现存的项目上,很难获得一套真正优秀的测试,这需要时间来构建测试。但是你必须从某个地方开始——所有关于罗马建造计划的陈词滥调都是老生常谈。

尝试加速提交生成。在建筑上持续集成几个小时总比什么都没有好,但是,把十分钟的神奇数字记下来要好得多。这通常需要对您的代码库进行相当严重的操作,因为您会中断对系统缓慢部分的依赖。

如果你要开始一个新项目,begin with ContinuousIntegration from the beginning.注意构建时间,一旦开始慢于10分钟的规则,就立即采取行动。通过快速的操作,您将在代码库变得如此庞大之前进行必要的重构,从而使其成为主要的痛苦。

最重要的是获得一些帮助。找到以前做过持续整合的人来帮助你。像任何一种新技术一样,当你不知道最终结果是什么时,很难引入它。找个导师可能要花钱,但如果你不这样做,你也会损失时间和生产力。(免责声明/广告-是的,我们会在这方面做一些咨询。After all we've mademost of the mistakes that there are to make.)


最后的想法

自从我和马特在这个网站上写了原稿以来,持续集成已成为软件开发的主流技术。几乎所有的思想工作项目都没有它——我们看到其他人在世界各地使用CI。我几乎没有听说过关于批准的负面消息——不像一些更有争议的极端计划做法。

如果您不使用连续集成,我强烈建议您尝试一下。如果你是,maybe there are some ideas inthis article that can help you do it more effectively.在过去的2年里,我们获得了很多关于持续整合的信息,我希望还有更多的东西需要学习和改进。


进一步阅读

像这样的一篇文章只能涵盖这么多的内容,但这是一个重要的主题,因此我创建了一个指南页on my website to point you to more information.

为了更详细地探索持续集成,我建议您看看保罗·杜瓦尔的适当的标题簿在这个问题上(它赢得了一个震动奖——比我以前管理的还要多)。关于更广泛的连续交付过程,看一看Jez Humble和Dave Farley的书- which also beat me to a Jolt award.

您还可以在ThoughtWorks网站.


Share:
如果你觉得这篇文章有用,请分享。我感谢你的反馈和鼓励

有关类似主题的文章…

…查看以下标签:

流行的 敏捷的 连续输水 extreme programming


致谢

首先,我要向KentBeck和我的许多同事介绍Chrysler综合补偿(C3)项目。这是我第一次有机会看到持续集成与大量的单元测试。它向我展示了可能的东西,给了我很多年的灵感。

感谢Matt Foemel,Dave Rice以及其他所有在Atlas上构建和维护持续集成的人。这个项目是一个更大范围的CI的标志,显示了它对现有项目的好处。

Paul Julius杰森叶Owen RodgersMike Roberts和其他许多开源贡献者都参与了CruiseControl的一些变体的构建。尽管一个CI服务器并不重要,大多数团队认为这很有用。CruiseControl和其他CI服务器在推广和启用软件开发人员使用持续集成方面发挥了很大作用。

我在ThoughtWorks工作的原因之一是能够很好地接触到由有才华的人完成的实际项目。我访问过的几乎每个项目都提供了大量连续集成信息。

重要修改

01 2006年5月:完成文章的重写,使ITUP更新,并澄清对方法的描述。

2000年9月10日:已发布原始版本。