QR code

Four Builds: A Balance Between Quality and Joy

  • Translated by to

代码安全需要多长时间才能知道?Martin Fowler曾经说过:10分钟。十年后,五百名开发人员表示同意。我不同意他们的看法。首先,十分钟对于一个小型软件系统来说是不够的。其次,对于我们在每次编辑一行代码后从IDE运行的构建来说,十分钟就太长了。我们需要对构建进行更细致的分类:从超快到彻底和死慢。

一个构建应该需要多长时间呢?

应该需要多长时间,以便运行所有必要的测试。错了。想象一下一个需要一个小时的构建。开发速度将接近于零。程序员会抱怨很多。

那么一个只需要几秒钟的构建呢?编码速度会很快—但不会持续太久。代码的质量会受到威胁,因为快速构建意味着测试不充分,充满了模拟。

那么,一个构建应该需要多长时间呢?正确答案是:在几秒钟到几个小时之间。但构建必须是不同的。

第一个构建是我们在笔记本电脑上运行的构建。它。它只包括单元测试。每一个测试只需要几毫秒。即使我们有很多测试,所有测试加在一起也只需要几秒钟。我们还会检查测试覆盖率的阈值。

如果本地构建需要的时间超过几秒钟,它就开始变成一种义务而不是帮助。我们不会运行这样的构建是因为我们享受它提供的信心。相反,我们运行它是因为这是“正确的做法”。这样的构建并不令人愉快,只是一个令人烦恼的例行公事。漫长的构建会打破充满活力的编码节奏。

那编译呢?这十秒钟包括编译源代码的时间。如果项目有数百个需要几分钟才能编译完成的大型C++文件,怎么办?我们会将这样的项目分解为更小的组件——每个组件都有自己的构建和自己的代码库。我们不容忍大型代码库和单体代码库。

最后,在运行了几十次快速构建之后,我们有足够的信心提交拉取请求。一旦提交,GitHub会接收并启动我们的工作流程。

我们有许多不同的YAML文件。除了单元测试,它们还运行集成测试和各种样式检查。我们明白失败的可能性很高,因为单元测试——在快速构建中运行的测试——只是所有测试中的一小部分。

我们等待几分钟,看到一些工作流失败。我们调查失败,向单元测试提出一个问题:“你为什么没发现这个问题?”找到答案后,我们修复测试或创建额外的测试。然后,我们再次推送,并等待几分钟。我们看到一个新的失败,重复这个过程,通常每个分支会发生几次。最终,我们看到GitHub的所有工作流都是绿色的。

我们为这个过程付费。首先,GitHub按分钟收费。其次,项目在我们无所事事等待GitHub Actions的答复时支付我们报酬。这就是为什么我们希望构建时间不超过十分钟——它必须要便宜

当所有GitHub工作流都是绿色的时候,我们点击按钮,要求Rultor或GitHub的Merge Queue来合并它。一个预检构建开始并需要长达一个小时,在一个按需的AWS EC2实例上。它需要这么长的时间是因为除了单元测试和集成测试之外,它还运行例如变异测试。即使在一个小的代码库中,十分钟可能不够。

预检构建也可能运行负载、压力、性能、浏览器内和安全渗透测试。我们不希望它们在一个绿色的便宜构建后就崩溃。但他们确实会偶尔崩溃。如果它们崩溃了,我们会回到快速构建,责怪疏忽的安全网。我们用一个新的单元测试重现失败,并进行另一次合并尝试,希望这次预检通过。最终,它确实通过了,代码进入master分支。

偶尔,我们会发布产品的新版本——不管是库还是微服务。这时候,质量是首要考虑的,而构建的持续时间并不重要。我们按下按钮然后等待,需要多久就等多久。有时候会持续几个小时。

与以往所有构建不同,这次构建是正式的。除了上述提到的所有测试外,例如在云端进行多浏览器测试,自动A/B测试,以及各种回归测试。未来,绝对会运行基于LLM的测试以检测设计不一致和安全漏洞。

为什么我们没有在预检构建期间运行这些测试?为了避免合并队列溢出。一个高效的程序员可能每天提交多达五个拉取请求。团队中有十名活跃贡献者,我们可能每天会得到几十个合并请求。由于合并队列无法并行化,即使预检构建花费一个小时也可能太长。一个正式的构建绝对不会适用。

此外,与生产环境的集成是耗时的。我们要进行数据库更改、应用数据迁移、更新AWS配置,并在“绿色”和“蓝色”环境之间切换。

在较小的项目中,廉价和预先构建的可能相似。在微型项目中,所有三种构建——廉价、预检和正式——可能是相同的。然而,我们始终将快速构建与其他构建区分开来。”四种构建”框架可能会被简化为”两种构建”,但永远不会简化为”一种构建适用于所有情况”。

Translated by ChatGPT gpt-3.5-turbo/42 on 2025-04-13 at 04:40

sixnines availability badge   GitHub stars