持续集成之道:构建可靠高效的开发流程

本文深入探讨持续集成系统的核心挑战与解决方案,涵盖测试重要性、CI可靠性、执行速度与代码覆盖率等关键议题,为构建世界级软件项目提供实用指导。

持续集成之道

现代软件开发中有一个不言而喻的真理:健全的持续集成(CI)系统是必不可少的。但许多项目却饱受脆弱CI系统之苦,这些系统让开发人员感到沮丧,并严重阻碍开发速度。为什么会这样?如何避免常见的CI陷阱?

持续集成需要明确目标

CI本应提供额外保证,确保项目代码的正确性。然而,开发人员为验证预期功能而编写的测试在最初编写时效用最低。这或许有违直觉,因为开发人员在最初编写代码时最为熟悉。他们从多个角度思考过代码,考虑了许多可能的边缘情况,并实现了相当不错的功能!

遗憾的是,编写代码是编程中最简单的部分。真正的挑战在于构建他人可读的代码,使项目能够长期蓬勃发展。软件熵随时间增加而增加。开发人员——尤其是不熟悉大型长期代码库的开发人员——无法预料他们的代码将如何被集成、重构和重新调整用途,以满足最初未考虑的需求。

当这些重构和扩展发生时,测试是能够自信进行更改的唯一方式。那么,为什么开发人员最终会缺乏高质量测试的系统呢?

琐碎测试的重要性

编写测试时,尤其是为了高代码覆盖率指标,最常见的抱怨是某些测试过于琐碎,没有触及代码库中有趣或容易出错的部分。在考虑当前代码时,这些抱怨是合理的,但现在设想软件可能被重新调整用途。曾经琐碎的部分可能变得微妙。未能测试琐碎情况可能导致工作陷入不可观察行为所隐藏的陷阱迷宫。

请记住以下三点:

  • 从长远来看,没有测试是琐碎的
  • 测试是预期行为的文档
  • 未经测试的代码容易发生意外行为变化

不可靠的CI系统

不可靠的CI对开发人员来说是毒药。对于内部项目,它会降低生产力,让人们讨厌在上面工作。对于开源项目,它驱赶贡献者的速度比他们到来的速度更快。

找出导致测试不可靠的原因并修复它。不可靠的CI通常表现为不稳定的测试,现有工具可以将测试标记为不稳定,直到找到根本原因。这将使CI立即改进,而不会拖累团队。

缓慢的CI流程

你可能会遇到过长的CI周期时间。这是有问题的,因为高质量的开发过程要求所有CI作业都通过。如果周期时间太长太复杂,以至于无法在本地运行,开发人员就会创建变通方法。这些变通方法可能采取多种形式,但最常见的是PR规模膨胀,因为没有人愿意提交一个2行的PR,等待一个小时合并,然后重新调整他们300行的PR。更重要的是,他们可以在单个PR中进行一些不相关的更改。这给代码审查者带来问题,并降低项目质量。

开发人员这样做并没有错,是CI让他们失望了。构建CI系统时,重要的是要牢记延迟预算,即"CI不应慢于时间t,其中t是先验选择的"。如果CI变得比这更慢,那么就需要努力改进它,即使这会侵占新功能的开发。

覆盖率的挑战

负责任测试的一部分是了解测试正在执行哪些代码行——一个简单明了的数字告诉你一切。那么为什么覆盖率如此常被忽视?

首先是技术挑战。现代软件针对许多不同的目标运行。为了有用,CI系统应该针对多个目标运行,这些目标将数据提交到可以合并覆盖率的托管系统。(这类工具失败带来的挫折感,以及如何在所有软件都是热垃圾的情况下保持开发速度是另一个话题。)如果没有这个,服务软件开发人员通常不会注意到遗漏的覆盖率,因为它消失在"预期"遗漏行的噪音中。

现在让我们谈谈社会挑战。软件通常以难以测试小功能片段的方式编写。这个问题催生了测试驱动开发(TDD)趋势,即先编写测试,以帮助开发人员以可测试的方式重构代码。这通常在可读性和可测试性方面是净收益,但需要纪律和不同的开发方法,这对许多人来说并不自然。

使更多代码库可测试的感知苦差事导致抱怨覆盖率是一个不完美的指标。毕竟,并非所有代码分支都是平等的,根据你的语言,某些代码路径永远不应被执行。这些不是否定覆盖率作为有价值指标的好理由,但在特定情况下,可能存在令人信服的理由不花费精力用测试覆盖某些内容。然而,要注意,未能用测试覆盖某段代码,其行为就不再是未来开发人员在重构期间将遵守的契约的一部分。

我们应该怎么做?

那么,面对所有这些障碍,我们如何达到CI的涅槃境界?逐步进行。现有项目是宝贵资产,我们希望保留现有内容,同时提高未来改进的能力。(重写几乎总是一个坏主意。)这需要一种渐进的方法,虽然专门针对给定项目定制,但有一个广泛的配方:

  1. 使CI可靠
  2. 加速CI
  3. 提高测试质量
  4. 改进覆盖率

我们都应该花时间投资于项目的长期性。这种基础性努力会迅速带来回报,并确保你的软件项目能够达到世界级水平。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计