译:Not Rocket Science

原文:https://graydon2.dreamwidth.org/1597.html
作者:graydon2
译者:ChatGPT 4 Turbo

关于我去年写的一个程序 bors 及其一些血统的技术说明。除非你的职业是构建软件,否则这会令人无比乏味,如果你正好是,我推荐你花一分钟时间阅读它。

十三年前,我在 Cygnus/RedHat 工作时,参与了一个项目,项目中有一位来自澳大利亚、非常实在的黑客 Ben Elliston。我们面临着一个有些噩梦般的跨时区集成测试场景,这个场景对于承认 CVS(当时的版本控制仓库)中的瞬时错误有着严重的惩罚。为了尝试保持项目的控制,Ben、Frank 和团队中可能还有其他几个人构建了一个由 cron 作业、rsync、多个 CVS 仓库以及一个追踪测试结果的小型 postgres 数据库组成的系统。

这个系统有一个简单的任务:自动维护一个总是通过所有测试的代码仓库它给了我们安心(客户只从那个仓库拉取代码,所以永远看不到错误),并且具有重要的次要好处:工程师可以从已知良好的修订版开始他们一天的工作,无需寻找别人不小心引入的错误。因为系统是自动化的,我们知道没有人会急于提交一些马虎的东西。你可以把所有你想要的马虎的东西提交到 非自动化 的仓库;如果它破坏了任何测试,就会被自动化过程拒绝。不宽容,但公平。那时我觉得我学到了一个重要的工程课程,任何合理的店铺在未来我去到的地方可能也会采用。事实证明,如果你设定这个作为一个明确的目标去工程化一个系统,实际上并不难做。Ben 将这个想法描述为“并非火箭科学”。我当时不知道这会有多难找!为了参考,让我在这里重新陈述这个原则:

软件工程的非火箭科学规则:
自动维护一个始终能通过所有测试的代码库

随着时间的推移,那个系统老化了,并且(据我所知)停止了服务。我对版本控制产生了兴趣,特别是那些强制执行这条不是火箭科学规则的系统。令人惊讶的是,只有一个系统似乎自动地做到了这一点(Aegis,由彼得 · 米勒编写,另一位迷人的澳大利亚人,可悲的是,现在正接近生命的尽头)。当时 Aegis 不是一个分布式系统,而当我在我自己的时间里使用 Aegis 时,我知道如果人们进入 分布式 版本控制领域,会有有趣的可能性,因为我看到我的朋友们在使用 bitkeeper。我想将这两个想法结合起来,所以我开始研究我自己的系统,叫做 monotone

Monotone 之所以被这样命名,是因为我真的想追求这个“单调增加的测试覆盖率”概念。修订分支包含基于可以由测试机器人轻松按乱序发布的证书等等。我觉得这是未来。当然,接下来发生了无数次冒险,最终产生了 mercurial 和 git,monotone 被搁置一旁,版本控制的世界发生了变化,诸如此类。万岁。

在这个过程中发生了一些奇怪的事情。“持续集成”成为了标准实践,最终进化为“持续部署”,但是_很少有网站似乎在自己的代码库中遵循不是火箭科学规则_。也就是说,我所见到的“持续集成”实践中,都是以错误的顺序进行的:在测试 之前 接受代码(留下一个潜在的破损树),或者在隔离中测试然后基于那次测试进行集成(没有保证集成后的组合能工作)。持续集成似乎到处都只是用来(迅速)学习树何时被破坏,而不是首先防止它破坏。我感到惊讶、恼火、悲哀。

所以几年后,当需要扩大 Rust 上我们几个人的贡献时,我决定我需要强制执行不是火箭科学规则来控制代码。我一再解释这个想法,但没有其他人对这个想法感兴趣,所以作为“技术负责人”,我最终亲自实施了它。结果是一个叫做 bors 的小脚本。

Bors 实现了针对构建机器人测试农场和 github 仓库组合的非火箭科学规则:它监控拉取请求,等待审阅者批准它们,然后对每个被批准的修订版本,创建一个 临时集成修订版本,该版本通过提议的更改扩展了你的集成分支。它测试那个临时修订版本,如果且仅如果测试通过,才会将你的集成分支指向该集成修订版本。如果测试失败,集成修订版本被丢弃,并在拉取请求中留下显示失败原因的评论。

你可以在 这里 查看其工作队列的 Rust 实例,以及在 这里 查看 Servo 实例。一个成功的集成示例在 这里,一个被拒绝的集成示例(至少在撰写时)在 这里。我再次重申,这项规则并非火箭科学。我之所以反复强调这一点,是因为它对我来说 太惊人了,工具支持似乎很少存在。我不得不自己写它!对于一个快速移动、敏感的项目来说,它的效果非常有益。主干从未被破坏。这确实意味着你的集成周期时间受到测试周期时间的限制,这意味着一些更改要尝试多次才能集成(bors 支持优先级标记,以帮助你手动调整集成顺序)。

在一些项目中,测试时间对于每个修订版本来说太长,至少在没有定义集成测试子集的情况下无法工作。这当然是每个人最初的主要担忧,而且这是合理的,但根据我的经验,这有点像人们首先反对测试(或类型检查),因为编写测试和类型会花费太长时间:如果你等待并稍后发现它们,你将花费更多时间与错误作斗争。我 强烈 建议任何从事软件工作的人尝试这种安排,看看它会带来什么样的区别。