Python 高手编程系列四百七十一:持续的开发过程

有很多过程,可以大大简化你的开发,并减少应用程序从准备到发布或部署到生产环境中的时间。它们的名字中往往包含持续(continuous)二字,我们将在本节讨论最重要和
最受欢迎的一个。重要的是要强调它们是严格的技术过程,所以它们几乎与项目管理技术
无关,虽然它们可以非常接近后者。
我们将提到的最重要的过程如下。
● 持续集成(continuous integration)。
● 持续交付(continuous delivery)。
● 持续发布(continuous deployment)。
列出的顺序很重要,因为它们中的每一个都是前一个的扩展。持续部署可以被简单地
理解为持续交付的变种。我们将单独讨论它们,因为对于一个组织来说,即使微小的差别
在其他组织可能是至关重要的。
事实上,这些技术过程意味着它们的实现严格依赖于正确工具的使用。每个过程背后
的想法是相当简单的,所以你可以建立自己的持续集成/交付/部署工具,但最好的方法是选
择已经建成的工具。这样,你可以更专注于构建你的产品,而不是浪费在持续开发的工具
链上。
持续集成
持续集成,通常缩写为 CI,是一个从自动化测试和版本控制系统中受益的过程,它提
供全自动集成环境。它可以与集中式版本控制系统一起使用,但实际上,只有在使用良好
的 DVCS 工具管理代码时,它才会更好地发挥作用。
创建一个仓库是实现持续集成的第一步,这是出自极限编程(eXtreme Programming,
XP)中一则软件实践。这些原则在维基百科中有清楚的描述,并定义了一种确保软件易于
构建、测试和交付的方法。
实现持续集成的第一个并且最重要的要求是拥有一个完全自动化的工作流程,该流程
可以测试整个给定修订的应用程序,以确定它是否在技术上是正确的。技术上正确的意思
是它是没有已知的错误,所有的功能可以按预期正常工作。
CI 背后的大体思想是,测试应该总是在合并到主开发分支之前运行。这只能通过开发
团队中的正式安排来处理,但实践表明这不是一个可靠的方法。问题是,作为程序员,我
们倾向于过度自信,无法批判性地看待我们的代码。如果持续集成仅仅建立在团队安排上,
它将不可避免地失败,因为一些开发人员最终会跳过测试阶段,并向可能向始终应保持稳
定的主开发分支提交可能出错的代码。而且,在现实中,即使简单的改变也能引入严重的
问题。
常见的解决方案是使用专用的构建服务器,每当代码库发生更改时就自动运行所有必
需的应用程序测试。有许多工具可以简化此过程,并且可以轻松地与版本控制托管服务(如 GitHub 或 Bitbucket)和自建服务(如 GitLab)集成。使用这样的工具的好处是,开发者可
以仅在本地运行所选择的测试子集(取决于他,与他当前的工作相关),并且为构建服务器
留下潜在的整套集成测试的耗时。这真的加速了开发,并且降低了新特性将破坏主代码分
支中现有稳定代码的风险。
使用专用构建服务器的另一个优点是,测试可以在更接近生产的环境中运行。开发人
员还应该尽可能地使用与生产相匹配的环境,并且有很好的工具(例如 Vagrant);但是,
很难在任何组织中实施这一点。你可以在一个专用的构建服务器上或者甚至在构建服务器
集群上轻松地完成。许多 CI 工具通过利用各种虚拟化工具来减少问题,这些工具有助于确
保测试始终在相同且全新的测试环境中运行。
如果你创建必须以二进制形式把桌面或移动应用程序分发给用户,那么拥有构建服务
器也是必须的。显然,可以在同一个环境中总是执行同样的构建过程。几乎每个 CI 系统都
考虑到在测试/构建完成后,应用程序通常需要以二进制形式下载的事实。这种构建结果通
常被称为构件(build artifacts)。
因为 CI 工具起源于大多数应用程序是用编译型语言编写的时候,所以它们大多使用术
语“构建”来描述它们的主要活动。对于诸如 C 或 C ++之类的语言,这是显而易见的,因
为如果不构建(编译),应用程序不能运行和测试。对于 Python,这样做没有一点意义,因
为大多数程序以源形式分发,并且可以在没有任何额外构建步骤的情况下运行。因此,在
我们的语言范围内,构建和测试术语在谈论持续集成时通常可以互换使用。
测试每一个提交
持续集成的最佳方法是在推送到中央仓库的每个更改上执行整个测试套件。即使一个程序
员在一个分支中推送了一系列的多个提交,通常也有必要分别测试每个更改。如果你决定只在
一个版本库推送中测试最新的变更集,那么很难找到从中引入问题的回归问题的来源。
当然,许多 DVCS(如 Git 或 Mercurial)允许你通过提供等分历史修改记录的命令来
限定搜索回归源的时间,但在实践中,作为连续集成过程的一部分自动执行这些命令会更
加方便。
当然,有一个问题,项目有个非常耗时的测试套件,可能需要几十分钟甚至几个小时才
能完成。在给定的时间段内,一个服务器可能无法对每个提交执行所有构建。这将使等待结
果更长。事实上,长时间运行测试本身就是一个问题,这将在后面的“问题 2—过长的构
建时间”部分中描述。现在,你应该知道你应该总是努力测试每个推送到仓库的提交。如果你
没有权限在单个服务器上执行此操作,请设置整个构建集群。如果你使用付费服务,则需要为
更多的并行构建支付更高的价格。硬件比较便宜,但是你的开发人员的时间却不是。最终,通
过更快的并行构建和更昂贵的 CI 计划,比你跳过选择更改的测试,你可以节省更多的费用。
使用 CI 测试合并
现实中,情况通常很复杂。如果特性分支上的代码通过所有测试,但并不意味着在合
并到稳定的主流分支时构建不会失败。在 Git 工作流和 GitHub 工作流部分中提到的流行分
支策略都假设合并到主分支的代码总是被测试和部署。但是如果你还没有执行合并,你怎
么能确保满足这个假设?由于它比较强调发布分支,这是 Git 工作流中一个次要的问题(如
果良好地实施并精确地使用)。但是对于简单的 GitHub 工作流来说,这是一个真正的问题,
合并到 master 通常与冲突相关,并且很可能在测试中引入回归。即使对于 Git 工作流,这
是一个严重的问题。这是一个复杂的分支模型,所以可以肯定的事是,人们会在使用它时
犯错误。所以,如果你不采取特殊的预防措施,你永远不能确保主代码在合并后通过测试。
这个问题的解决方案之一是把合并特性分支到的稳定主分支的责任委托给 CI 系统。在
许多 CI 工具中,你可以轻松地按需设置构建作业,这个作业可以在本地将特定的特性分支
合并到稳定分支,并将其推送到中央仓库(仅当它通过所有测试时)。如果构建失败,则这
样的合并将被恢复,使得稳定分支不被触及。当然,这种方法在快节奏项目中变得更加复
杂,其中许多特性分支是同时开发的,因为存在不能由任何 CI 系统自动解决的高冲突风险。
当然,这个问题也有解决方案,例如 Git 中的变基(rebase)。
如果你正在考虑进一步实施持续交付过程,这种将任何内容合并到版本控制系统中的
稳定分支的方法实际上是必须的。如果你的工作流中有一个严格的规则,证明稳定分支中
的所有内容都是可发布的,那么也需要这样做。
矩阵测试
如果你的代码需要在不同的环境中测试,矩阵测试(matrix testing)是一个非常有用的
工具。根据你的项目需求,CI 解决方案中可能或多或少地需要支持这样的功能。
解释矩阵测试的最简单的方法是以一些开源的 Python 包为例。例如,Django 是一个对
Python 语言版本的支持集合有着对严格规定的项目。1.9.3 版本列出了 Python 2.7,Python 3.4
和 Python 3.5,这是运行 Django 代码所必须的。这意味着每当 Django 核心开发人员对项目
进行更改时,必须在这 3 个 Python 版本上执行完整的测试套件,以支持此声明。如果单
个测试在一个环境中失败,整个构建必须标记为失败,因为向后兼容性约束可能被破坏。
对于这种简单的情况,你不需要 CI 的任何支持。有一个强大的工具 Tox(参考
https://tox.readthedocs.org/),除了其他功能,还允许你在不同 Python 版本的独立虚拟环境
中轻松地运行测试套件。这个实用程序也可以很容易地用于本地开发。
但这只是最简单的例子。通常情况下,必须在完全不同参数的多个环境中测试应用程
序。举几个例子如下。● 不同操作系统。
● 不同数据库。
● 不同版本的支持服务。
● 不同类型的文件系统。
全套组合形成一个多维环境参数的矩阵,这就是为什么这种设置被称为矩阵测试。当
你需要这样的深度测试工作流时,很可能需要一些集成支持,以便在你的 CI 解决方案中进
行矩阵测试。使用大量可能的组合,你还需要一个高度可并行化的构建过程,因为在每个
矩阵上的运行都需要在构建服务器进行大量的工作。在某些情况下,如果你的测试矩阵有
太多的维度,你将被迫做一些权衡。

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值