持续集成

连续集成的流程图草图

软件工程中,连续集成CI )是每天几次将所有开发人员的工作副本合并到共享主线的实践。如今,它通常以一种触发测试的自动化构建的方式实现。格雷迪·布赫(Grady Booch)1991年的方法中首先提出了CI一词,尽管他没有每天倡导几次整合。极限编程(XP)采用了CI的概念,并确实提倡每天整合一次以上,也许每天多达数十次。

理由

在进行更改时,开发人员副本副本的副本进行工作。当其他开发人员将更改的代码提交给源代码存储库时,此副本逐渐停止以反映存储库代码。现有的代码基库不仅可以更改,而且可以添加新代码以及新的库以及创造依赖性和潜在冲突的其他资源。

在分支机构上,较长的发展持续了,而没有回到主线,当开发人员分支最终合并后,多集成冲突和失败的风险就越大。当开发人员向存储库提交代码时,他们必须首先更新其代码,以反映存储库的更改,因为他们拿了副本。存储库包含的更改越多,开发人员在提交自己的更改之前必须做的越多。

最终,存储库可能与开发人员的基线有很大不同,以至于他们输入有时称为“合并地狱”或“集成地狱”的内容,集成时间超过了进行原始更改所需的时间。

工作流程

本地运行测试

CI应与通过测试驱动开发的实践编写的自动单位测试结合使用。开发人员本地环境中的所有单元测试均应在投入主线之前运行和通过。这有助于防止一个开发人员的过程中的工作破坏另一个开发人员的副本。如有必要,例如使用功能切换,可以在承诺之前禁用不完整的功能。

定期编译主线;运行主线和/或使用连续质量控制

构建服务器定期编译代码。构建服务器可以自动运行测试和/或实施其他连续的质量控制过程。这样的过程旨在通过定期运行其他静态分析,测量性能,从源代码中提取文档并促进手动质量质量检查过程来提高软件质量和交付时间。

使用CI作为连续交付或连续部署的一部分

CI通常与连续交付连续部署在所谓的CI/CD管道中交织在一起。 “连续交付”可确保在主线上签入的软件始终处于可以部署给用户的状态,而“连续部署”完全自动化了部署过程。

历史

关于连续整合的最早已知工作是Ge Kaiser,de Perry和Wm Schell开发的注入环境。

1994年,Grady Booch使用短语连续集成在面向对象的分析和设计中与应用程序(第二版)来解释如何在使用微观过程开发时,“内部发行版代表了系统的一种连续集成,并且存在是为了强制存在关闭微型过程”。

1997年,肯特·贝克(Kent Beck)罗恩·杰弗里斯(Ron Jeffries )在克莱斯勒综合薪酬系统项目中发明了极端编程(XP),包括连续集成。贝克发表了关于1998年连续整合的发表,强调了面对面交流对技术支持的重要性。 1999年,贝克在他的《极限编程》的第一本书中详细阐述了更多。 CruiseControl是最早的开源CI工具之一,于2001年发布。

2010年,蒂莫西·菲茨(Timothy Fitz)发表了一篇文章,详细介绍了IMVU工程团队如何建立和使用第一个实用的CI系统。尽管他的帖子最初受到怀疑,但它很快就陷入了困境,并发现广泛采用是基于IMVU的精益软件开发方法的一部分。

共同的做法

本节列出了各种作者建议如何实现连续集成以及如何自动化此实践的最佳实践构建自动化本身就是最佳实践。

持续集成 - 经常将新代码与现有代码存储库集成或更改的代码的实践 - 应该经常出现,以至于在提交构建之间没有中间的窗口保留,因此如果没有开发人员注意并立即对其进行纠正,则不会出现任何错误。正常的做法是通过每项承诺触发这些构建,而不是定期安排的构建。在快速投入的多开发器环境中这样做的实用性使得通常在每次提交后的短时间内触发短时间,然后在本计时器到期或自上次构建以来较长的间隔后启动构建。请注意,由于每个新提交都重置用于短时触发的计时器,因此这与许多按钮bebouncing算法中使用的技术相同。通过这种方式,“拒绝”提交事件是为了防止在一系列快速施工之间进行不必要的构建。许多自动化工具会自动提供此计划。

另一个因素是需要支持原子化合物的版本控制系统。即,所有开发人员的更改都可以看作是一个单一的提交操作。尝试仅从更改的文件中的一半构建毫无意义。

为了实现这些目标,持续的集成依赖于以下原则。

维护代码存储库

该实践主张将修订控制系统用于项目的源代码。构建项目所需的所有工件都应放置在存储库中。在此实践和修订控制社区中,该惯例是该系统应从新的结帐中构建,而不需要其他依赖项。极端编程的拥护者马丁·福勒(Martin Fowler)还提到,如果工具支持分支,则应将其使用最小化。取而代之的是,更优于集成更改,而不是同时维护的软件的多个版本。主线(或中继)应该是软件工作版本的位置。

自动化构建

单个命令应具有构建系统的能力。许多构建工具,这些工具已经存在多年,例如Make ,而其他最新的工具经常在连续的集成环境中用于自动化构建。 (例如,包含一组用于构建软件的规则的MakeFile可以自动使用Make Build Process。)构建的自动化应包括自动化集成,该集成通常包括部署到类似生产的环境中。在许多情况下,构建脚本不仅编译二进制文件,还会生成文档,网站页面,统计和分销媒体(例如Debian Deb ,Red Hat RPM或Windows MSI文件)。

进行自我测试

构建代码后,所有测试都应进行,以确认其行为按照开发人员的期望的行为。

每个人每天都要承诺基线

通过定期提交,每个参数可以减少冲突的变化数量。检查一周的工作有可能与其他功能发生冲突的风险,并且很难解决。早期,该系统领域的小冲突导致团队成员就所做的变化进行交流。每天至少进行所有更改(每次构建一次)通常被认为是连续集成的定义的一部分。此外,通常建议进行夜间构建。这些是下限;典型的频率预计会更高。

每个提交都应建立(基线)

该系统应构建对当前工作版本的承诺,以验证它们是否正确集成。一种常见的做法是使用自动连续集成,尽管可以手动完成。自动化连续集成使用连续的集成服务器或守护程序来监视更改的修订控制系统,然后自动运行构建过程。

每个错误修正提交都应带有测试用例

修复错误时,最好推动重现该错误的测试用例。这避免了要恢复的修复程序,以及重新出现的错误,这被称为回归

保持快速构建

构建需要迅速完成,以便如果集成存在问题,则将很快确定。

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

生产环境中部署时,拥有测试环境可能会导致测试系统的故障,因为生产环境可能以很大的方式与测试环境有所不同。但是,建立生产环境的复制品是成本良好的。取而代之的是,应构建测试环境或单独的预生产环境(“分阶段”),以作为生产环境的可扩展版本,以减轻成本,同时维持技术堆栈的组成和细微差别。在这些测试环境中,服务虚拟化通常用于获得对依赖项的按需访问(例如,API,第三方应用程序,服务,大型机等),它们超出了团队的控制,仍然不断发展或过于复杂而无法配置在虚拟测试实验室中。

使获得最新的可交付成果变得容易

在重建不符合要求的功能时,使利益相关者和测试人员易于使用的构建可以减少必要的返工量。此外,早期测试减少了在部署直到部署的机会生存的机会。较早发现错误可以减少解决这些错误所需的工作量。

所有程序员都应通过从存储库中更新项目来开始一天。这样,他们都将保持最新状态。

每个人都可以看到最新构建的结果

应该很容易地找出构建是否破裂,如果是,谁做出了相关的更改以及这种变化是什么。

自动部署

大多数CI系统都允许在构建完成后运行脚本。在大多数情况下,可以编写一个脚本将应用程序部署到每个人都可以看的实时测试服务器。以这种思维方式进一步的进步是连续部署,它要求将软件直接部署到生产中,通常具有额外的自动化以防止缺陷或回归。

成本和收益

连续整合旨在产生诸如:

  • 早日检测到集成错误,并且由于小更改而易于追踪。这可以节省项目的寿命。
  • 避免在发行日期时避免最后一刻的混乱,当每个人都试图检查其略微不兼容的版本时
  • 当单元测试失败或出现错误时,如果开发人员需要将代码库恢复为无错误状态而无需调试,则仅丢失了少量更改(因为集成经常发生)
  • 不断可用于测试,演示或发布目的的“当前”构建
  • 频繁的代码签到推动开发人员创建模块化,较不复杂的代码

通过连续的自动测试,收益可以包括:

  • 执行频繁自动测试的纪律
  • 立即对当地变化的全系统影响的立即反馈
  • 由自动测试和CI产生的软件指标(例如代码覆盖代码复杂性功能完整性的指标)的重点开发人员致力于开发功能,质量代码,并帮助在团队中开发动量

连续集成的一些弊端可以包括:

  • 构建自动测试套件需要大量的工作,包括持续的努力涵盖新功能并遵循故意的代码修改。
    • 无论是否采用连续集成,测试本身都被认为是软件开发的最佳实践,并且自动化是测试驱动开发(例如测试驱动的开发)不可或缺的一部分。
    • 可以在没有任何测试套件的情况下执行连续集成,但是如果必须手动和经常完成可释放产品的质量保证成本,则可以很高。
  • 建立构建系统涉及一些工作,并且可能变得复杂,因此很难灵活修改。
  • 如果项目的范围很小或包含无法测试的旧版代码,则连续集成不一定是有价值的。
  • 增值取决于测试的质量以及代码的真正可测试方式。
  • 较大的团队意味着不断将新代码添加到集成队列中,因此跟踪交付(而保留质量)很困难,并且构建排队可以放慢所有人。
  • 每天进行多个提交和合并,可以轻松推动功能的部分代码,因此集成测试将失败,直到功能完成为止。
  • 安全和关键任务发展保证(例如, DO-178CISO 26262 )需要严格的文档和过程中的审查,这些文件很难使用持续集成。当需要对产品进行监管批准时,这种类型的生命周期通常需要在产品释放之前完成其他步骤。

也可以看看