引言

持续集成,简称CI,是一项由Grady Booch提出的技术,它鼓励开发者们持续不断地将他们的代码合并到主干源码仓库。

这些'合并'或者'提交',每一次并入到仓库通常都伴随着执行一系列的自动化任务:代码的编译,单元测试和集成测试的执行,评判代码质量是否下降的静态代码质量分析等等。

这些自动化任务有助于验证新代码的合理性,并分辨出新代码是否会造成任何破坏,例如,集成方面是否有遇到问题?最重要的是,开发者们可以在提交代码变更之后快速及时地收到这一反馈。

拥有CI设施和流程被视为是绝大多数现代软件公司的一个基本要求 —— 无论组织是否采用敏捷方法,DevOps,或者两者兼而有之。

由于能够为开发者和客户两者带来可观的收益,CI已然成为任何软件开发流程里的必要部分。这些可以看到的收益包括软件质量,更快交付到市场,更快的缺陷反馈周期,更低的开发成本,以及整个软件流程里集成问题发生频率的降低。

敏捷里的CI

敏捷开发 —— 过去十年来基于十二项原则建立起来的最常用的软件开发方法;这十二项原则里的其中三项强调了快速开发周期和及时的反馈循环:

  1. 客户是满意的,他们得到了更早并持续交付的有价值的软件
  2. 可工作的软件被定期地交付(以周计,而不是月)
  3. 可工作的软件是整个流程的衡量准则

CI流程和一些工具是用来实现这些众多目标的一部分。

在一个鼓励早期反馈循环和持续交付可工作软件的环境里,CI使得开发者们能够通过自动化质量保证和构建流程,带着信心持续地提交变更。借助CI设施,每一次签入仓库的集成问题以及代码质量的可接受水平都能够被验证。

DevOps里的CI

'DevOps'这个术语被用来描述一组为了提高整体软件项目的交付效率而将'开发'和'运维'整合到一起的实践及方法。

最近几年,DevOps在许多组织中获得了很多关注,尤其是那些处理构建大型复杂软件的企业。

DevOps是一种文化上的转变,它鼓励组织内的不同部门 —— 开发,测试和IT运维相互沟通和协作。DevOps的目标不是单靠一款工具就能实现的。这里有一组共同组成所谓“DevOps工具链”的各个阶段,每个都有其单独的目标。依赖于组织的选择,存在着各种各样的工具可以让我们实现那些目标。

一般来说,DevOps工具链包含下面这些:

devops-toolchain

图片来自: https://commons.wikimedia.org/wiki/File:Devops-toolchain.svg

CI流程涉及到该工具链里的两个阶段,即创建和验证。创建阶段包括代码开发,将代码签入版本控制系统等。验证阶段则包括自动构建产品并对其进行测试。

DevOps文化的其余部分则是基于这两个基本组成。没有CI的话,很难看到敏捷开发的好处,也几乎不可能创造出DevOps文化。

通过CI流程建立的开发工作流

通过上述对于CI如何结合敏捷开发以及DevOps方法的介绍和基本了解,现在我们将进一步介绍一个典型的CI流程,它用在主干代码库新功能的引入。

  1. 签出代码

开发人员最开始首先从源码管理系统里签出或者克隆最新的代码到本地开发机器。随后,开发人员继续基于主干分支创建出一个新的功能分支。该分支将专门用于引入仅在新功能范畴内的更改。

  1. 开发新功能

这一阶段即编写新功能所需的代码。

请记住,代码的更改不仅有功能代码的变动,还包括新代码的单元测试和集成测试。

  1. 早期集成并且持续进行

在一个团队里工作时,可能有众多开发者正在同时开发多个功能特性,然后提交变更到主干分支。如此一来,新功能因为和主干分支不同步而落后的时间便会变得越来越长。

因此,建议开发人员经常保持他们的代码和主干代码分支的内容同步。该步骤将会把主干分支的变更带到功能分支,所以除了自己的功能代码之外,开发人员总是使用主干分支代码的最新副本。

开发人员必须在他们的功能分支上执行自动化测试。如果这些测试或者代码本身编译失败的话,他们必须修复这些集成问题。

和主干分支的同步会一直被保留,等到功能被完整实现,新的代码会被发起集成到主干代码库。

一般来说,建议每个开发者从主干分支同步到他们的功能分支至少一天一次。

  1. 自动构建和验证

当有变更提交到主干分支时,无论他们的变动有多小;它将会发起一次自动构建流程,编译代码然后执行单元和集成测试。

这个过程会验证新代码有没有破坏任何现有正在工作的代码。

当然,它也假设在这个阶段运行的由开发者他们自己提供的所有测试都是之前步骤的一部分。

因此,即便显而易见,我们仍然需要强调的是,开发人员必须提供足够的测试用例来验证代码的可执行性。在没有合适的测试用例的前提下,验证这一过程将无法达到必要的水平。这些测试覆盖的代码量称为代码覆盖率 - 更高的覆盖率,意味着更好的验证效果。

  1. 将变更提交到主干分支

当功能被认为是完全满足开发者和相关人员的需求时,功能分支的代码便需要被合并到主干分支。

在做这件事情之前,功能分支需要和主干分支再同步一次而开发者需要确认该次构建和验证步骤没有错误,全部通过。

如果开发者经常集成的话这一步会更轻松并且没有压力,否则的话它通常会变成一个合并冲突的噩梦,即出现开发者们一起协同工作的代码仓库,其代码存在冲突并且针对相同的文件有覆盖变动的情况。

用户会发现上述步骤同之前提到的敏捷开发和DevOps的目标是多么的相似而且点明了它们的主旨!

优点

引入CI的优点有很多,主要是关于代码变更以及代码质量的快速反馈(无论正面还是负面)。

  1. 自动化验证代码变更的过程。通常这些步骤在开发人员的本地机器上也可以通过一条命令手动执行!
  2. 在软件开发的早期发现缺陷
  3. 在早期发现与其他代码和组件的集成问题
  4. 自动化测试代码的能力
  5. 由于代码质量的提升,客户也因此感到很愉悦
  6. 能够上线一个软件开发的一小部分,验证每个位是否完全正常运行,没有错误
  7. 能够针对每次提交以及整体代码引入衡量代码质量的手段,并且对代码质量把关
  8. 缩短开发复杂软件的市场交付时间
  9. 减少软件开发的大爆炸方式造成的代码合并冲突和无法预料的行为,即所有内容大块地合并到主干分支的情况(通常在一个项目生命周期结束的时候)。

难点

用"缺点"一词来描述这部分内容的话可能不是一个好选择,因为CI只会给每个人带来好处(不仅仅开发者,还有客户),所以我更倾向于使用"难点"一词。

  1. 不经历重大的返工的话,遗留系统的架构可能无法支持CI;
  2. 很难对遗留代码引入CI。遗留代码大都缺少自动构建系统的支持。一般它们都是手动发起构建或者是以一个半自动的方式。为了克服这一问题,通常我们需要为此引入一个重度耗费人力物力的现代构建系统。任何希望迁移到CI的遗留系统首先考虑的应该是将引入一个新的自动构建系统作为起点;
  3. 遗留代码一般都缺少自动化测试。这将会使得它很难或者根本不可能检查已经提交到主干分支的新代码的正确性。CI的主要目的(即早期发现问题)没有测试是不可能办到的。

  4. 在文化上,组织可能没有采用敏捷原则或DevOps的工作方式。在开发周期里,持续不断地提交到仓库这件事情可能不会发生,从而使得CI变得没有意义。除此之外,每个组织也有它的政治因素在内,使得在实现CI的过程中可能遭遇各种各样的磨难。

小结

笔者已经介绍了CI的基本原理,为什么需要它,采用的典型流程是什么,收益以及短板等等。

大体上来说,企业组织利用CI不仅仅只是为了编译代码和执行测试,还可以确定其他可衡量的方方面面,比如代码质量,代码覆盖率,使用自动化测试衡量的性能等等。

一些组织也会去拓展CI的用例场景,不仅仅只是用于验证代码的可用性,还用于在一个测试或者生产环境打包和安装构建。这被称为持续交付或持续部署。

持续集成应该是大多数公司制作复杂软件的目标。一旦CI的基本设定到位,开发流程便不会再有什么特别的开销。如果要说有什么变化的话,大多数团队都会发现,引入CI流程和相关工具将会使得集成问题大大减少,并允许团队更快速、自信地开发软件。

继续前行 - CI服务器及工具化

上述内容里笔者没有提到辅助实现CI的一些工具,因为这是一种除了自动化构建之外不需要特定工具的实践。拥有一个源码管理仓库以及一个持续集成服务器是有利无害的。CI服务器和其他一些相关工具的内容将会在持续集成系列的下一篇文章里介绍。

About Author

colstuwjx

colstuwjx

互联网运维工程师,IT屌丝一枚,好技术。