本节书摘来自异步社区《配置管理最佳实践》一书中的第2章,第2.5节,作者: 【美】Bob Aiello , Leslie Sachs著,更多章节内容可以访问云栖社区“异步社区”公众号查看
2.5 构建工具评估和选择
目前有很多好的构建工具,也有很多相关的最佳实践教程。这些教程可以指导你建立一个可靠、可扩展的构建流程。这里将会讨论一些工具和最佳实践,你可以有选择性地实施其中一些来支持公司的开发工作。目前软件开发中主要有几类比较流行的构建工具。不久以前,有段时间构建自动化仅仅意味着使用 Make(也许还有一些 shell 脚本)自动执行构建过程的每一个步骤。这种方法可以很好地支持 C 和 C++ 的构建。但是在实现的时候,要注意底层不同平台带来的差异性。我在 HP-UX, Solaris, AIX 和 Linux 上都用过 Make。 Make 是1977年由斯图尔特·费尔德曼在贝尔实验室创造的。 GNU Make 相对于 Make进步了一些,解决了一些跨平台的构建问题。值得注意的是, Make不仅仅可以用在 C 和 C++的项目上,某些情况下也可以用来构建 Java 的项目。
2.5.1 Apache Ant 进入构建舞台
作为Apache Tomcat 项目的一部分,Ant 最初是由詹姆斯·邓肯·戴维森(James Duncan Davidson)创造的。一开始Ant 是和 Apache Tomcat 被捆绑在一起使用。到2000年7月的时候, Ant 1.1 才作为一个单独产品被发布。Ant 与Make截然不同,它是基于 Java 实现的,而 Make 仅仅是通过一些shell 脚本来构建的。
2.5.2 Maven
Maven 一开始是作为Jakarta Alexandria 项目的一部分在2001开发的,在后来却作为一个单独产品被发布了。 Maven 目标是成为集中整个项目信息源的标准化的构建框架,并自夸:“需要写很多行Ant XML 代码的活,Maven 可以轻松搞定。”Maven 是基于约定优于配置的理念,也就是说 Maven 希望使用者遵守它定义好的声明和约定来使用Maven。Maven 通过生成框架的机制可帮助你初始化一个符合约定的项目。Maven 生成的框架代码可帮助你使用不同的Java 框架。Maven 的生命周期是非常重要的概念,理解好每一个生命周期,有助于使用 Maven的更多功能。
2.5.3 Maven 与 Ant
Ant 需要大量的 XML 代码来描述到底要做什么。从这个意义上说,Ant 比Maven更注重过程。 而Maven 在项目描述上采取了截然不同的做法。Maven规定应用程序应一直遵守一个特定的结构。这也就是前面所说的 Maven 倡导的约定优于配置的概念。 Maven爱好者认为开发人员必须以 Maven 的标准来组织应用程序结构。这样Maven 就知道资源都存储在哪里,哪些是需要构建的,剩下的 Maven 就可以自己完成了。Maven 1.1使用的是 Jelly 脚本,而Maven 2 使用的是纯 Java 的 XML。Maven 有一个定义好的生命周期,理解了Maven的生命周期就可以更大地提高构建效率。在实践中,许多构建工程师使用Ant 插件来拓展 Maven 的功能。 Maven 预先为你定义了项目框架,尽管对于复杂的构建,这个框架可能不是特别顺手。当在两个都备受推崇的工具中选择时,开发者一般都有各自的偏好,有些甚至是固执己见。在曾经工作过的几个公司里,我用 Maven 1.0.2和 Maven 2.0构建过规模相当大的产品,当然也用过Ant 6 和Ant 7。我认为每个备受推崇的工具都有自己的优点和固有缺点。
2.5.4 使用 Ant 生成复杂构建
Ant 被用于生成复杂构建时,很快就会陷于一堆笨重且杂乱的XML中。 Ant 脚本要好好地组织结构,尽量减少每一步之间的依赖,以便其都可以单独地执行。例如,调用源代码管理工具的代码内嵌到 Ant 构建项目的目标(target)当中。 这就导致每次调用Ant 编译Java类的时候都会调用源代码管理工具。其实这是没必要的,因为有可能我在本地做一个构建,而源代码早已经在本地工作空间中,这时根本就不需要重新获取一遍代码。此外当团队从一个源代码管理工具转到另一个时,就必须检查整个项目的 Ant XML文件,修改每一个涉及源代码管理操作的部分。实践中应该避免这样的Ant 组织结构,尽量使每一步都相对独立。还有一点要谈的是当源代码管理系统关机维护或者备份的时候,构建团队就不能构建项目的情况。好的构建工程脚本应该采取结构化的方法,创建开发沙箱后,可以单独地进行编译。构建不应该依赖于源代码管理工具是否正常运行。
2.5.5 持续集成
持续集成是现在十分流行的最佳实践之一,它要求在开发人员每次提交变更到代码库后,都立刻进行构建和部署代码。虽然一开始持续集成流行于敏捷开发领域,但是现在在很多非敏捷开发环境下,持续集成也是一个广受推崇的最佳实践。持续集成系统一直监控源代码管理系统中的变化,一旦有变更就会立刻触发构建。构建的结果会发布在显示面板(dashboard) 上,包括导致最近系统故障的变更、构建失败的变更等。每个持续集成系统都是不一样的,在公司中使用之前,应该根据其功能来评估是否适用。
2.5.6 持续集成系统
目前有很多非常受欢迎的持续集成系统可供选择。持续集成是配置管理中最令人激动的领域,有很多很强大的开源解决方案,当然也包含很多扩展功能的商业产品。在有新代码提交到代码库时,先进的持续集成系统都支持自动发起构建的功能。另外,也可以安排一个特定的时间,例如每天晚上自动触发一个构建。持续集成系统通常都可以识别出最新的变更,尤其是最后造成构建失败的变更。大多数持续集成系统都使用 XML文件进行配置。有些系统已经具有强大的图形化界面,这使管理变得更容易。
2.5.7 集成开发环境
集成开发环境(IDE)可以让开发人员以迭代的方式快速开发应用程序,帮助他们提高工作效率和产品质量。集成开发环境通常会安装一些插件,就可以在里边使用编译器(例如C++ 或 Java的编译器)来构建项目。构建工程师面临的挑战之一就是开发人员只知道在集成开发环境中构建产品,这就会导致其很难写出一个可以在命令行下执行的构建脚本。一些集成开发环境可以生成在命令行下运行的脚本。在集成开发环境中构建出的应用程序是绝对不可以部署到生产环境(或者QA环境)中的。因为通过集成开发环境生成构建的方式在本质上是不可重复的。最大的问题就是开发人员常常不了解那些由集成开发环境隐藏了的构建过程。
2.5.8 静态代码分析
构建工程通常被认为是进行静态代码分析的最好时间点。因为构建工程师控制所有源代码的构建和发布,所以可以插入一些打桩代码(instrument code)生成一个用来进行静态代码分析的构建。自霍尔斯特德复杂性度量(Halstead complexity metrics)成立之初,我就做过静态代码分析的工作。使用静态代码分析工具可找出可能存在的安全漏洞,并且在代码发布之前修复。构建工程师往往是唯一的可以把所有代码都放到一起构建出发布版本的人。构建工程师还可以通过脚本和适当的修改构建出整个系统,这对于静态代码分析来说都是必要的。显然,用来做静态代码分析的构建通常包含打桩代码,所以这样的版本通常也不能部署到生产系统中去。
2.5.9 构建框架
我曾经使用过很多不错的构建框架,它们都可以提供广受好评的结构化方法来开发一个完整的构建解决方案。大多数产品都可以让用户制订构建计划,分配构建代理(build agent),并把所有的结果反馈到统一的构建显示面板上。这些产品也许是整个应用程序生命周期(ALM)解决方案的一部分,也许是扩展了某些特定功能的扩展插件。这个时候就需要花费一段时间评估可用的构建解决方案,然后再为公司选择合适的构建工具。
2.5.10 构建工具的选择
选择合适的工具是一件非常重要的事情,通常包含估计实际需求、进行工具评估和协调团队达成共识。在实践中,许多专业技术人员发现很难选择一个适合自己的工具。这首先就要找到支持项目中所采用技术的工具。下面是一些例子:
GNU make 支持C/C++
Ant, Maven 或 GNU make 支持Java
MS Build 或 GNU make 支持 .NET (e.g. C#)
2.5.11 对比优缺点达成一致
在选择工具的时候,应该尽可能地让所有利益相关者都加入到这个过程中。在一些公司当中,是开发部门做决定说我要选择哪个工具;而另外一些公司,则是以更民主的方式来选择。很久以前,一夜之间大家都开始谈敏捷开发。心理学家发现自我管理的团队更有效,尤其是获得高生产效率和高产品质量方面。自我管理团队,顾名思义,有权力来评估和选择自己团队使用的工具。达成共识是任何一个成功的自我管理团队的核心竞争力之一。每种方法都有优点和缺点。我的建议是哪种方法适合自己公司的文化,就以哪种方法去选择工具。总体而言,在软件开发工作中,调研工具,对比工具优缺点,分享评估结果,最后达成一致往往是选择工具或者流程最好的方式。