在初创公司使用 Rust:一个警示故事

在某些方面,Rust 很棒。但是,在为需要快速行动的初创公司选择它之前请三思。

我在写这篇文章时犹豫不决,因为我不想开始或卷入一场关于编程语言的圣战。(只是为了摆脱火焰诱饵,Visual Basic 是有史以来最好的语言!)但是我有很多人问我关于 Rust 的经验以及他们是否应该为他们的项目选择 Rust。因此,我想分享一些我在创业环境中使用 Rust 的利弊,在这种环境中快速移动和扩展团队非常重要。

我想明确一点,我在某些方面是 Rust 的粉丝。这篇文章不是关于 Rust 作为一种语言或任何类似的语言有多糟糕。然而,我确实想谈的是,使用 Rust 几乎肯定会对生产力造成重大影响,如果你想快速行动,这可能是一个主要因素。仔细权衡速度影响是否值得您的公司和产品使用该语言带来的好处。

就在前面,我应该说Rust 非常擅长它的设计目的,如果你的项目需要 Rust 的特定好处(一种具有高性能、超强类型、不需要垃圾收集等的系统语言)那么 Rust 是一个不错的选择。但我认为 Rust 通常用于不太适合的情况,团队付出了 Rust 的复杂性和开销的代价,却没有获得太多好处。

我对 Rust 的主要体验来自于在之前的一家初创公司使用它工作了 2 年多一点。这个项目是一个基于云的 SaaS 产品,或多或少是一个传统的 CRUD 应用程序:它是一组微服务,在数据库前面提供 REST 和 gRPC API 端点,以及一些其他后台结束微服务(它们本身是结合 Rust 和 Python 实现的)。使用 Rust 主要是因为公司的几位创始人都是 Rust 专家。随着时间的推移,我们的团队规模显着扩大(工程人员数量增加了近 10 倍),代码库的规模和复杂性也显着增加。

随着团队和代码库的增长,我觉得随着时间的推移,我们为继续使用 Rust 付出了越来越重的代价。开发有时会很缓慢,推出新功能所花费的时间比我预期的要长,而且团队在早期决定使用 Rust 时感到生产力受到了真正的打击。从长远来看,用另一种语言重写代码会使开发更加灵活并加快交付时间,但要找到主要重写工作的时间会非常困难。所以我们有点被 Rust 困住了,除非我们决定硬着头皮重写大量代码。

Rust 应该是自切片面包以来最好的东西,那么为什么它对我们来说效果不佳呢?

Rust 有一个巨大的学习曲线。

在我的职业生涯中,我使用过数十种语言,除了少数例外,大多数现代过程语言(C++、Go、Python、Java 等)在基本概念方面都非常相似。每种语言都有其差异,但通常这是学习一些跨语言不同的关键模式的问题,然后可以很快产生生产力。然而,对于 Rust,人们需要学习全新的想法——比如生命周期、所有权和借用检查器。对于大多数使用其他通用语言工作的人来说,这些概念并不熟悉,而且即使对于经验丰富的程序员来说,学习曲线也相当陡峭。

当然,其中一些“新”想法出现在其他语言中——尤其是函数式语言——但 Rust 将它们带入了“主流”语言环境,因此对于许多 Rust 新手来说将是新的。

尽管是我共事过的一些最聪明、最有经验的开发人员,但团队中的许多人(包括我自己)都在努力理解在 Rust 中做某些事情的规范方法,如何理解编译器中经常出现的神秘错误消息,或者如何理解关键库的工作原理(更多内容见下文)。我们开始每周为团队举办“学习 Rust”会议,以帮助分享知识和专业知识。由于每个人都感到开发速度缓慢,这都极大地降低了团队的生产力和士气。

作为软件团队采用新语言的比较点,我在谷歌的一个团队是第一批完全从 C++ 转向 Go 的团队之一,整个过程只用了不到两周的时间。 15 多人的团队第一次用 Go 编写代码时相当轻松。对于 Rust,即使在每天使用该语言工作数月之后,团队中的大多数人也从未感到完全胜任。许多开发人员告诉我,他们经常感到尴尬,因为他们的功能落地所花的时间比他们预期的要长,而且他们花了这么长时间试图围绕 Rust 进行思考。

还有其他方法可以解决 Rust 试图解决的问题。

如上所述,我们正在构建的服务是一个相当简单的 CRUD 应用程序。在这个特定系统的整个生命周期中,此服务的预期负载将不超过每秒几个查询,最大值。该服务是一个相当复杂的数据处理管道的前端,可能需要数小时才能运行,因此该服务本身预计不会成为性能瓶颈。没有人特别担心像 Python 这样的传统语言会在提供良好性能方面遇到任何问题。除了任何面向 Web 的服务需要处理的之外,没有特殊的安全或并发需求。我们使用 Rust 的唯一原因是因为该系统的原始作者是 Rust 专家,而不是因为它特别适合构建这种服务。

Rust 做出了安全比开发人员生产力更重要的决定。在许多情况下这是正确的权衡——比如在 OS 内核中构建代码,或者对于内存受限的嵌入式系统——但我认为这并不是在所有情况下都是正确的权衡,尤其是在速度至关重要的初创公司中。我是一个实用主义者。我宁愿让我的团队花时间调试用 Python 或 Go 编写的代码偶尔出现的内存泄漏或类型错误,也不愿让团队中的每个人都因为使用旨在完全避免这些问题的语言而遭受 4 倍的生产力损失.

正如我上面提到的,我在谷歌的团队完全用 Go 构建了一项服务,随着时间的推移,该服务发展到支持超过 8 亿用户,并且在其高峰期是谷歌搜索 QPS 的 4 倍。在构建和运行此服务的这些年里,我一方面可以数出我们遇到由 Go 的类型系统或垃圾收集器引起的问题的次数。基本上,Rust 旨在避免的问题可以通过其他方式解决——通过良好的测试、良好的 linting、良好的代码审查和良好的监控。当然,并不是所有的软件项目都有这种奢侈,所以我可以想象,在其他情况下,Rust 可能是一个不错的选择。

你将很难招聘到 Rust 开发人员。

我在这家公司工作期间,我们雇佣了很多人,但在加入工程团队的 60 多人中,只有两三人以前有过 Rust 经验。这并不是因为不想找到 Rust 开发者——他们只是不在那里。(出于同样的原因,我们对雇用只想用 Rust 编写代码的人犹豫不决因为我认为在需要以敏捷方式做出语言和其他技术选择的创业环境中设置这种期望是不好的。)随着 Rust 变得更加主流,Rust 开发人才的数量会随着时间而改变,但是基于 Rust 的假设你将能够雇用已经知道 Rust 的人似乎有风险。

另一个次要因素是,使用 Rust 几乎肯定会导致团队中懂 Rust 的人和不懂 Rust 的人之间的分裂。因为我们为这项服务选择了一种“深奥”的编程语言,公司中本来可以帮助构建功能、调试生产问题等的其他工程师基本上无能为力,因为他们无法做出头脑或Rust 代码库的尾巴。当您试图快速行动并利用团队中每个人的综合优势时,工程团队中缺乏可替代性可能是一个真正的责任。根据我的经验,人们通常在 C++ 和 Python 等语言之间切换时没有什么困难,但 Rust 足够新,也足够复杂,它给人们一起工作带来了障碍。

库和文档不成熟。

这个问题(我希望!)会随着时间的推移得到解决,但与 Go 相比,Rust 的库和文档生态系统非常不成熟。现在,Go 的好处是它在向世界发布之前由 Google 的整个专门团队开发和支持,因此文档和库相当完善。相比之下,Rust 长期以来一直感觉像是一项正在进行的工作。许多流行库的文档都非常稀少,人们通常需要阅读给定库的源代码才能了解如何使用它。这是不好的。

团队中的 Rust 拥护者经常会说“async/await 仍然很新”和“是的,该库的文档很缺乏”之类的话,但这些缺点对团队的影响非常大。我们在早期采用 Actix 作为我们服务的 Web 框架时犯了一个巨大的错误,这个决定导致了巨大的痛苦和痛苦,因为我们遇到了深藏在库中的错误和问题,没有人能弄清楚如何修复。(公平地说,这是几年前的事了,也许现在情况有所改善。)

当然,这种不成熟并不是 Rust 特有的,但它确实相当于您的团队必须支付的税款。无论核心语言文档和教程多么出色,如果您不知道如何使用这些库,那也没关系(当然,除非您打算从头开始编写所有内容)。

Rust 使新功能的粗加工变得非常困难。

我不知道其他人如何,但至少对我来说,当我构建一个新功能时,我通常不会预先准备好所有的数据类型、API 和其他细节。我经常只是放屁代码,试图让一些基本想法发挥作用,并检查我对事情应该如何工作的假设是否或多或少是正确的。在 Python 中执行此操作非常容易,因为您可以快速、随意地玩打字之类的东西,而不用担心在您粗略构思时某些代码路径被破坏。您可以稍后返回并整理所有内容并修复所有类型错误并编写所有测试。

在 Rust 中,这种“草稿编码”非常困难,因为编译器可以并且将会抱怨每一个没有通过类型和生命周期检查的该死的东西——因为它是明确设计的。当您需要构建最终的、生产就绪的实现时,这非常有意义,但当您试图将某些东西放在一起以测试想法或获得基础时,这绝对很糟糕。该unimplemented!宏在一定程度上是有帮助的,但仍然需要在编译之前对堆栈上下的所有内容进行类型检查。

真正麻烦的是,当您需要更改承载接口的类型签名时,发现自己花费数小时更改每个使用该类型的地方,只是为了看看您最初的尝试是否可行。然后当你意识到你需要再次改变它时重做所有这些工作。

Rust 擅长什么?

肯定有一些我喜欢 Rust 的东西,以及我希望在其他语言中拥有的 Rust 特性。match语法很棒。, Option,ResultErrortraits 非常强大,?运算符是处理错误的一种优雅方式。许多这些想法在其他语言中都有对应物,但 Rust 对它们的处理方式特别优雅。

对于需要高水平性能和安全性的项目,我绝对会使用 Rust,对于这些项目,我并不十分担心需要与快速发展的整个团队一起快速改进代码的主要部分。对于个人项目,或非常小的(比如 2-3 人)团队,Rust 可能会很好。Rust 是内核模块、固件、游戏引擎等事物的绝佳选择,在这些事物中,性能和安全性至关重要,而且在发布前可能很难进行真正彻底的测试的情况下。

好吧,既然我已经激怒了 Hacker News 一半的读者,我想现在是时候宣布我下一篇文章的主题了:为什么nano是高级文本编辑器。下次见!

在初创公司使用 Rust:一个警示故事
标签: