在本文中,开发环境是指可以在部署之前测试代码更改的沙箱,不是 Eclipse 或 Microsoft Visual Studio 这样的集成开发环境(IDE)。
本文最初发布于 Slack 官方博客,由 InfoQ 中文站翻译并分享。
对我来说,开发环境一直是个谜。尽管我在 Slack 的第一天就了解了它们,并在过去三年几乎每天都在使用它们,但我从未真正地理解它们。
半年前,我定了一个目标,要全面了解开发环境。我与 Slack 一些最资深的工程师进行了交流,研究了无数文档,筛选了多年的 Slack 对话。从中,我发现了一个关于 Slack 开发环境随时间演进的有趣旅程。
为什么需要开发环境?
开发环境是我们可以自由修改的应用程序副本。它们的主要价值是让我们可以在不影响实际用户或不泄露真实数据的情况下测试应用程序更改。
开发环境使我们能够快速迭代,因为在上面测试更改非常快也非常简单。通过它,我们可以很容易地与他人共享更改以供审核。
总之,开发环境极大提高了开发速度和安全性。
后台是什么样子?
Slack 的开发环境是我们的应用程序在远程服务器(准确地说是 Amazon EC2 实例)上的副本。这些实例运行 Slack 应用程序及其所依赖的许多服务。
每个开发环境都有自己的 Slack 子域,我们可以在浏览器中查看我们的更改。开发环境中的任何更改都不会影响实际用户,因为它们自己有一套与生产环境隔离的基础设施(例如数据库)。
远程开发 vs. 本地开发
在 Slack,我们是远程开发,这意味着我们的开发环境在服务器上。另一个选项是在我们的个人电脑上进行本地开发。对于小型项目来说,本地开发非常好,因为它速度快,而且不需要联网。然而,对于较大的项目,远程开发环境则有显著的优势。
首先,我们不必在本地设置 Slack 应用程序。Slack 的架构非常复杂,它依赖于许多不同的服务,不用在本地设置是非常有价值的。
其次,如果一项更改在开发环境中有效,那么它在生产环境中也很可能有效,因为我们将开发环境配置为生产环境的镜像。对于使用时间特别长的开发环境,可能仍然会出现某种程度的偏差,但是,出现这种偏差的可能性以及偏差的幅度,都要比在本地使用单独的机器进行开发时小得多,本地开发经常会导致配置不一致。
第三,远程开发环境不依赖于可能会崩溃或落后的个人计算机。云硬件更便宜、更有弹性,而且可伸缩。此外,它们使我们很容易在多台机器上进行开发,并与队友共享工作以供审核。
随着互联网变得越来越快、越来越可靠,远程开发越来越有意义。
如何使用开发环境?
我们最好通过一个例子来看下 Slack 的开发环境工作流。假设出于某种原因,我们想测试一个使用了紫色 Comic Sans 字体、全大写的 Slack 主页版本。
我们首先创建一个特性分支,然后使用一个名为 slack sync-dev 的命令行工具将其追加到开发环境中。它会随机预定一个开发环境,然后将本地更改同步到上面。这样,我们本地编辑的任何内容在保存时都会自动传输到开发环境。
slack sync-dev只是对两个著名的实用工具fswatch(检测更改)和 rsync(传输更改)的封装。
如果做了任何前端更改,我们就必须使用 webpack(我们用作构建系统的一个开源工具)在本地构建它们。命令 slack run buildy:watch 构建我们的前端资产,并通过本地主机将它们提供给我们的开发环境。
完成后,我们可以导航到 dev575 子域。
现在,我们可以在页面上找 Bug,调整更改,并与他人共享以供审核。
前端更改是由个人计算机构建并提供。如果想让其他人在我们关机后还能够看到这些更改,我们就必须生成一个静态构建,在开发环境中构建前端资产,而不是在本机。
为什么在本机构建前端?
2017 年,当首次引入 webpack 时,我们是在开发环境中远程构建前端更改。当有人更改了前端并同步后,开发环境就会自动重新构建前端资产。
然而,随着代码库的增长,webpack 变得越来越消耗资源。构建会消耗整个实例的内存。当时,多个开发人员在同一个实例上工作,他们经常被打断。因此,我们将 webpack 转移到了本地机器上。
现在,每个实例只有一个开发环境,而有了更高级的实例,就完全有可能将 webpack 移回我们的开发环境,开发人员将获得更流畅的体验。但目前,系统运行速度很快,而且可扩展,所以我们觉得没必要去修复没坏的东西。
改进命令行工具
我们讨论一下命令行工具。上文已经介绍了一些,比如 slack sync-dev。Slack 离不开这些工具,因为它们让开发更快、更简单。
早期,在还没有 slack sync-dev 的时候,我们不得不手动地将我们的更改复制到开发环境中,这很耗时,而且容易出错。现在,我们有 60 多个命令行工具,这简化了许多这样的日常任务。
其他的例子包括 slack bo-me(它在当前开发环境中创建一个 bot 用户)以及 slack tail-dev(它跟踪当前开发环境中的远程日志)。如果你想进一步了解我们的开发工具,请查看我们 2016 年发表的博文。
扩展我们的开发环境
2014 年的时候,我们只有一个开发环境供所有人使用。如果有人破坏了这个环境,其他人就无法测试他们的更改了。这在当时并不是什么大问题,但随着 Slack 的发展,我们不得不增加开发环境。到 2019 年底,我们已经维护了 550 个开发环境,足够每个 Slack 工程师都连接到一个不同的开发环境。
不过,这一增长趋势并没有持续下去,事实上,2020 年就完全逆转了。在讨论原因之前,让我们先看看另一个随时间变化的有趣指标:每个 EC2 实例上开发环境的数量。
随着时间的推移,数值在下降,因为我们想将开发环境彼此隔离开来。当多个环境共享同一个实例时,如果有一个开发人员在其中一个环境上运行一个内存密集型进程,就会降低其他所有环境的运行速度。
这是一个折衷——每个实例上的开发环境数少了,就意味着我们需要购买更多的 EC2 实例。此外,这些实例是静态托管的,因此,我们需要花大量的工程时间来提供新的实例以及删除损坏的实例。更糟糕的是,长期运行的实例会随着时间的推移而变得混乱,而其行为将不再可靠。
为了解决这些问题,我们创建了一个按需提供开发实例的新系统,逆转了第一个图表中所显示的增长趋势。我们按需提供新实例,而不是保持数百个实例同时运行。一旦开发人员完成了测试,他们使用的实例将被自动删除。有了这个系统,我们就可以更有效地使用开发环境。我们将在下一篇文章中深入讨论这些扩展方面的演进,请继续关注!
作者介绍:
Michael 是 Slack 平台团队的一名软件工程师。他已在 Slack 工作了将近 3 年。期间,他参与了各种各样的项目,包括面向用户的功能、API 基础设施和扩展实验。