编译|傅宇琪、Tina 在 AI 写码逐渐成为“新常态”的当下,编程语言的选择反而更重要。 Flask 作者、创业者 Armin Ronacher 指...
2025-10-18 1
编译|傅宇琪、Tina
在 AI 写码逐渐成为“新常态”的当下,编程语言的选择反而更重要。 Flask 作者、创业者 Armin Ronacher 指出:语言背后是复杂的权衡,在 AI 时代必须被重新审视;更关键的是,语言会直接影响 Agent 生成代码的质量。
Armin 认为,Go 在 AI 场景下更“对味”,它抽象层薄、结构规整,便于模型读懂与改写。同一类小程序,他让 AI 分别用多种语言各写十次再比通过率,Go 明显优于 Python,也好于 Rust。与此同时,他也强调一个现实:无论你创办什么公司,最终都绕不开 Python。也许不会用它写核心服务,但只要涉及机器学习或数据处理,Python 一定会出现。同理,JavaScript 也无法回避;既有 JavaScript,通常就会有 TypeScript。
更长远地看,“为人类与 Agent 共编而设计的下一代语言”正成为行业趋势。Armin 认为,现在正是创造“更完美语言”的窗口期:我们短期内不会摆脱 AI 生成代码的范式,而现有语言也未必是人机协作的最优解。那么,如今的创业公司在 Python / Go / Rust / TypeScript 之间如何选择?我们翻译了本期播客,汇总 Armin 的一线观点与实战经验,供大家参考。
以下是一些亮点:
一家完全依赖机器的公司,也会失去团队的活力。Claude 不是人,它不会有情绪或激情。一个优秀的团队,靠的是人之间的能量与协作,这一点永远不会被 AI 替代。
我非常尊重编程语言,因为它们背后蕴含着复杂的权衡。而在 AI 时代,我们可能需要重新审视这些权衡方式。
编程初学者常常天真地以为“语言就该这样设计才对”,但随着经验积累,你才会理解各种权衡背后的复杂性。
统一代码库没那么神圣:OpenAPI 等高质量代码生成让前后端“同语种”的价值下降;清晰的边界(尤其 RSC 场景)反而是优点。
当前确实是一个适合创造“更完美语言”的时刻,因为我们很可能不会马上摆脱 AI 生成代码的模式,而现有语言也未必是最佳选择。
反对“旗帜化的 996”,我在行业中见过太多惨痛的例子,包括一些社区成员因为长期过劳而出现精神问题,比如精神错乱或精神分裂。这些并非个案,而是长期高压与不健康生活方式的必然结果。工作固然重要,但没有什么值得你为此失去完整的人生。
1 Python、Go、Rust、TypeScript 如何各擅其长
Gergely:我们先聊聊编程语言。你曾在 Python 领域深耕了很多很多年——超过十年。你还记得当年 Python 2 向 3 迁移的那场“风波吗”?当时究竟发生了什么?
Armin:很巧的是,今年出了部《Python 纪录片》,我受邀参与拍摄,其中有一段专门讲到 Python 2 到 3 的迁移,这让我重新回顾了整个过程。
回过头看,我认为这样的迁移如今已不太可能再发生。当年虽然 Python 没被这次迁移“整死”,但确实只差一点。若不是社区投入巨大努力去推动迁移,这次变革可能会给语言带来灾难性的后果。
要理解这次迁移,就要知道 Python 的历史。最初它的字符串类型和 C 类似,只支持基础字符串。后来才引入了 Unicode 字符串,用 u 前缀表示。而 Python 3 的主要目标,就是统一并严格化字符串处理,将一切迁移到 Unicode。但问题在于,现实世界中的编码远比设计者想象的复杂。Python 3 的字符串改动在理论上是合理的,实践中却异常棘手。
迁移的复杂性不仅体现在语言内部,也波及了操作系统和生态。比如当时很多 Linux 系统仍未全面采用 UTF-8 编码,这导致文件系统中出现各种奇怪的情况。最终,Python 和操作系统生态的演进相互促进,Unicode 的支持才逐渐完善。
但在那之前,仍有数以百万计的 Python 2 代码无法直接运行在 Python 3 上。最初的设想是“一次性迁移”,可现实中根本做不到。我们不得不同时维护支持 Python 2 和 3 的库,持续多年。我记得当时在佛罗伦萨的 Python 语言峰会上,我提议重新引入字符串 u 前缀,这样开发者就能编写兼容两个版本的代码。但当时遭到强烈反对,许多人认为应当直接迁移到 Python 3,不必再兼容旧版本。然而事实证明,这种理想主义行不通。最终,Python 3 的迁移能够成功,靠的是社区多年持续的努力和务实的态度——接受两代共存,逐步过渡,整个过程花了十年以上。
这场迁移也为后来者提供了宝贵的教训。像 Rust 在设计之初就明确引用了 Python 3 的教训,提出“版本增量系统”(edition system)的概念,使得新特性可以选择性启用,不必彻底割裂旧版本。这样,一个项目中可以同时存在不同语言版本的代码,这显然是从 Python 迁移中吸取的经验。
Gergely:你提到 Python 曾经是你最喜欢的语言。后来,你为了性能等原因,在 Sentry 引入了 Rust,现在你也在尝试使用 Go。你会如何比较这些语言?当你考虑一种语言时,你会怎么判断它适合做什么,不适合做什么?
Armin:我写过一些关于我在编程中的“两种人格”的博客。一方面,我喜欢打造精致的开源软件,希望能被成千上万人使用,我会投入大量心血去雕琢代码的每个细节——这有点像制表匠制作瑞士手表,每一处都要精密考究。在这种情境下,我非常在意语言的特性、API 的优雅程度以及整体设计。但当你在构建一家公司、打造一款产品时,这一切都不再重要。那种“写一次、运行无数次”的理想状态,在商业环境中并不存在。
Rust 之所以令人惊叹,是因为它非常适合打造精巧的开源项目,但这同样使它成为创业公司中不够理想的语言。它过于严格、过于精确,在开发效率上存在更多摩擦。当然,相比 C++,Rust 已经是一次巨大的进步,尤其是在处理二进制文件时安全得多。然而,如果要快速迭代产品,Rust 的成本太高了。
Gergely:能举一些这种“摩擦”的例子吗?为什么你认为 Rust 不适合初创公司?
Armin:最明显的一点是,Rust 编译极慢,这是巨大的阻力。其次,与 Python 相比,你需要写更多的代码,还要花大量时间思考类型。我喜欢类型系统,但有些事情实在难以通过类型表达,而这些问题在 Python 中根本不用考虑。
值得注意的是,动态语言与静态语言之间的界限正在模糊。比如 C 语言引入了 dynamic 关键字,让静态语言也能在运行时进行动态类型绑定;TypeScript 则将这一思路扩展到 JavaScript,使得两种世界在某种程度上融合。而 Rust 则完全是静态类型语言,如果你的问题本质上需要动态类型支持,就得自己手动实现各种动态包装,这很麻烦。
另一个典型的摩擦点是借用检查器(borrow checker)。虽然它能保证内存安全,但也让某些设计无法实现。比如在 C++ 中,你可以创建自引用结构体,而在 Rust 中编译器会直接拒绝。你明知道逻辑没错,却被迫重构,最后可能把自己逼进死角。Rust 对某些问题的约束太强,它擅长的领域非常“Rust 形”,但很多问题并非如此。
正因如此,我现在在新公司主要使用 Go。Go 是一种极其实用的语言,如果你追求的是务实、高效,它非常合适。它稳定、简单,即便哪天 Google 不再维护,也会有一群人继续维护它。甚至现代的 Java 也非常不错,比如虚拟线程(virtual threads)让并发变得更轻松,不必总处理 Promise。这些语言可能不“性感”,但足够可靠。
对我来说,选择语言的标准已经更为务实。对公司而言,重点不在代码本身,而在你构建的产品。
Gergely:你现在正在创办一家初创公司?团队规模有多大?
Armin:现在团队除了我和一位联合创始人两人,还有一群 Claude 和 Codex——一支“AI 实习生大军”在写代码,这也彻底改变了我的工作方式。
Gergely:一门好的编程语言要具备什么特质?为什么你认为灵活但速度较慢的 Python 是好的?为什么 Go 似乎成了你心目中 Python 和 Rust 的折中方案?
Armin:现在,无论你创办什么公司,最终都会用到 Python,这是无法避免的。你未必会用它来写核心服务,但只要涉及机器学习或数据处理,Python 就一定会出现。同样,你也不可能绕过 JavaScript。有了它,就会有 TypeScript。问题在于,你的整个代码库中,这些语言所占的比例是多少。
我个人并不想用 Python 或 JavaScript 来写后端服务,这并非出于性能考虑,而是因为生态定位不同。比如我现在的公司大量处理邮件解析,这类任务 Python 处理得不错,但若要在大规模场景下运行,我认为并不理想。结合我在 Sentry 使用 Rust 的经验,我可以想象在规模扩大后 Rust 会重新派上用场,但在当前阶段,它并不是最佳选择。
Gergely:当公司需要处理海量数据、运行众多进程时,我们是否就需要关注编程语言的性能问题?
Armin:我认为“规模化”并不仅仅取决于数据量,而是包括团队规模、问题复杂度以及系统架构的复杂性。在这些条件下,企业往往需要在不同语言间做取舍。引入新语言的原因可能是性能考虑,也可能是为了融入某个生态系统。以 Sentry 为例,我们之所以引入 Rust,不只是因为我个人喜欢它,而是因为当时遇到了性能瓶颈。
我们本可以用 Go 来写新的服务,但那意味着要维护一个独立服务,这不够高效。Rust 之所以成为选择,是因为它能嵌入 Python,从而在不分拆系统的情况下提升性能。后来我们做本地符号处理时,备选方案是 C++,但在早期尝试后发现,C++ 程序崩溃频繁,维护困难;而当时 Go 的生态还不完善,如果从零构建一切成本太高。Rust 的生态正好在发展中,尤其在 debug 方面有 Mozilla 等公司也在推动,这让它成为更务实的选择。
当然,我们后来也在一些并非最合适的场景使用了 Rust,例如数据接入系统。如果现在让我重来,可能不会再那样做。但当时团队规模有限,只能复用已有资源,这是一种现实权衡。我相信,未来我的公司也可能再次因为环境或生态的变化,引入原本计划不用的语言。这并不一定是出于性能需求,可能只是出于生态稳定性或兼容性的考虑。
Gergely:你如何看待当下 Python、Rust 和 Go 的生态?
Armin:Python 的生态极其成熟,尤其在基础设施和自动化领域。我目前主要用 Python 来配置和管理云资源。它在机器学习领域仍无可替代,我的数据管道也是用 Python 写的,它依旧非常适合构建 Web 服务。至于是否用它写核心业务逻辑,要看具体情况。比如一个以 AI 推理为主的公司,大部分时间其实在等待网络返回结果,这种场景下用 Python 反而非常合适,开发效率高。但如果服务要求高并发、高吞吐,Go 可能更合适。Go 的语法比 Python 更简单直接,也更易于维护;而 Python 随着生态的膨胀,复杂度反而上升了。
Rust 则适用于处理二进制数据、构建数据库或负载均衡器等需要高性能和精确内存管理的系统。对于不能容忍垃圾回收延迟、要求性能可预测的场景,Rust 是极佳选择。尤其在需要并发处理、内存安全、或被嵌入到高安全环境(如浏览器)的模块中,它的优势明显。Rust 也非常适合为 Python 编写扩展模块,它在性能优化或生态整合方面都优于其他方案。
Go 的定位则相对单一,最适合用于构建 Web 服务或命令行工具。至于 WebAssembly,虽然没有如预期般流行,但它的应用需求已根深蒂固,而 Rust 能很好地满足这一点。相比之下,用 Go 运行在浏览器中仍存在性能和垃圾回收等限制。
在浏览器端,JavaScript 是无法绕开的。而在服务端,我对此其实态度复杂。总体来说,TypeScript 已经让这个生态相当成熟了。如果未来有人推出“JavaScript 2”,像 Python 3 那样清理历史包袱,或许会更好,但我并不建议重演那种迁移灾难。我目前不选择用 TypeScript 构建后端,主要原因是 npm 生态。依赖太多,让人几乎无法掌控项目。我倾向于保持依赖最小化,但在 JavaScript 世界,要构建一个正常项目几乎不可能少于 500 个依赖包。浏览器端我能接受,因为没有替代方案,但在服务端这让我难以安心。
此外,“统一代码库”的理念在实践中也并不理想。前后端的职责、运行环境、性能约束差异太大,强行统一反而让边界模糊。更好的做法是通过 OpenAPI 或代码生成工具来桥接两端——这种方式更清晰、也更可靠。
选择语言时要从问题出发,而不是从偏好出发。初创公司应该在早期尽量控制技术栈的数量,三到四种语言已经足够。
Gergely:过去 TypeScript 的最大卖点之一就是“统一代码库”,React 前端与 Node 后端共享语言,团队成员能跨端协作。但现在随着 AI 工具的出现,这种优势似乎正在改变。
Armin:没错。我最近在一次技术交流会上提到,如今“地板在抬高,天花板却没变”。意思是,大家对软件质量的期望越来越高,而支撑这种期望的工具也更强大。以代码生成为例,现在的成熟度远超两三年前。比如 Stainless 这样的公司,已经能自动生成所有主流 AI 云服务的 SDK。这在过去要花巨大人力维护,如今几乎全自动完成。
当代码生成如此高效时,统一代码库的价值就不再那么关键。事实上,保留清晰的系统边界反而更有利于开发,尤其是在使用 React Server Components 这类技术时,明确“哪些代码运行在服务器、哪些在客户端”变得尤为重要。
2 AI 时代,语言选择更重要
Gergely:说到 AI 辅助编程,你现在的创业公司就大量使用这些“AI 实习生”——Claude、Codex 等等。能谈谈你们是如何用它们的吗?以及你们目前在做什么?
Armin:我们选择了“电子邮件”作为核心领域,因为它是天然的自然语言载体。如今自然语言处理技术已经在可接受的成本下实现了大规模可用,而邮件中蕴含着丰富而长期未被充分利用的数据。
老实说,我过去对 AI 编程的态度非常消极,直到今年三月才逐渐改变。到五月,我彻底意识到:软件开发的世界再也回不去了。虽然当前 AI 协作在团队层面还不算完美,但我相信随着规模增长,它的潜力会越来越明显。
举个例子:在 Sentry 时,我们曾为改进错误分组算法花了三周时间,仅仅是为了构建一个可视化工具来验证新旧算法效果。而现在,我用 Claude 半小时就能生成一个更漂亮、功能更完整的版本。过去很多项目夭折,不是因为想法不好,而是因为前期要投入大量精力搭建验证环境,而 AI 工具几乎消除了这道门槛。
此外,如今我能轻松用 Claude 构建日志可视化系统、云部署控制台等辅助工具,这些过去我根本不会花时间去做。现在连我并非技术背景的联合创始人也能直接用 Claude 和 Codex 构建原型,验证产品体验。很多功能模块我甚至不亲自写代码,但最终结果完全符合预期。
如今我们约有 80% 以上的代码是 AI 生成的,这些代码结构规范、测试完善,承担着标准化 API、开放接口、基础逻辑等工作。人类开发者的重点则放在那些真正需要创造性和深思熟虑的部分。这样的分工,使得整个研发过程前所未有地高效。
Gergely:过去你对 AI 编程工具一直持怀疑态度,为什么转变了想法?
Armin:最大的变化在于:这些工具现在真的开始替我完成那些我讨厌但又不得不做的工作。举个例子,就在昨天,我需要排查一个线上接口为何不能正常工作。问题并不在代码本身,而是出在 AWS 的权限配置上。结果发现是三个错误叠加造成的:一个是 IAM 权限问题,一个是系统白名单配置错误,最后还有一个逻辑漏洞。单独看每个错误都不难,但它们叠在一起时很难一眼看出问题所在。
过去这类问题我得花上两个小时才能理清,但这次,我一边处理别的工作,一边让 Claude 协助排查。虽然我仍需复制一些日志内容,但 Claude 能结合“世界知识”理解上下文,把不同系统的信息串联起来,帮我定位问题。我能继续推进其他任务的同时,它在后台帮我调试生产环境,这种效率的提升是质的变化。
另一个让我改变看法的关键,是它能自动生成“复现案例”(repro case)。过去我最讨厌写复现案例,但我也知道只要复现清晰,调试过程就会轻松得多。现在我只要告诉 Claude:“请帮我生成这个问题的复现案例,大致逻辑是这样。”它就能生成一个完整的示例,有时甚至能写出几千行代码。以前这种事得花上好几天。
从那之后,我开始越来越大胆地把更多任务交给它。现在我会把不想做的部分全权交给 AI,而把我想掌控的部分留在自己手里。这就是我转变的核心,意识到我可以这样高效地分工协作。
Gergely:那这些具备“代理(agentic)能力”的 AI 工具,会改变软件工程的哪些方面?又有哪些不会变?
Armin:系统架构、复杂度管理、可维护性……这些核心问题并不会因为 AI 而改变。我这些年积累的经验,比如如何让系统在规模扩张后仍然可维护,这些不是机器能完全替代的。
AI 工具确实能辅助工程师,但如果你把所有决策都交给机器,反而会丧失竞争力。因为机器生成的内容往往基于“已有知识”,而创新往往发生在尚未被模型学习到的领域。真正的优势,仍来自人类对新问题的创造性思考。此外,一家完全依赖机器的公司,也会失去团队的活力。Claude 不是人,它不会有情绪或激情。一个优秀的团队,靠的是人之间的能量与协作,这一点永远不会被 AI 替代。
当然,我在使用 Claude 时确实写更少的代码了,但“编程”的本质体验依然存在,只是我敲键盘的次数变少了。不同的是,AI 大大降低了构建自定义工具的成本,也让我能做出更好的决策。部分原因是它检索能力极强,当我遇到新问题时,它不仅能给出答案,还能解释“为什么”。这种能结合教学与解答的方式,对理解复杂概念特别有帮助。比如在一些我不擅长的数学问题上,它能把内容“翻译”成我能理解的形式,帮助我更快掌握。
还有一个显著的变化是,它让更多从未接触编程的人进入了这个领域。前阵子我在火车上遇到一位空管人员,他告诉我自己用 ChatGPT 学会了写简单的程序,以解决工作中的问题。过去这种人不会编程,而现在只因订阅了带有 Codex 的 ChatGPT,他就能实现自动化脚本。
我们会看到越来越多“新程序员”,他们的入门方式不是通过编程课程,而是因为 AI 让他们“顺便”写起了代码。过去要成为能独立产出成果的程序员,至少要花上几个月时间学习;而现在,只需输入几个指令,就能看到结果。这种即时的成就感,会让更多人愿意学习编程。AI 实际上降低了入门门槛,让编程变得更民主化。
Gergely:随着 Claude、Codex 以及其他越来越强大的 Agent 的出现,你认为编程语言的重要性会发生怎样的变化?它是否会逐渐变得只对少数人重要?也许只有像你这样长期研究语言优劣的人还会在意,而对大多数人来说,他们只需告诉 AI 用什么语言解决问题,AI 就能在现有代码库上直接完成任务。
Armin:我依然坚持之前的看法,非常尊重编程语言,因为它们背后蕴含着复杂的权衡。而在 AI 时代,我们可能需要重新审视这些权衡方式。
我之所以在创业中最终选择 Go,是因为我发现 Go 代码在 AI 场景下的可扩展性非常出色。它的抽象层很薄,使得 AI 更容易理解代码。我甚至做过实验:让 AI 在不同语言中各写十次同类型的程序,然后比较成功率,结果发现 Go 的表现远优于 Python,也明显好于 Rust。这说明编程语言依然重要,因为语言会直接影响 Agent 生成代码的质量。
至于现在的语言中是否已经存在适合“人机协作”环境的理想语言,我并不确定。也许我们已经接近了编程语言的巅峰,但也可能正是此时,会有人提出全新的设计思路:在 AI 降低某些成本、但提高其他成本的背景下,重新平衡这些取舍。
我认为编程语言仍然会非常重要,尤其是它在运行时环境中的权衡,这一点甚至会变得更关键。唯一不同的是,一切都在加速。技术演进的速度比以往更快,无论是产品层面还是技术层面,都让人感觉如果此刻不去投入,就会错过变化。
我相信现在有不少人正在尝试构建一种“为人类与 Agent 共同编程而设计的语言”,这不仅仅是一两个人的想法,而是整个行业的趋势。
当前确实是一个适合创造“更完美语言”的时刻,因为我们很可能不会马上摆脱 AI 生成代码的模式,而现有语言也未必是最佳选择。
不过,计算机完全取代人类编程的可能性并不高。人类仍会在相当长一段时间内保持在循环(Loop)中,参与更多我们意想不到的环节。因此,我们不可能追求“最优输出是直接生成汇编代码”的目标。那样的话,人类将无法审核这些代码。反而,未来的取舍可能会倾向于更高层次的语言,以便让审阅和协作更加容易。
Gergely:汇编语言的一个问题在于,每种架构或 CPU 类型都需要不同的汇编代码。这也是为什么在上世纪九十年代,Java 会如此流行,因为它能在不同系统上运行,比如 Mac。
Armin:没错,但如果 AI 能够自动将代码迁移到不同的操作系统,那也许可以反过来质疑:我们是否还需要为跨平台而设计语言?
Gergely:尽管 AI 理论上可以让我们“少干活”,比如让 Agent 在后台循环执行任务、你可以去睡觉,但现实中人们反而变得更忙了。尤其是在旧金山,一些 AI 初创公司甚至公开宣扬“996”,还会在社交媒体上自豪地展示团队在午夜仍在办公室奋战的场景。你怎么看这种趋势?
Armin:首先,我得特别感谢 Peter Steinberger,他很大程度上促使我深入接触“智能编程”。他当时经营一家叫 PSPDFKit 的公司,后来卖掉后重新开始写代码。他告诉我,他找到了一个“能替自己编程的电脑”,从那以后几乎废寝忘食。我一开始对此持怀疑态度,但后来我明白,Agent 编程确实会改变你的思维方式。
起初,我感到一种强烈的焦虑:每当 Agent 没有在运行、没有在产出,我就觉得自己在浪费时间。那种感觉几乎像上瘾,它带来即时的满足感,就像在拉老虎机一样。你一遍又一遍地运行它,期待新的结果。对我来说,这种“即时奖励机制”一度让我彻夜不眠,不是因为我在高效推进创业项目,而只是被这种过程本身所吸引。
此外,现在很多人都意识到技术正在发生巨变,都想尽可能抓住机会。这也助长了那种高强度的工作文化。但“996”是一种极端的工作制度——每天工作 12 小时,每周 6 天,几乎没有私人时间。我虽然也有过每周工作 80 小时的时期,但我始终不会把这种节奏常态化,因为我知道人不可能持续高效。尤其是我有妻子和三个孩子,家庭是我生命中最重要的部分,所以我的工作必须围绕家庭来安排。你可以高强度工作,但不必以牺牲生活为代价。
还有一点常被忽视:如果你是创始人,或者公司早期的核心工程师,且手里有真正有意义的股权,那你在高强度工作中得到的回报是不同的。但对于后来加入的员工,尤其在公司股权不太可能兑现的情况下,没有理由去透支自己去成全他人的利益。
我反感“996”被当成一种口号去宣传。它的本意是毫无弹性的劳动安排:每天 12 小时、每周 6 天,完全牺牲生活。而这种文化在现实中导致了严重的健康问题,甚至心理疾病。公司若真想倡导高能量、高投入的工作环境,至少也该坦诚地面对代价,而不是用带有极端色彩的数字去粉饰。
我在行业中见过太多惨痛的例子,包括一些社区成员因为长期过劳而出现精神问题,比如精神错乱或精神分裂。这些并非个案,而是长期高压与不健康生活方式的必然结果。工作固然重要,但没有什么值得你为此失去完整的人生。
3 错误处理心得
Gergely:不同语言在错误类型或频率上是否存在明显差异?从错误处理(Error handling)的角度看,编程语言的选择到底有多重要?
Armin:不同语言的崩溃方式确实不同,这不仅与语言本身有关,也取决于你用它构建的系统类型。比如,在大规模应用中,JavaScript 的错误极为常见,你打开浏览器开发者工具几乎在每个网站上都能看到各种错误和警告,但这些日志中的报错并不意味着网站无法使用。浏览器不会轻易因为 JavaScript 报错就崩溃,通常只是某个功能失效,例如事件监听器不再触发,导致“点击无响应”。这种问题在 Sentry 的早期产品中不容易被察觉,直到我们推出 Session Replay 功能,才更好地将错误与用户行为联系起来。
相反,在用 C++ 开发的电脑游戏中,如果程序崩溃,整个会话就会中断。虽然此类崩溃事件数量远低于 JavaScript 的报错量,但每一个都更具意义。也因此,不同语言的错误率难以直接比较,因为每种错误的影响范围完全不同。以 Sentry 的数据为例,C++ 崩溃报告的数量非常少,但每条报告的价值都很高。
当然,有些错误类型你见得多了会觉得“不该再发生”。在 JavaScript 社区中,类型检查器的普及确实减少了一部分可预防的错误,至少强制开发者在编译时显式处理空值,但我并没有观察到 TypeScript 的普及对整体错误率有明显影响。理论上,类型安全的语言应能减少某些低级错误,但在实践中,这种改善微乎其微,几乎无法量化。
这也可能与另一个现象有关:开发者在得到更安全的工具后,往往会更大胆地构建复杂系统。Sentry 发展过程中正处于“复杂化时代”,错误的来源也从“是否空值”变成了“微服务之间的版本不匹配”之类的问题。类型检查在这类场景中无能为力——网络层返回的空值仍然可能导致异常。
随着 React 等框架的普及,错误类型也在演化。比如“水合错误”(hydration errors)在 React 出现前根本不存在,但如今已成为常见问题。这些错误源于服务器端初始渲染与客户端动态渲染内容不一致。可以说,应用越复杂,错误种类就越多。
Gergely:像 React 这样的框架带来了全新的错误类别——以前根本没有,现在却随处可见。所以,从某种意义上说,错误甚至“越来越多”。
Armin:做错误监控的生意是个“安全的生意”,因为错误永远不会消失,只会不断演变。
Gergely:而且随着 AI 工具的普及,尤其是那些训练于最常见框架的模型,我们可能会看到代码量与部署量的爆炸式增长,这对错误监控来说也是机会。既然你们长期处在“错误的前线”,Sentry 团队在开发过程中有没有因为这些经验而改变对错误的处理方式?你们是否更有意识地在设计阶段考虑错误问题?
Armin:很多人会以为,在一家做可观测性(observability)产品的公司工作,团队自然会在构建自家系统时特别擅长处理错误与监控。但事实上,错误往往仍是“事后补救”的部分。要让团队真正重视那 5% 甚至 1% 的异常情况,需要强大的自我约束与文化建设。每次提交代码时,当测试通过后,很少有人会额外花时间去确保系统在失败时也能正确上报错误。
就我观察,Sentry 的代码在错误处理方面并不比其他公司的普遍更完善。因为“良好的错误报告”“合理的日志设计”“完整的指标采集”这些事情都需要刻意为之,而非自然产生。我们或许能比普通团队做得好 50% 或 100%,但整体上仍远远不够。要真正改善,理想的提升幅度应是千倍,而这只有在我们彻底改变编程方式、让语言自身在每个堆栈帧、每个异常路径中都原生支持这些能力时才可能实现。
从根本上说,我们要解决的不是“如何更好地分析错误”,而是“如何让错误数据更容易被收集”。这要求我们从编程环境层面重新思考:怎样的语言和运行时可以让可观测性成为内建能力。长期以来,开发者在这方面的主要障碍是“上下文传递”。Java 的 Ron Pressler 在介绍虚拟线程和 Project Loom 时曾讲过,堆栈帧的伟大之处在于它能隐式地携带上下文信息。但当程序转向异步模型或基于 Promise 的结构时,这种天然的上下文携带性就丧失了。
此时,如果你想让一个“关联 ID”贯穿整个调用链,必须在每个 Promise 之间手动传递,非常容易丢失。而有了堆栈帧,这种信息就始终存在,你可以随时向上回溯。
不同语言对此的解决方案不尽相同。例如,在 .NET 中叫作“执行上下文”(Execution Context),在其他语言中则称为“Context Local”。它是一种轻量级的上下文存储机制,可以随逻辑执行流传播,而不局限于线程。对于分布式追踪或 OpenTelemetry 等场景,这一点极为重要。我们在 Sentry 早期就反复强调“需要在各处支持 Context Local”,但 JavaScript 的浏览器端至今仍未原生支持。Node.js 后端经过多次演进,从早期的 domain,到 async hooks,再到现在的 async local storage,才逐渐具备这一能力。
Gergely:即便像 Sentry 这样的团队,开发时的首要目标仍然是“让功能跑起来”,错误处理依旧排在次要位置。而且,似乎在许多语言的设计中,错误与上下文传递本身也像是“事后补充”。如果从语言设计阶段就考虑到“程序一定会出错”,并让这种上下文传递成为底层机制,或许情况会好得多。
Armin:我倒不认为那是“事后补充”,更准确地说,这是“被有意忽略”的部分。因为语言设计总是要在不同需求间权衡取舍。以 Context Local 为例,它的最大问题是会让每次函数调用变慢。而对于追求性能的语言阵营,这几乎是不能接受的。要说服他们为调试性牺牲性能,难度极高。
一个典型案例是原生平台的编译器优化。过去,编译器为了多出一个可用寄存器,牺牲了堆栈寄存器(stack pointer)的保留方式,改用复杂的 DWARF 解栈机制来在调试信息中恢复堆栈。这种改动虽然提升了运行效率,却让实时性能分析和错误堆栈恢复变得极为困难。举个例子,这让我们在 Sentry 中处理原生代码崩溃报告时经常拿不到完整的堆栈信息,因为对应的调试符号文件往往缺失或不可访问。
Facebook 曾为了解决类似问题,在 Android 应用中“偷偷”采集系统符号表,以改进错误报告质量。Sentry 当然不可能那样做,那会损害用户信任。直到大约两年前,Debian 或 Red Hat 的工程师才推动恢复堆栈指针的默认行为。虽然这样会带来大约 5% 的性能损失(Python 特例高达 20%,因此未启用),但他们仍认为这是值得的。可见,这背后其实是一场长达数年的博弈:调试能力与性能之间始终难以兼得。
Gergely:这确实让人意识到语言设计的艰难。每个选择都在牺牲某一方,要么牺牲性能,要么牺牲可调试性。语言必须服务不同的用户群:有的人只关心运行速度,有的人却更在意崩溃后的可恢复性,没有哪个方案能让所有人满意。
Armin:我现在对语言设计师的尊敬比以往任何时候都高。编程初学者常常天真地以为“语言就该这样设计才对”,但随着经验积累,你才会理解各种权衡背后的复杂性。很多决定看似微小,但会深刻影响语言的使用者群体。比如,我曾觉得 Python 是构建 Web 服务最理想的语言,因为它可以在运行时轻松检查进程状态而不明显拖慢性能。可后来才意识到,这正是 Python 性能偏慢的根本原因之一。
4 给“初创”的建议
Gergely:从担任初创公司早期工程师的创业经历中,你学到了什么?你会给现在加入一家快速成长型初创公司的工程师什么建议?
Armin:如果从十年前加入初创公司的视角来说,我的经历其实是一条相对线性的路径:遇到一个机会,我评估是否想做,然后决定要不要接下。这有点像“秘书问题”(secretary problem),只是我没有尝试太多次,而是倾向于在觉得事情有趣、有价值时就全情投入。
我本身并不是一个典型的“好员工”,我不太适合被固定在某种角色或框架中。在 Sentry 工作这些年,我的头衔从“软件工程师”到各种管理职位都有,但我从未真正把自己与某个头衔绑定。早期的时候,我甚至要处理各种琐事:例如管理办公室、处理薪资、买家具。
所以,如果你加入一家早期初创公司,要做好心理准备:一切都处于混乱和变化中,没有清晰的边界或流程。有些人热爱这种不确定性,有些人会非常不适应。如果你喜欢尝试新事物、乐于应对模糊与挑战,那就勇敢投入;否则,你需要有非常清晰的目标与路径意识,知道自己要往哪里走,即使中途会有曲折或暂时的退步。
Gergely:现在你自己也创办了一家公司,从早期工程师变成了创始人。这个过程和你想象的有什么不同?作为一个曾经的“早期员工”,你现在在创业时有什么新的体会吗?
Armin:某种程度上,我其实在很久以前就开始为创业做心理准备。回想 Sentry 初期的那几年,也许当时就存在另一条可能的路径,比如我们可以做别的产品。后来,当我的股份在四五年后完全归属时,我也想过是否要开始新的事情。那时我看到像 Vercel 这样的公司把 Next.js 打造成一个完整的业务体系,我就在想:是否也能把 Flask 打造成类似的平台?
这一次创业,我和联合创始人从“我们希望建立一家怎样的公司”出发,而不是“我们想做什么产品”,这是与上一次最大的不同。我们都知道自己是那种会去创业的人,但这次我们更想先明确“为什么要创业”。当然,也可能会因此想太多,但回头看,如果当年 Sentry 能早点讨论这些基础问题,许多后来遇到的困难也许能更早化解。
所以现在我刻意在一开始就思考这些长远问题,比如股权结构、激励机制、合作方式等。经验让人更清醒:许多事情你可以在书上读到、在播客里听到,但只有亲身经历过,才会明白那种压力、紧迫感与责任感。十年前我就爱读各种创业故事,也以为自己理解了创业,但真正做起来,感觉完全不同。
Gergely:无论你读了多少创业故事、听了多少建议,只有亲身去做,才会真正体会其中的不同。
Armin:对某些人来说,阅读和学习可能足以让他们做好准备,但对我不是。没有哪本书或播客能让我真正准备好。我成长过程中接受的教育很普通,并没有教我如何面对创业的不确定性或复杂性。这些都只能在实践中一点点摸索、学习。
Gergely:你最喜欢的编程语言是哪一种?
Armin:Python。一是它给了我职业生涯的起点,这份情感很深;二是尽管它在设计上有许多缺陷,但却极其务实。我喜欢这种“实用主义”的精神。就像 Flickr 和 Slack 的前 CTO Cal Henderson 使用 PHP 的方式一样,他并不在乎语言“是否完美”,而是专注于“能否解决问题”。我用 Python 做产品时也是这种心态,它让我能高效完成很多事。
Gergely:有没有一个你特别喜欢的工具?
Armin:如果不局限于编程工具,我最喜欢的其实是一把电动螺丝刀。它能拧螺丝——听起来很平常,但当我第一次买到一套真正高品质的电动工具时,我的生活发生了变化。我开始更愿意打孔、组装家具,也更享受动手创造的过程。
Gergely:** 这似乎也是一个隐喻:当你拥有好的工具,你会更有动力、更愿意去尝试新事物,也会变得更有冒险精神。
参考链接:
https://www.youtube.com/watch?v=45kVol96IlM
声明:本文为 InfoQ 翻译整理,不代表平台观点,未经许可禁止转载。
今日好文推荐
极客时间 8 周年庆送好礼啦~100% 中奖!人人有份!
这一次来真的,献上超强福利:
✅ 15 小时视频职业指导
✅ VIP 月卡 / 周卡 / 年卡免费领
✅ 职场突围特训营、InfoQ 大会门票
✅ Air Pods 、限量周边、AI 实战手册、现金红包…
相关文章
编译|傅宇琪、Tina 在 AI 写码逐渐成为“新常态”的当下,编程语言的选择反而更重要。 Flask 作者、创业者 Armin Ronacher 指...
2025-10-18 1
本报讯 (毛延锋 记者徐东周)近日,新型丙烯酸盐灌浆材料在河北省高碑店市投产转化。该产品为河北省市场监管局科技计划项目,由河北省产品质量监督检验研究院...
2025-10-18 1
证券之星消息,根据天眼查APP数据显示中兴通讯(000063)新获得一项发明专利授权,专利名为“报文处理方法、客户端设备、服务器端设备和介质”,专利申...
2025-10-18 1
“你家发大水,把楼都淹了!”旅游途中接到这样一个急电,可想而知,心情会多么复杂。近日,广东惠州的李女士旅游途中接到物业来电,得知家里发大水,水流进楼下...
2025-10-18 0
来源:睿见Economy2025可持续全球领导者大会于10月16日-18日在上海市黄浦区世博园区召开。曼彻斯特大学名誉教授,《大脑传》作者马修 · 科...
2025-10-18 1
中新网上海新闻10月16日电(夏圣雪 许婧 10月14日,“2025全球工程大会·首届世界绿色设计大会”在华东理工大学举行。来自政府、高校、企业及国际...
2025-10-18 1
本篇文章给大家谈谈河北麻将来一把有挂,以及河北麻将多少个一副对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。 麻将怎么玩 一般我们参加的人数为4...
2025-10-18 1
发表评论