持续集成的关键是自动化。绝大多数的集成都可以而且应该自动完成。读取源代码、编译、连接、测试,这些都可以自动完成。最后,你应该得到一条简单的信息,告诉你这次创建是否成功:"yes"或"no"。如果成功,本次集成到此为止;如果失败,你应该可以很简单地撤消最后一次的修改,回到前一次成功的创建。在整个创建过程中,完全不需要你动脑子。
如果有了这样一套自动化过程,你随便想多频繁进行创建都可以。唯一的局限性就是创建过程本身也会消耗一定的时间。(译注:不过与捉虫所需的时间比起来,这点时间是微不足道的。) [Page]
一次成功的创建是什么样的?
有一件重要的事需要确定:怎样的创建才算是成功的?看上去很简单,但是如此简单的事情有时却会变得一团糟,这是值得注意的。有一次,Martin Fowler去检查一个项目。他问这个项目是否执行日创建,得到了肯定的回答。幸亏Ron Jeffries也在场,他又提了一个问题:"你们如何处理创建错误?"回答是:"我们给相关的人发一个e-mail。"实际上,这个项目已经好几个月没有得到成功的创建了。这不是日创建,这只是日创建的尝试。
对于下列"成功创建"的标准,我们还是相当自信的:
所有最新的源代码都被配置管理系统验证合格
所有文件都通过重新编译
得到的目标文件(在我们这里就是Java的class文件)都通过连接,得到可执行文件
系统开始运行,针对系统的测试套件(在我们这里大概有150个测试类)开始运行
如果所有的步骤都没有错误、没有人为干涉,所有的测试也都通过了,我们就得到了一个成功的创建
绝大多数人都认为"编译+连接=创建"。至少我们认为:创建还应该包括启动应用程序、针对应用程序运行简单测试(McConnell称之为"冒烟测试":打开开关让软件运行,看它是否会"冒烟")。运行更详尽的测试集可以大大提高持续集成的价值,所以我们会首选更详尽的测试。
单一代码源
为了实现每日集成,任何开发者都需要能够很容易地获取全部最新的源代码。以前,如果要做一次集成,我们就必须跑遍整个开发中心,询问每一个程序员有没有新的代码,然后把这些新代码拷贝过来,再找到合适的插入位置……没有什么比这更糟糕的了。
办法很简单。任何人都应该可以带一台干净的机器过来,连上局域网,然后用一条命令就得到所有的源文件,马上开始系统的创建。
最简单的解决方案就是:用一套配置管理(源代码控制)系统作为所有代码的来源。配置管理系统通常都设计有网络功能,并且带有让开发者轻松获取源代码的工具。而且,它们还提供版本管理工具,这样你可以很轻松地找到文件以前的版本。成本就更不成问题了,CVS就是一套出色的开放源代码的配置管理工具。
所有的源文件都应该保存在配置管理系统中。我说的这个"所有"常常比人们想到的还要多,它还包括创建脚本、属性文件、数据库调度DLL、安装脚本、以及在一台干净的机器上开始创建所需的其他一切东西。经常都能看到这样的情况:代码得到了控制,但是其他一些重要的文件却找不到了。
尽量确保所有的东西都保存在配置管理系统的同一棵代码源树中。有时候为了得到不同的组件,人们会使用配置管理系统中不同的项目。这带来的麻烦就是:人们不得不记住哪个组件的哪个版本使用了其他组件的哪些版本。在某些情况下,你必须将代码源分开,但是这种情况出现的几率比你想象的要小得多。你可以在从一棵代码源树创建多个组件,上面那些问题可以通过创建脚本来解决,而不必改变存储结构。
自动化创建脚本
如果你编写的是一个小程序,只有十几个文件,那么应用程序的创建可能只是一行命令的事:javac *.java。更大的项目就需要更多的创建工作:你可能把文件放在许多目录里面,需要确保得到的目标代码都在适当的位置;除了编译,可能还有连接的步骤;你可能还从别的文件中生成了代码,在编译之前需要先生成;测试也需要自动运行。 [Page]
大规模的创建经常会耗费一些时间,如果只做了一点小小的改动,当然你不会希望重新做所有这些步骤。所以好的创建工具会自动分析需要改变的部分,常见的方法就是检查源文件和目标文件的修改日期,只有当源文件的修改日期迟于目标文件时,才会重新编译。于是,文件之间的依赖就需要一点技巧了:如果一个目标文件发生了变化,那么只有那些依赖它的目标文件才会重新编译。编译器可能会处理这类事情,也可能不会。
取决于自己的需要,你可以选择不同的创建类型:你创建的系统可以有测试代码,也可以没有,甚至还可以选择不同的测试集;一些组件可以单独创建。创建脚本应该让你可以根据不同的情况选择不同的创建目标。
你输入一行简单的命令之后,帮你挑起这副重担常常是脚本。你使用的可能是shell脚本,也可能是更复杂的脚本语言(例如Perl或Python)。但是很快你就会发现一个专门设计的创建环境是很有用的,例如Unix下的make工具。
在我们的Java开发中,我们很快就发现需要一个更复杂的解决方案。Matt用了相当多的时间开发了一个用于企业级Java开发的创建工具,叫做Jinx。但是,最近我们已经转而使用开放源代码的创建工具Ant(http://jakarta.apache.org/ant/index.html)。Ant的设计与Jinx非常相似,也支持Java文件编译和Jar封装。同时,编写Ant的扩展也很容易,这让我们可以在创建过程中完成更多的任务。
许多人都使用IDE,绝大多数的IDE中都包含了创建管理的功能。但是,这些文件都依赖于特定的IDE,而且经常比较脆弱,而且还需要在IDE中才能工作。IDE的用户可以建立自己的项目文件,并且在自己的单独开发中使用它们。但是我们的主创建过程用Ant建立,并且在一台使用Ant的服务器上运行。
自测试的代码
只让程序通过编译还是远远不够的。尽管强类型语言的编译器可以指出许多问题,但是即使成功通过了编译,程序中仍然可能留下很多错误。为了帮助跟踪这些错误,我们非常强调自动化测试--这也是XP提倡的另一个实践。