初创公司环境下 Rust 的使用心得:速度与收益的权衡

2024-07-14
来源:网络整理

坦白说,在写这篇文章之前,我(作者)犹豫了很久,因为我害怕这篇文章最终会成为所有编程语言力量批判的导火索。但确实有很多朋友问我 Rust 是如何工作的,在自己的项目中是否应该选择 Rust。经过深思熟虑,我最终决定分享一些在创业环境中使用 Rust 的经验,并谈谈这门语言与快速行动和扩大团队两个核心目标之间的冲突。

我其实很喜欢 Rust,也无意诋毁它。但我的个人经验告诉我,选择 Rust 几乎肯定会对生产力产生重大影响,影响快速行动的基本目标。所以在开始之前,请仔细权衡 Rust 对速度的影响是否值得它为你的业务和产品带来的好处。

Rust 是一门优点和缺点都很明显的语言。如果你的项目需要 Rust 的一些特性,比如高性能、强类型、没有垃圾回收的系统语言,那么它做得很好。但 Rust 在这方面也相当糟糕,即团队为 Rust 的复杂性和编写开销付出了代价,却得不到任何好处。

我对 Rust 的主要经验来自我之前在一家初创公司的工作经历,工作时间长达两年多。这是一个基于云的 SaaS 项目,是一个传统的基于 CRUD 的应用程序:一组在数据库前面提供 REST 和 gRPC API 端点的微服务,加上一些后端微服务(它们本身是用 Rust 和混合实现的)。

我们开始使用 Rust 是因为我们的几位创始人都是 Rust 专家,但随着时间的推移,我们的团队已经显著壮大(工程人员增长了近 10 倍),并且我们的代码库的规模和复杂性也迅速增长。

随着团队和代码库的不断壮大,我意识到公司继续使用 Rust 的代价越来越大。有时开发速度很慢,新功能的发布时间比我预期的要长,而且人们觉得选择 Rust 不利于提高生产力。

从长远来看,用另一种语言重写代码会让开发更加灵活,加快交付速度,但问题是我们很难抽出全职的时间来推动这次重写。总之,我们感觉有点被 Rust 困住了,任何解决方案都不是那么容易实现的,所以我们需要硬着头皮强行实现。

这些情况似乎和很多朋友的固有印象不一样,那么既然Rust语言如此安全、稳定,性能又如此优秀,为什么它不适合我们呢?

学习难度高

在我的职业生涯中,我接触过几十种语言,其中大部分都是现代过程式语言(例如 C++、Go 和 Java 等),其基本概念高度相似。虽然每种语言之间都有差异,但主要体现在跨语言模式的差异上,掌握起来并不太难。

但对于 Rust,我发现最困难的其实是接受一整套全新的思想——比如生命周期、所有权、借用检查器等。即​​使是经验丰富的程序员也不熟悉这些定义,因此他们将不可避免地面临陡峭的学习曲线。

当然,这些“新”的理念在其他语言中也有所体现,尤其是函数式语言。但 Rust 是第一次被完全引入“主流”语言环境,这自然让很多 Rust 新手苦不堪言。虽然我的同事们都很聪明,经验丰富,但包括我自己在内的很多人,都很难理解 Rust 中的一些实现规范,为什么编译器中经常会出现神秘的错误信息,以及关键库是如何工作的。

为此,我们开始每周举行一次“Rust 学习会议”,让团队分享知识和专业知识。然而,开发速度却变慢了,这大大降低了团队的生产力和士气。

与此形成鲜明对比的是,我在 工作时,从 C++ 转到了 Go。整个过程用了不到两周的时间,15 人的团队在第一次写 Go 程序时感觉相当轻松。但在 Rust 中,即使经过几个月的全职开发,团队中的大多数成员仍然感到非常不自信。许多开发人员告诉我,他们感觉非常不舒服,因为实现功能所花的时间比他们预期的要长,而这一切都源于被迫用 Rust 思考。

Rust 并不特殊,总会有替代语言

如上所述,我们构建的服务是一个相对简单的 CRUD 应用程序。在此系统的整个生命周期中,服务的预期负载不会超过每秒几个查询,但服务后面是相当复杂的数据处理管道,可能需要几个小时才能运行,因此服务应该不会成为性能瓶颈。换句话说,即使是这种不以性能著称的语言,在这样的场景下也绝对不会造成任何麻烦。

另外,除了针对Web的业务需求处理之外,该服务并没有什么特殊的安全性或者并发性要求,我们使用Rust的唯一原因是这个系统的发起人是一位Rust专家,和语言本身的特性和适应性无关。

Rust 有一个众所周知的设计权衡:安全性比开发人员的生产力更重要。在许多情况下,这个决定是可以的:无论是在操作系统内核中构建代码还是限制嵌入式系统的内存,这都是必要的。但除此之外,有些要求不需要过多关注安全性,特别是对于像我们这样的初创公司来说,速度决定成败。

我是一个典型的实用主义者,我宁愿团队花时间调试 Go 代码中偶尔出现的内存泄漏或类型错误,也不愿让每个人都被迫将生产力降低四分之三以完全避免这些问题。

上面提到,我曾在 团队用 Go 构建过一个服务。随着时间的推移,该服务已经支持了超过 8 亿用户,峰值流量是 搜索 QPS 的 4 倍。在构建和运行该服务的这些年里,由 Go 类型系统或垃圾收集器引起的问题其实屈指可数。

基本上,Rust 解决的问题也可以通过其他方式解决 —— 比如更好的测试、越来越好的代码审查和监控等等。除非你实在没有这些资源,否则 Rust 或许是个不错的选择。

招募 Rust 开发人员很困难

我在这家公司工作期间,招了不少人。但在 60 多人的工程团队中,只有两三个人有 Rust 开发经验。我们不是不想找有经验的 Rust 程序员,而是根本找不到。

所以大家在做决定之前一定要谨慎,纯粹的 Rust 开发确实不符合创业环境的基本需求。是的,随着 Rust 越来越主流,相应的开发人才肯定会越来越多,但至少目前来看,这并不容易。

另一个次要因素是,团队中懂 Rust 和不懂 Rust 的人之间存在分裂。由于它是一门比较“深奥”的编程语言,公司里其他本来可以帮助构建功能、调试生产问题的工程师完全无法参与其中。这时候,如果你想快速行动,充分发挥团队每个成员的综合优势,Rust 就成了你面前最大的障碍。

以我的经验,程序员可以轻松地在 C++ 和 等语言之间切换,但 Rust 太新、太复杂,这提高了人与人之间协作的门槛。

图书馆和文档还不成熟

我希望这个问题能够逐渐得到解决,但我不得不承认,与 Go 相比,Rust 的库和文档生态系统非常不成熟。

Go 的优点在于,它的所有已发布的成果都是由 专门的团队开发和支持的,因此配套的文档和库也相当齐全。相比之下,Rust 总感觉像是一个“半成品”,库和文档严重不足,人们经常需要看库的源代码才能明白怎么用。这不好,非常糟糕。

Rust 的支持者确实承认“Rust 还不够成熟”、“库文档确实不完善”,但仅仅承认是没有用的,这些问题反而影响了团队的开发效率。

我们早期在 Web 即服务框架上犯了一个大错误,后来导致了很多麻烦。这个库充​​满了错误和问题,至今仍不清楚如何修复。(当然,这已经是几年前的事了,所以也许从那时起情况有所改善。)

当然这些问题并不是 Rust 独有的,但它们已经成为开发团队无法避免的“技术税”。无论核心文档和教程有多好,如果你不知道如何使用那些库,一切都将毫无意义。

在 Rust 中粗略地构建一个新功能很困难

我不知道其他人怎么想,但就我个人而言,在开发新功能之前,我不会规划数据类型、API 和所有其他细节。我通常会先编写代码,然后尝试看看基本思路是否可行。

在 中做到这一点非常容易,我们可以快速尝试,自由探索,而不必担心粗糙的想法会影响某些代码路径。在我们确定它可以工作之后,我们可以回过头来清理它,修复类型错误,并毫不拖延地编写测试。

但在 Rust 中,这种“粗糙编码”的方式非常困难,因为编译器可能会认为每个不符合类型和生命周期检查的问题都是错误。这就是 Rust 的特点——设计必须清晰。

如果我们需要构建一个可用于生产的产品,那么这很好,但如果你只是想做一些测试或初步探索,那就太糟糕了。这有点帮助,但你仍然需要在编译之前对堆栈上下的所有内容进行类型检查。

更烦人的是,当我们需要改变承载接口的类型签名时,我们会发现自己花了几个小时改变使用该类型的每个地方,以查看我们最初的尝试是否有效,如果我们需要做进一步的调整,我们就必须重新开始整个过程​​。

结论

Rust 确实有一些我喜欢的地方,它的一些特性我希望其他语言也能采用。匹配语法是第一位的,但也有强大的 、 、 和 特性,以及优雅地处理错误的“?”运算符。这些设计在其他语言中很相似,但 Rust 从上到下都散发着优雅的气息。

对于需要高性能和高安全性的项目,我绝对愿意使用 Rust。毕竟在这样的项目中,我不应该频繁修改项目的主要部分,对速度也没有太高的要求。但在小团队中,不适合全面使用 Rust——它适合开发内核模块、固件、游戏引擎等。毕竟它们都强调性能和安全性,而且在发布之前往往很难进行彻底的测试。但除此之外,请谨慎使用 Rust,这门语言可不是好惹的!

原文链接:

分享