持续集成是一种软件开发实践,团队成员频繁将他们的工作成果集成在一起(通常每人每天至少提交一次,这样每天就会有多次集成);每次提交后,自动触发运行一次包含自动化验证集的构建任务,以便能尽早发现集成问题。
早在 20 世纪 80 年代,微软 Office
产品研发团队就使用一种开发实践,称作每日构建(daily build),也叫每晚构建(nightly build)。
它是指每天定时自动执行一次软件构建工作,也就是将当前版本控制系统中的源代码检出到一个构建环境(即没有安装集成开发环境的干净机器)中,对其进行编译、链接、打包的过程。
执行每日构建有助于确保开发人员明确了解他是否在前一天的代码编写过程中引入了新的问题。每日构建通常包含少量的自动化冒烟测试,这可以帮助团队确定是否新的变更破坏了原有的功能。其关键部分在于,每次构建一定要包含新的代码修改和测试。
“冒烟测试” 这一术语来源于电子硬件测试。硬件样品只要通电后没有冒烟,就说明该硬件最基本的质量要求达到了。
一次集成过程
- 开发人员将代码提交到代码仓库;
- 持续集成服务器按一定的时间间隔(如每隔 1 分钟)对代码仓库进行轮询,发现有代码变更。
- 持续集成服务器自动将最新代码检出到已准备好的专用服务器上(如果应用规模不大,可以与持续集成服务器是同一台机器)。
- 在专用服务器上运行由持续集成服务器指定的构建脚本或命令,对最新代码进行检查(如代码动静态扫描、编译打包、运行单元测试、部署并运行功能测试等)。
- 运行结束后,将验证结果(成功或者失败)反馈给开发团队。
六步提交法
纪律是团队高效协作的保障,每个人都应该遵循下面 6 个工作步骤:
一、检出最近成功的代码
工程师开始工作时(例如工作日早上刚刚开工认领了一个新的开发任务),就要将最近一次构建验证成功的代码版本从团队的开发主干上检出(checkout)到自己的开发工作区中。
二、修改代码
在个人工作区中对代码进行修改(包括实现产品新功能的代码,甚至编写对应功能的自动化测试用例)。
三、第一次个人构建
当开发工作完成并准备提交时,首先执行一个自动化验证集,对自己工作区的新代码执行第一次个人构建(有时也被称为本地构建),用于验证自己修改的代码质量是否达标。
四、第二次个人构建
从“检出代码”到“第一次个人构建完成”这段时间内,很可能在开发主干上有其他成员已提交了新代码,并通过了持续集成的质量验证。此时,就需要将这个版本的代码与自己本地修改的代码进行合并(merge),然后再次执行一次质量验证,确保自己的代码与其他人的代码都没有问题。
五、提交代码到团队主干
当第二次个人构建成功以后,提交代码到团队开发主干。
六、提交构建
持续集成服务器发现这次代码变更,立即开始执行提交构建,运行自动化质量验证。如果这次构建失败,则应该立即着手修复,并马上通知团队成员,禁止其再向团队开发主干提交代码,并且不要检出这个版本。
四个关键点
一、六步提交法中的 3 次验证有什么作用?
3 次验证分别是第 3、4 和 6 步。命令相同,脚本一致,为什么还要执行 3 次呢?
第 3 步的个人验证目标是验证开发者自己修改过的代码是否正确。
第 4 步的个人验证是确保其他人的代码与自己的代码合并后,两部分的代码质量都没有问题。
第 6 步的提交构建验证是在一个干净且受控环境中执行与第 4 步个人构建相同的内容,以确保开发人员的本次提交是完整且无质量问题的,没有遗漏。
二、个人验证一定要做两次吗?
第一次个人验证的目标是验证自己的修改是符合质量预期的。
第二次个人验证的目标是验证自己改动的代码和其他人提交的代码合并在一起,也符合质量预期。
三、如何确保在提交前执行个人构建?
一种方式是在提交代码之时,由持续集成平台通过钩子(hook)捕获提交事件,在代码合并到主干之前,强制进行第二次个人验证。
当然,我们也可以通过团队口头 约定的方式,要求团队成员遵守这一要求。
四、每次构建应该包含哪些质量验证内容?
自动化单元测试并不能覆盖软件的所有运行场景。因此,除单元测试以外,我们仍旧希望在个人验证环节和提交构建验证中能运行更丰富的质量验证集合,如代码动静态扫描、代码规范检查、构建验证测试等。
在条件允许的情况下,如果能够运行所有的自动化质量保证手段,就更棒了!
构建验证测试(build verification test)是指检查如下内容:
- 构建结束后生成的二进制包是否包含了正确的内容,例如配置文件的完整性。
- 这个构建结果是否能够正确安装并正常启动运行起来。
- 启动后最基本的功能是否可以使用,如用户登录等。
代码规范检查的工具相对丰富且成熟,而且最容易执行。它与自动化测试相比,执行成本较低。不需要团队自行编写大量代码,只需要制订团队的编码规范,并在规范检查工具中配置相应的扫描规则,即可使用。
自查表
如果想知道自己的团队是否达到了持续集成的最佳状态,则可以从下面 6 个方面进行自我检查:
- 主干开发,频繁提交;
- 每次提交应该是一个完整的任务;
- 让提交构建在 10 分钟以内完成;
- 提交构建失败后应禁止团队成员提交新代码,也不许其他人检出该代码;
- 立即在 10 分钟内修复已失败的提交构建,否则回滚代码;
- 自动化构建验证通过后,对软件质量有比较大的信心;
在团队中实施持续集成实践
- 构建脚本化,搭建持续集成框架;
- 向构建中添加已有的自动化验证集合;
- 选择利于持续集成的分支策略;
- 建立六步提交法;
- 持续优化;
- 工程师改变习惯,并提升技能;
工程师的开发习惯
在没有进行持续集成实践之前,很多公司对开发工程师的代码提交粒度和频率并没有太多要求,尤其是使用传统瀑布开发方法的组织。
如果工程师习惯于长时间不与其他人的代码进行集成,则在刚刚开始使用持续集成实践时,很难立即达到前面所说的“持续集成最佳状态”,如小步提交、代码完整、不影响已有功能等。
但是,如果能够遵循第 6 章中对需求拆分的实践,则有助于加快质量反馈速度,达成良好的持续集成效果。强调开发质量和质量打磨周期的持续缩短是影响工程师习惯的入手点。
视而不见的扫描问题
扫描的结果常会被工程师忽视。其原因可能有两个:
- 团队成员对扫描规则没有达成一致,部分工程师对其中的问题有异议,但这种异议被管理者所忽视。
- 扫描出来的问题太多,无从下手修复。
第一个问题的原因是团队技术管理问题,代码规范没有统一标准。此时,首先应该由团队技术负责人与团队一起学习代码规范,讨论并制订团队的代码标准,并记录达成一致的检查项,再进行自动化扫描。
第二个问题通常发生在产品研发进度紧张的时候。此时应该执行“童子军营地法则”,即保持质量指标不再恶化,例如,“每次提交代码都让问题数减少,至少不能增加”;或者限期整改,如“3 个月内将严重问题清零”。同时,也可以开发一些方便易用的工具,工程师可以用它方便地发现相关的编码规范问题,并及时修正。