Jake Wharton:Kotlin、开源与软件开发的未来


Jake:Kotlin、开源与软件开发的未来

这是一场关于编程语言、开源文化与软件工程未来的长篇对谈。Android 开发者、Retrofit 与 OkHttp 的作者 Jake Wharton 回顾了 Kotlin 进入 Android 生态的历程,分享了自己对 Kotlin、Java、Swift、Rust 以及跨平台开发的看法,也谈到小团队、远程工作、开源维护和职业选择。面对人工智能快速进入软件行业,他从软件质量、开发者责任、劳动者权益与技术伦理等角度,解释了自己为何拒绝过度依赖 AI,并坚持让技术服务于人,而不是让人被工具和商业模式所支配。

第 1 章

Jake: 我要裁掉一大批工程师,把他们所有的工作都交给大语言模型。

Huyen: 你怎么看这种转变?

Jake: 整个大语言模型行业都靠风投资金撑着:先补贴用户使用,让用户上瘾,再开始榨取价值。这就是他们的套路。

Huyen: Coinbase 的 CEO 裁掉了 14% 的员工,还提到了 AI。

Jake: 那还不算太糟。我离开 Cash App 后,他们裁掉了 70% 的工程师。

Huyen: Kotlin 还是一项职业优势吗?

Jake: 我不太确定它现在还算不算优势。

Jake: 我喜欢 Rust。

Huyen: 你会考虑用 AI 智能体写代码吗?

Jake: 从来没有。

Huyen: 如果六个月后 AI 写的代码比你好,你的 B 计划是什么?

Jake: 大概还是会继续……

第 2 章

Huyen: Jake,2010 年,Java 是世界第一大编程语言,Android 也运行在 Java 之上。JetBrains 为什么还要开发 Kotlin 与它竞争?为什么要做这种尝试?

Jake: Kotlin 出现时,Java 语言的发展有些停滞。Oracle 正在接手这门语言的管理工作,版本发布间隔仍然长达两年;Google 的团队只能受限于 Java 语言当时所提供的能力,这就为其他语言留下了机会。当时,社区也在寻找替代语言:有人使用 Scala,也有人尝试 Groovy。Kotlin 恰好出现在大家渴望更现代的语言的时候。

Jake: Java 生态之外的其他语言不断演进,让人们看到了许多令人向往的特性。JetBrains 本身又是一家工具公司,能在推出新语言的同时提供 IDE 及周边基础设施。因此,相比一门必须从零构建一切的语言,Kotlin 更容易得到采用。它还能利用现有生态:你不必丢掉原有的 Java 库,甚至不必丢掉整个既有的 Java 代码库。你可以逐步引入和迁移,继续使用自己熟悉的库,再随着时间推移逐步采用 Kotlin。

第 3 章

Huyen: Jake 是 Android 开发者,也是 Retrofit 和 OkHttp 的作者。他把 Kotlin 带到了 Android;2025 年,在科技行业大规模裁员期间,他离开了大科技公司,并公开反对 AI。

Huyen: 2017 年,Google 宣布 Kotlin 成为 Android 官方语言之一。后来,你成了 Google 的 Kotlin 团队中第一位工程师。这是怎么发生的?

Jake: 当时我已经在 Square 工作了五六年,而我们大约三年前就采用了 Kotlin。为了让公司批准使用 Kotlin,我写过一份文档,解释我们为什么应该使用它。我把文档公开了,因为其中并没有只适用于我们自身场景的内容,它基本上是一篇支持这门语言的通用论证。

Jake: 那份文档极大地提升了 Android 社区对 Kotlin 的兴趣。我也就逐渐成了深度参与这门语言发展、积极推广其应用的人。随着关注度不断上升,Google 内部的人也意识到 Kotlin 可能带来很大好处。我认识的人开始暗示,这件事或许真会发生,并询问我是否有兴趣参与。

Jake: 对于把 Kotlin 引入 Android 这件事,我想不出比加入那家为整个 Android 生态提供工具的公司、让 Kotlin 成为 Android 官方支持的语言更大的认可了。这是一个不可能拒绝的机会。

第 4 章

Huyen: Android 团队在采用 Kotlin 时遇到过反对意见吗?

Jake: Android 团队确实有所迟疑。当时,Android 已经以 Java 为基础发展了大约十到十二年,团队非常熟悉它,而且整个技术栈到处都有与它的集成。现在却要采用一种相对较新、尚未充分验证的语言——Kotlin 大概也只是在一两年前才真正稳定下来——当然会有风险和顾虑。

Jake: Google 并非完全厌恶风险,但他们希望把各方面都考虑周全,所以 Kotlin 的引入方式非常审慎。它不是一次硬切换,也不是一夜之间就宣布新语言取代旧语言,而是渐进采用。对于 Android 发布的库,我们最初会为 Kotlin 构建配套库;过了很久,才开始用 Kotlin 重写基于 Java 的库。

Jake: 这几乎再次证明了 Kotlin 对 Java 传统的尊重:把它集成进代码库的人不需要一夜之间把所有东西全部切换掉。

第 5 章

Huyen: 除了 Android,Kotlin 还用在哪里?

Jake: 最初几年,由于 Android 社区对 Kotlin 的支持声势很大,大家产生了误解,以为它只是一门 Android 语言。当时甚至有文章说,它是 Google 专门为 Android 开发的语言,这显然不是真的。

Jake: 好在此后 Kotlin 在更多领域得到了采用。例如,以前会用 Java 编写的后端服务,现在也会用 Kotlin。Spring 这样的框架和生态如今已有许多功能优先支持 Kotlin。除此之外,JetBrains 正在大力推进多平台方案,因此在 iOS 生态中也能看到 Kotlin 的身影。现在也有用 Kotlin 开发的桌面应用;其中使用最广泛的应用之一,可能就是供用户获取各种 IDE 的 JetBrains Toolbox。

Jake: Android 很早就采用 Kotlin,也帮助它在其他领域播下了种子。举个具体例子:在 Square,我们所有后端服务原本都使用 Java。公司最初批准 Kotlin 时,只允许在 Android 上使用。我们对此非常兴奋,后端的 Java 开发同事看到后也想尝试。后来 Kotlin 也逐渐获准用于后端,他们便能使用它了。我认为,Android 对 Kotlin 的采用一直是推动其他生态开始使用它的催化剂。

第 6 章

Huyen: 现在给你一个任务:用 60 秒向一位 Java 开发者推销 Kotlin。

Jake: Kotlin 就是 Java 也许十年后想成为的样子。但由于 Java 不能破坏现有代码,它需要很长时间才能推动语言演进。那些最终很可能进入 Java 的特性,现在 Kotlin 已经提供了。

Jake: 而且你不必使用最新版本的运行环境。虽然我们当然希望大家使用新版 JVM,但确实仍有代码库停留在 Java 8 或 Java 11。Kotlin 尊重这一现实:即便目标平台可能是旧版 JVM,你仍然能使用这些现代语言特性。

Huyen: 目前在生产环境中使用 Kotlin 的最大公司有哪些?

Jake: Facebook、Google、Amazon。它们当然最先在移动端使用 Kotlin,但现在构建后端服务时肯定也在使用。你还能看到它们在开发许多相关工具。就在我们录制本期节目这一周,Facebook 正在把自己的 Kotlin 格式化工具贡献给 Kotlin Foundation,最终让它成为 Kotlin 的官方格式化工具。

Jake: 这些很可能是世界上规模最大的代码库。能让它们从其他语言迁移到 Kotlin,确实证明了这门语言的实力,也证明了这些公司对它的长期投入。

第 7 章

Huyen: Google 是许多工程师梦想中的公司,也是你推动采用的 Kotlin 的最大使用者之一,但你工作两年零九个月后就离开了。为什么?

Jake: 我之前在 Cash App 工作。我们推动了 Kotlin 的采用,也用 Kotlin 编写了许多开源库。后来 Google 决定在 Android 上采用 Kotlin,去 Google 做这件事是一个不容错过的机会。不过,我离开 Cash App 时基本上就说过,自己大约两年后会回来,因为我的计划就是过去完成这件事:让 Kotlin 成为 Android 官方支持的语言。

Jake: 我很喜欢开发工具和库,但我不想一辈子只做这些。我也想使用自己构建的东西。因此,我的想法是在两年里尽我所能,让 Kotlin 取得成功、成为 Android 官方支持的语言,确保自己未来能依靠它,然后再回去使用我在 Google 构建的成果。

Jake: 所以两年期满时,我确实准备离开,回到原来的方向。可就在我要正式提交离职通知前,Google 批准了另一个我非常想做的项目,于是我又留下九个月完成那个项目。

Jake: 但归根结底,我想用工具和库创造产品,而不只是开发工具和库。我必须回到一个能让我享受这些投入所带来的收益的岗位。Google 有很多值得喜欢的地方,也有一些不讨人喜欢的地方。不过,我觉得自己已经完成了目标,于是必须回去使用自己构建的东西。

第 8 章

Huyen: 抱歉,你说“不讨人喜欢的地方”,指的是什么?

Jake: Google 是一家非常大的公司。好在 Android 团队与 Google 的其他产品团队相对隔离,我在那里共事的人也非常优秀,这些方面都很棒。但我对 Google 这家公司有许多意见,比如他们会设法把你锁在自己的产品和服务体系里。不过 Android 团队非常出色,我确实怀念做那些工作的日子。

第 9 章

Huyen: 在 Cash App 工作五年后,你于 2025 年 11 月,在科技行业大规模裁员和危机之中离职。找新工作有多难?

Jake: 这并不是最容易的事。市场上当然还有工作,不过我有点挑剔,对下一家公司有一些要求。我很幸运,能够按照自己的意愿主动离职,所以并没有极强的紧迫感,也没有立刻陷入绝境。

Jake: 工作机会肯定仍然存在,但市场已经不像五年前那样,随便一个人走进来都可能被立刻招走,做 Android 开发还能拿到高得离谱的薪水。我必须付出更多努力。我非常同情那些被迫开始求职的人。但我不认为市场已经彻底崩盘:工作仍然存在,只是要花更多时间,也必须找到让自己脱颖而出的方法。

第 10 章

Huyen: 现在美国高级 Kotlin 工程师比较现实的薪资范围是多少?

Jake: 我通常看到的基本工资从 20 万美元起,此外一般还会有一定数额的股权,也许每年价值 10 万美元,并按照完整的四年归属期逐步兑现。当然,也有很多岗位低于这个水平。

Jake: 总体来说,公司现在更加留意资金流向,不再开出高得离谱的薪酬。要是你确实想得到更高的数字,就得进入某些潜在回报更丰厚、风险也更高的领域。显然,我们正处在一个所有人都聚焦于某项特定技术的时期。你可以找到薪酬远高于上述水平的工作,无论现金还是股权都可能更多,但那些股权可能归零,也可能涨到十倍。

Jake: 所以这实际上取决于个人选择:你处在人生的哪个阶段,能够承受多大的风险。我现在已经不想做这种押注了,更愿意获得持续而稳定的现金薪酬。年轻时则完全相反,我非常乐意承担这种风险。有时会赢,有时会输。随着生活状况改变,对你而言最重要的东西也会变化。

第 11 章

Huyen: 到 2026 年,Kotlin 对软件工程师来说还是一项职业优势吗?

Jake: 我不太确定它现在还算不算优势。某种意义上,这恰恰体现了这门语言的成功:Kotlin 已经变成了一项基本要求,不再是差异化优势,也不再稀有或难以找到。

Jake: 这正是因为 Google 采用了 Kotlin,并让它成为 Android 官方支持的语言。现在进入 Android 领域的人学的就是 Kotlin;当你进入这个就业市场时,大家默认你已经掌握它,因为所有人都在使用。Compose UI 也是一样:大约四年前它还比较少见,如今已经成了默认要求。

Jake: 除非你会使用这门语言更高级的特性,例如多平台功能,那才可能成为优势和差异化因素,让你从其他 Kotlin 开发者中脱颖而出。但我认为它本身已经算不上多大的优势;现在更多体现的是它已经无处不在。

第 12 章

Huyen: 求职时,你公布了对未来雇主的九项价值观。我会逐项念出来,请你解释它们的含义,以及为什么它们对你很重要。第一项:不要 AI——不要 AI 公司、基于 AI 的产品,也不要强迫开发人员使用 AI。

Jake: 它排在第一位是有原因的。这可能是我最看重的条件。我们所处的时代正在快速变化,不仅开发方式如此,许多公司也在把 AI——基本上就是大语言模型——强行塞进本来可能根本不该有它的地方。

Jake: 我认为没有人真觉得过去几年软件质量有所提高,也不觉得这种工具长远来看会提升软件质量。但某些公司高管似乎会这么看,他们认为这种工具能让工程师工作得更快,产出质量更高的代码。我认为事实恰好相反。

第 13 章

Jake: 此外还有这些工具背后的伦理问题。它们基本上建立在人类历史上规模最大的版权侵权之上。这里有一个非常鲜明的对照:Aaron Swartz 曾下载约 30 GB 的科学资料,因此面临数十年监禁。那大概是 2013 年前后的事,我不记得确切时间了。面对版权侵权指控,他最终选择结束自己的生命。

Jake: 再看今天,这些模型的训练方式实际上无视艺术家的版权,也无视现有代码的许可证。你能访问某样东西,并不意味着你有权将其混编、重新演绎,甚至在某些情况下把吸收的内容原样输出。

Jake: 我们还看到新闻说,Facebook 使用 BitTorrent 下载了数百万本书和数 TB 的数据。短短十五年,我们就从 Aaron Swartz 事件走到今天这种局面。这些公司考虑问题时,伦理似乎根本不在考量范围内。我不想与这些事情产生关联,但要避开它们正变得越来越难。

Jake: 所以这一项排第一是有原因的,它立刻排除了很多公司。这也直接反映了我为何离开 Square 和 Cash App。

第 14 章

Jake: 这件事最奇怪的地方在于:想想我们日常使用的工具,通常是某位工程师对 Kotlin 这样的新语言、IntelliJ IDEA 这样的新 IDE,或者某个新构建系统感到兴奋。这是一种由工程师推动的过程:你对某样东西产生热情,这份热情感染其他人,然后你去央求工程管理者允许大家使用 Kotlin,或者购买 IntelliJ IDEA 许可证之类的东西。

Jake: 为什么 AI 技术的推广方式完全相反?为什么一家公司的 CEO 应该告诉你日常工作该怎么做,命令你使用某种工具?他们不会跑来对你说:“你应该使用静态类型语言,因为这样我们就能用编译器可检查的方式对业务需求建模。”不会的,这是由工程师作出的工程决策。

Jake: 为什么要在语言里对空值和可选性建模?诸如此类的事情,一直由我们工程师主导。因为我们了解业务需求,所以会选择能让我们有效交付业务所需产品的工具。如果 Jack Dorsey 跑来对我说必须使用 Eclipse,我大概也会辞职。

Jake: 当公司领导层强迫你使用这些工具时,情况就不一样了。单是这一点或许还只是一回事,可再加上一轮又一轮的裁员,怎么看都不是好兆头。

第 15 章

Jake: 我可以作出个人选择,说自己不会使用这些东西。总体而言,一家公司要去构建这些东西,我认为是在抢占地盘、趁机捞钱,也就是趁热打铁。从经营策略上说,我可以理解这种做法:钱在哪里就去哪里,用户在哪里就去哪里,而现在钱和用户确实都在那里。

Jake: 这也回到了薪资的话题。我的处境很幸运:长期努力工作后,我已经为自己赢得了选择工作去向的自由,很多人并没有这种条件。所以那份清单代表的是我自己,而 AI 排在最前,是因为它是我现在最看重的因素。它立刻排除了我原本可能加入的 80% 的公司。

Jake: 幸运的是,我现在可以在选择工作时贯彻自己的价值观,把最重要的条件放在首位。这样做越来越难,但这一项似乎最受关注,也最能立即引起反响。AI 是当下我们行业里最受关注的话题,所以它排在第一。

第 16 章

Huyen: 第二项:不要加密货币。密码学是好东西,但加密货币很糟糕。

Jake: 沿着这份清单往下看,你会发现每一项都能和我之前所在的环境对应起来。在大语言模型之前,风口是加密货币。在 Square 和 Cash App,我们同样非常深入地投入了这个领域。

Jake: 加密货币基本上就是庞氏骗局,对吧?它没有真正的价值。但这几乎又与我的许多其他价值观背道而驰,例如所有权,以及不让别人控制你通过劳动获得的东西——这些理念我完全赞同,错的是实现方式。它实际上已经演变成了一套掠夺性的体系,唯一能赚到钱的,要么是靠让别人蒙受损失而获利的人,要么是在它之上搭建业务、再从客户身上攫取价值的人。

第 17 章

Huyen: 远程工作:我远程办公,但也乐意每年去办公室几次。

Jake: 我从 2015 年起就一直远程办公。这种工作方式一旦习惯了,就很难再回去。我很喜欢面对面相处。我们录这期节目时正好有一场会议,我能见到大约 50 个认识的人;平时最多也不过一年见一两次,有些人甚至要隔好几年才能见到。所以我依然很看重面对面的交流、人与人之间的互动,以及由此建立起来的同理心。但我不想再每天坐在车里通勤了。

现在我有了孩子,这种灵活性尤其宝贵:可以按需要自由安排工作时间,也能根据家人的生活安排和实际情况调整工作。真的太舒服了,我回不去了。

第 18 章

Huyen: 开源:你使用开源软件,也发布自己的开源项目,或者希望开始这么做。

Jake: 我几乎只熟悉开源这种开发方式,因为当初为了成为更好的开发者,我就是转向开源社区,借此学习新技术和其他知识。所以对我来说,默认做法就是:只要我在尝试或构建什么,就把它公开出来。

后来我去了 Square,我们把很多东西开源,也因此取得了很大成功。我认为几乎每家公司都建立在他人劳动成果的基础之上。如果你把自己的东西开源,或者为开源项目做贡献——即使那个项目不是你创建的——这就是一种回馈,也是在让这份帮助延续下去。下一个企业或项目可能会建立在你参与构建的东西之上,就像你起步时也复用了 Linux、Android、SQLite、JVM 等不必由自己从头构建的东西一样。

第 19 章

Huyen: 客户优先于股东:你的产品专注于为客户提供价值,而不是让股东变得更富有。

Jake: 很少有产品能让我每次看到更新都兴奋。更多时候我感到的是担忧:这次更新又弄坏了什么?改了什么?又把什么移到付费墙后面了?这就是所谓的“平台劣化”(enshittification)——这个词几年前还当选过年度词汇。

资金不可能源源不断。很多公司靠风险投资起步,初期确实很好;作为这些公司产品的用户,你也能获得大量价值。但接下来不可避免地会发生转折:这些公司从一开始就没有可持续的模式,之后不得不彻底转向某种可持续的商业模式,结果通常对用户不利。

我想选择一家已经具备可持续经营机制的公司。它不需要为了回报风险投资者,或者为了把华尔街投资者的利益置于真正的产品用户之上,而设法从用户身上攫取价值。

第 20 章

Huyen: 人优先于利润:不使用零工,也不采取榨干客户每一分钱的剥削性做法。

Jake: 这和上一条并没有太大区别。不过有一类公司会依靠风险投资补贴,以低价冲击某个市场,比如 Uber 和 Airbnb。最初几年,Uber 比出租车便宜,是因为某个风险投资人替你支付了另一半车费。等这笔钱没了、公司必须转向盈利时,再坐 Uber 就会和出租车一样贵,甚至更贵。

你可以对工会有各种看法;有好的工会,也有不好的工会。但出租车公司受到监管,从业者基本都必须满足一定要求。如今的零工经济则不同:这些公司会让人觉得,“我可以业余送餐,多赚一点钱。”但你没有把车辆折旧、油耗等成本算进去。与真正全职成为出租车司机相比,作为零工个体,你最终会失去很多权利。传统行业里有相应制度提供保护,而零工经济里没有。所以,这整类公司都是我不想参与的。

第 21 章

Huyen: 小而专注:把一件事做好,胜过试图满足所有人的一切需求。

Jake: 我在 Square 的第一段经历,以及我们打造 Cash App 时最美好的日子,都是团队规模还很小的时候。你认识每一个人,能够迅速把愿景变成现实。与后来相比,当时的你甚至会天真地相信自己无所不能。

我离开 Cash App,也就是 Square 时,公司好像已经有 12,000 人了;而我加入时只有 200 人。至于 Google 有多少员工,谁知道呢?那又大了一个数量级。公司一旦到了这种规模,就会形成官僚主义习气,产品开发速度放慢,大家也开始有点急切地寻找能够带来新用户的新东西。

团队小的时候,我觉得事情会更纯粹一点。你可以找到某个细分方向,然后非常专注地把它做好。我也属于喜欢做很多不同事情的人。公司越来越大以后,工程师的职责往往会越来越窄。我记得听说,大约五年前有个人在 Twitter 工作,只负责私信界面。当时私信甚至还没有后来那么多聊天功能,他做的真的就只是 Twitter 私信。范围窄到这种程度,你就失去了参与产品不同部分开发的机会。

我希望能在一个产品内部灵活切换,做各种不同的事情。这也会带来很多学习机会。东西规模较小时,你承担的职责更多,会被迫走出舒适区;因为没有一个 50 人的团队替你管理其他事情,不能只是把需求扔过墙,等两个月后别人交付结果。你必须更多地亲自动手。

第 22 章

Huyen: 多元、公平与包容:要让机会得到公平分配,需要主动付出努力。

Jake: 你住在哪里、出生在哪里、以前做过什么工作——生活中各种因素都会让你获得某些优势或处于某些劣势。这甚至不只是性别、肤色之类最容易想到的因素。

还是以我在 Cash App 的经历为例。我们讨论薪资时,我发现身处不同国家的同事和我做着完全相同的工作,却只拿当地市场价,可能只有我在美国所得薪资的一半。这在我看来不合理。他们只是碰巧住在那个地区而已。于是你会看到有人仅仅为了让工资单上的数字更高而搬到美国,除此之外,做的工作完全相同。

这个例子和性别、肤色无关,但你所在的地区同样可能让你处于劣势:收入更少,甚至可能不足以维持自己想要的生活。当然,那些显而易见的问题也一样——因为别人无法控制的特征而歧视他们,这种做法荒谬至极。

很难相信我竟然还需要把它明确写成一条价值观,因为其中很多东西本来就不该需要写出来,它们本来就是理所当然的价值观。反对这些观念的人小时候也许应该多看一点《Star Trek》之类的作品。在那里面,人们长得完全不同,甚至是外星人,都是再正常不过的事;女性也和男性承担同等角色。我们早就不该再需要专门讨论这些问题了。

但由于更大的政治环境,现在出现了许多反对这些观念的声音。所以我认为有必要明确说出来:这件事对我依然非常重要。

第 23 章

Huyen: 工作与生活的平衡:我的手机上不装工作聊天或代码审查工具。

Jake: 在 Square 的头五六年,我手机上装着 Slack 和 GitHub,星期六晚上临时上线审查一个 PR,我完全不觉得有问题。这对我本人或许没什么,但后来我意识到,实习生、初级员工或其他刚加入的人看到我这么做,并不知道背后的原因。

他们不知道,虽然我星期四人在办公室,但可能因为状态不好、需要看医生或其他原因,那天根本没工作。所以我只是在把时间补回来:某天晚上工作得晚一点,以补上星期四没做的工作;或者进入状态后连续工作 12 个小时,第二天直到下午一点才打开电脑,以此取得平衡。

但不了解这些背景的人只会看到:“Jake 一直工作到晚上八点,星期天晚上十一点还在审查我的 PR。”于是他们很可能认为公司就是这样要求的,觉得自己也应该在手机上安装工作聊天工具。这完全是一个合乎情理的推断。

周末有人问了一个工作问题,而你十秒钟就能回答,表面看当然没什么大不了。但你正在开一个先例。尤其是在远程办公普及、手机应用又如此强大的今天,人太容易永远保持在线了。可我认为断开连接非常有价值,也希望把这个观念传递给别人。我想让大家看到:不查看工作邮件是没问题的。星期五下午五点关掉它,到星期一早上九点再打开,这应该成为常态,而不该被视为某种反常行为。

第 24 章

Huyen: 哪条价值观让你损失的工作机会最多?“不用 AI”排除了 80%,然后呢?

Jake: 真正大幅限制选择范围的,是关于风险投资的那一条:要找一家能够盈利、有健康商业模式、具备某种赚钱途径的公司;它也不能依附于自己无法控制的外部系统,不能建立在别人的技术之上,以至于价格波动或地缘政治事件一发生,公司突然就无法持续经营。

这一条直接排除了大约 95% 的潜在公司,因为普遍采用的就是那种模式。风险投资支持的公司也可以很健康,但我认为那是例外,而不是常态。这里还有一个直接冲突:那些规模小、又以健康方式接受风险投资的公司,很可能做的也不是我感兴趣的东西。所以我会说,这一条让候选范围缩小了 90% 到 95%。

这确实是一条很难坚持的原则,特别是因为另一类公司通常也意味着更高的薪资。如果这真是我的价值观,我就必须做好接受降薪的准备。

第 25 章

Huyen: 2026 年 2 月,经过三个月的求职,你加入了 Skylight。为什么选择这家公司?

Jake: 它契合了我们刚才谈到的许多价值观,除此之外还有一个锦上添花的优点:我自己就是这个产品的目标客户。我已经在使用这款产品,也确实有这种需求和家庭场景,而这正是一款面向家庭的产品。

我一直很想折腾硬件,而他们做的就是硬件产品。我也很喜欢它不在 Play Store 上架,因此不用应付 Google 那整套东西。我们自己分发应用。这里还有很多我从未做过、但与 Android 相邻的工作。除了在 Google 时会构建 Android 操作系统,并在开发框架的过程中构建自己的模拟器之外,我其实没怎么接触过 AOSP,也没真正做过实体硬件设备,不了解其中有哪些要求。

应用不在 Play Store 上架,意味着你对操作系统拥有相当大的自主权,几乎可以让它做任何想做的事。所以,它满足了我们讨论过的许多价值观;公司资金状况良好,也有收入来源,而且成员总体上都非常优秀。

我认识 Kevin Barry,也就是 Nova Launcher 的作者。他比我早大约六个月加入。我觉得他愿意选择这家公司,是对它的一次重要信任背书。

对其他公司来说有点不走运的是,Skylight 恰好是我接触的第一家公司,于是它成了衡量其他所有公司的标杆。后来我看得越多,选择就越容易。其他公司也有很不错的机会,但没有哪一家能像它这样,把我寻找的所有东西完整地组合在一起。

第 26 章

Huyen: 为了加入 Skylight,你需要在自己的九条价值观中做出任何妥协吗?

Jake: 我觉得没有。其中一个问题是,他们之前确实没怎么做过开源,但他们对此持开放态度。他们也完全接受这样一个事实:我仍然维护着许多开源项目,这依旧是我的一部分职责,其中很多项目甚至也用在他们的产品里。

他们确实有一些 LLM 功能,但整个产品并不是围绕它构建的。这些功能加得很克制,完全可选,你不必使用;而且我认为这些功能运用得很恰当。整个产品并没有转型为聊天机器人之类的东西。他们——现在应该说“我们”了——希望能够以克制、恰当的方式使用它。他们此前已经证明了这一点;现在我加入以后,也希望能继续把这些价值观带进公司,我认为这会产生积极作用。

所以确实没怎么妥协,这几乎是一个毫无悬念的选择。

第 27 章

Huyen: 你在那里具体在做什么?

Jake: 这是一款面向家庭的产品。它本质上是一台可以挂墙或放在台面上的大型 Android 平板,运行一款以家庭或住户管理为核心的应用。家庭具体是什么结构并不重要;它的目标是把各种待办事项从你的脑子里移出去,主要帮助父母减轻负担。

比如,记住哪个孩子要踢足球或参加演出、这周要去商店买什么、这周吃什么、谁什么时候会在家、孩子的哪些家务应该何时完成;还要督促孩子履行责任,努力帮助他们养成健康习惯等。他们喜欢用一句醒目的话来概括它:“家庭操作系统。”

整件事的核心,就是减轻家庭主要照料者的认知负担,把这些事情全都放进设备里,由它替你管理,让你可以专心做一个好的家庭成员。

第 28 章

Huyen: 我们回到 AI。2026 年 5 月,Coinbase CEO Brian Armstrong 裁掉了 14% 的员工,并提到了 AI。他的原话是:“非技术团队现在也在发布生产代码。”你怎么看这种转变?

Jake: 这本来就不是一家让我多么尊敬的公司。它几乎违背了我的每一条价值观,而且他本人也不是什么优秀的公众人物。我记得他就是那些宣称“工作场所不谈政治”的人之一——这句话本身当然就非常政治化;与此同时,他自己却可以随心所欲地在 Twitter 上发表政治言论。

这看起来很短视。还是呼应我们前面谈过的内容:整个 LLM 行业都是靠风险投资的钱撑起来的。就在我们录制这期节目的这一周,GitHub Copilot 要改成按用量收费的消息传得很广。我不清楚原来的具体方案,好像一直是按月收费,每月大约 30 美元;现在之所以转为按用量收费,是因为先前为了跑马圈地、抢占市场份额而提供支撑的资金正在消失。

于是某个人的 GitHub Copilot 账单就从 30 美元涨到了大约 1,400 美元,差不多增长了两个数量级。这不会是个例,而会成为普遍模式。

接下来你会看到,一些公司已经对 AI 形成依赖,离开这些 LLM 产品甚至无法运作,而它们的成本将会上涨。上涨一个数量级或许还能承受,但两个数量级会让许多“用 LLM 替代工程师”的设想彻底破产。我也经常看到有人讨论:随着这些成本上升,哪怕只看纯粹的薪资支出,最后也会比你原以为能被替代的那名工程师更贵。

我对降低门槛这个概念并没有太大意见。让希望为代码库做贡献的人更容易参与,我完全支持。我合作过的最优秀的设计师之一,曾用一个周末学会 Android 开发,然后在 Android 代码库里写出一段极其复杂的动画,直接提交了一个 PR。这非常出色。

所以,让并非专职工程师的人也能以更切实的方式做贡献,能够真正影响正在构建的东西,我完全赞成。但这件事有负责任的做法,也有不负责任的做法。所谓不负责任,就是直接说:“我要扔掉一大批工程师,把所有工作都转交给 LLM。”

14% 甚至还不算特别严重。我离开 Cash App 后,他们裁掉了 70% 的工程师。他们认为可以靠提高组织效率来弥补人员减少的影响——组织当然确实可以更精简——但他们还想把一切都交给 LLM,让每个工程师完成四个人的工作;也让产品人员通过聊天系统生成 PR,却并不真正全面理解产出究竟是什么。

我认为这种方式在短期内可能有效,但最终会造成软件质量的长期下降。至于这种下降会发生在成本上涨一到两个数量级之前还是之后,我不知道,但我认为这两件事都不可避免。成本上涨这件事,我觉得并不存在多少争论余地,事情就是会这样发展。整个行业不过是在重复其他公司早已用过的套路:拿风投资金补贴用户的使用成本,让用户形成依赖,然后转向价值榨取。这就是标准剧本,所以一定会发生。我认为那样做相当短视,因为最终一定会反噬他们。

Huyen: 你试过用 AI 智能体写代码吗?

Jake: 从来没有。我选择采取一种极端立场,因为我想确保人们会认真思考自己正在使用的东西背后究竟是什么。这里面的问题太多了。

就拿科技从业者整体来说,我们很少成立工会,因为过去资金充足、薪酬优厚,一切都很好。既然如此,我们为什么还需要工会带来的额外力量?可现在资金正在枯竭,你会看到一轮轮裁员,看到人们被随手抛弃。我们现在身处德国,这里的劳动者保护非常完善;而在美国,你可能还没收到通知,账号就已经被关掉了,或许只是突然发现邮箱不再刷新。

我觉得,依赖这些系统本质上是在把权力从自己手中转交出去。你把自己变成了一个可替换的齿轮,公司随时可以丢掉你,再找一个更便宜的版本顶上,从而节省成本。

我还认为,这会让你自己承担很大风险。这里大概有两个维度:一是使用 LLM 的伦理问题;二是责任问题,也就是存在负责任和不负责任的用法。

负责任的用法,是把它当作助力,用它增强你作为工程师已经具备的能力,让你更高效地发挥自己的实际能力。至于不负责任的用法,则是让它编写超出你自身能力范围的代码——如果没有 LLM,你根本做不成那件事。

考虑到前面说的定价问题,这样做风险很大。假设 LLM 的价格上涨 20 倍,你只能负担得起过去所用 token 的 4%。如果你已经极度依赖这个工具,是否会因此基本丧失日常工作的能力?还是说,你可以回到传统方式,只在少数地方使用它,用来完成那些乏味、重复或需要大范围机械修改的任务,也就是更有效地使用它?

所以,目前我觉得自己还可以坚持这种极端立场。我不知道能坚持多久,希望我能撑到泡沫破裂、大家集体重新审视这一切的时候。我不认为它会彻底消失,但我希望人们在过度使用之前能多想一想。不要依赖到这种程度:让整个软件工程工作都建立在它之上。让它仅仅成为工具箱里的一件工具,就像我们已有的无数其他工具一样。

第 29 章

Huyen: 如果六个月后 AI 写的代码比你更好,你的 B 计划是什么?

Jake: 我大概会去规模越来越小的公司工作,赚越来越少的钱,同时保住自己的幸福感。毕竟我已经不在职业生涯的起点,也不再拼命争取晋升。我很幸运,过去所做的选择给了我很多机会,也让我身处一个可以坚持这种强硬立场的位置。很多人并不具备这样的条件。

不过归根结底,我很难相信你说的情况真的会发生。现在不断有研究在探讨 LLM 将如何随时间发展。它们本质上建立在人类的集体成果之上——姑且说是 2022 年以前的成果。有一项研究,我本来应该事先查清楚,印象中可能来自哈佛大学。研究基本确认:当模型把自己生成的数据重新喂给自己训练时,必然会导致模型坍塌,整个过程不可持续。

所以,要么我们认定开发者永远不会再进步,软件质量从此就停留在当前水平,并接受 LLM 生成的代码;要么就必须有人亲自创造新的东西。

LLM 也不会思考,不具备智能,无法推理,更不知道自己为什么会做出那些选择。归根结底,那些选择都来自统计。我不觉得自己需要担心。它现在确实已经强得有些吓人,但从机制上说,它也注定具有不确定性。由于它是基于统计的方案,就一定会写出 bug,不可能每一次输出都百分之百完美。

我们都从 Stack Overflow 复制过带有 bug 的代码;那里一些得票最高的答案也藏着非常微妙的 bug。最终得到的代码仍然需要调试。因此,我不相信未来会完全不再需要专心写代码的程序员。

第 30 章

Huyen: Kotlin 最初是为了消灭 Java 样板代码而诞生的,而我们知道 AI 很擅长写样板代码,人类不必再受这种苦了。那么,AI 是否已经消灭了 Kotlin 相比 Java 最主要的优势?

Jake: Brian Goetz——我想他现在是 Java 的首席语言设计师——一再强调,代码被阅读的次数是被编写次数的十倍。我从不认为实际敲出代码是最困难的部分。

在写代码之前,你得思考并决定解决问题的正确方式:边界应该划在哪里?如何为业务中的复杂事物建模?写完之后,还要长期维护这些代码。人们会发现 bug,需求也会不断变化:可能是因为外部环境变化——人类社会在发展,政治和其他事物都在改变,你必须更新代码来反映这些变化;也可能只是因为业务本身发生变化,公司开始关注产品的其他方面或开发新产品。代码会存在很长时间,也会被反复修改。

所以,最初编写样板代码这件事并不是我最关心的问题。Kotlin 早期确实也紧紧抓住这一点来宣传:需要输入的字符更少;不必分别写 getter、setter 和字段,只需声明一个属性;还有尾随 lambda 语法,可以写出漂亮的 DSL。我认为这些都是吸引人们使用这门语言的切入点,因为它们很容易展示在幻灯片或网页上。

但归根结底,一门语言和它的库是兴盛还是衰亡,取决于它们能否让代码库长期保持高效。这不只是写样板代码,还包括长期维护;因此需要非常优秀的工具,而强类型系统之类的能力也会在长期演进中持续提供帮助。

我不认为样板代码才是真正的问题。当然,AI 可以很好地帮人度过无从下笔的阶段,而且我们确实不缺相对乏味或繁重的任务,比如把一千个调用点全部更新为指向新的实现。把这种工作交给 AI 会很有价值。但长期来看,真正的问题并不在这里,这也不是语言本身真正闪光的地方。更重要的是类型系统、工具以及周边的一切,因为它们能让代码库持续演进和成长。

第 31 章

Huyen: Java 现在已经有 record、sealed class 等特性,看起来 Java 与 Kotlin 之间的差距正在缩小。Kotlin 的黄金时代结束了吗?

Jake: 值得肯定的是,Java 并没有躺在功劳簿上停滞不前,也没有认输。它改为每六个月发布一次,让新的语言特性先以实验形式推出并接受社区测试,同时还在底层基础设施上做了大量工作,使语言更容易演进。

事实上,我觉得 Java 引入的许多语言特性,做得比 Kotlin 更周全。Kotlin 往往只能设法把这些能力嵌入现有限制之中。如果只看 JVM,Kotlin 最终要编译成 Java 字节码。Kotlin 真正进入大众视野时,目标还是 Java 6 字节码,所以它实现的语言特性都必须转换成与 Java 6 兼容的字节码。

Java 语言没有这个问题。它可以引入 record 这样的特性和新的字节码指令,也可以修改虚拟机来满足语言需求。语言、字节码和虚拟机可以同步演进,因此能够把 record 之类的能力实现为高度统一的整体。相比之下,Kotlin 的 data class 能做的只有生成普通 Java 类、普通方法,或许再附加少量元数据。

为了让 Kotlin 未来继续保持竞争力,我非常希望它能正视这些新特性,并设法把它们整合进来。

第 32 章

Huyen: 如今 Kotlin 哪些方面做得比 Java 更好?

Jake: 我认为,可空性方案依然极难超越。所谓“十亿美元错误”常被说成是空指针异常,但真正的问题其实并不是存在 null,因为我们总是需要表达“缺失”这一概念;问题在于类型系统没有正确地对它建模,没有迫使你面对某个值可能为空的事实。

如果一切都可能为空,而你又可以选择忽略这一点,最终就会在运行时遇到故障。Kotlin 把 null,也就是“缺失”的概念提升到类型系统中,直接从程序里消灭了一整类 bug。

作为程序员,你需要做的改动相对简单:当某个值可选时,只需在类型末尾加一个问号,就能彻底消除一类 bug。这至今仍是一个极其强大的理念。

第 33 章

Huyen: 如今 Kotlin 和 Swift 主宰着移动开发:Android 使用 Kotlin,iOS 使用 Swift。Swift 哪些方面做得比 Kotlin 更好?

Jake: 我非常喜欢 Swift 这门编程语言。与 Kotlin 相比,Kotlin 当初必须同时做到与现有 Java 代码互操作,并以 JVM 字节码为目标。Swift 虽然也要与 Objective-C 互操作,但我觉得它的历史包袱更少:设计者可以决定自己想要的语言特性和能力,也可以决定这些特性如何编译,因为它不必以某种既存表示形式为目标。

例如,Swift 的错误处理在语言中是一等概念。它迫使你明确一个函数是否可能抛出错误,这一点很像 Kotlin 迫使你处理可空性。

相比之下,Kotlin 对异常的处理基本等于没有处理。JVM 有异常机制,Java 语言又有受检异常和非受检异常;Kotlin 的选择实际上是:“底层虚拟机使用异常机制,所以我们也必须使用,但我们把所有异常都当作非受检异常。”

我认为这正是 Kotlin 的一个痛点:你不知道自己调用的任何函数可能以什么方式失败。如何为函数潜在的失败建模,一直是 Kotlin 语言演进中的课题。比如把字符串解析成数字时,字符串里可能含有字母,因此解析可能失败。怎样对这种情况建模,才能迫使每个调用者都正视失败的可能,而不是在代码库里埋下一颗地雷?

在 Swift 中,这个函数会被标记为 throws,你必须在调用处使用 try!,或者用 try? 等安全方式调用。

Swift 另一个令我印象深刻的地方是,它以原生代码为目标,因此拥有真正的 struct 和非常紧凑的内存表示。Kotlin 则建立在 JVM 之上,那里一切都是类,一切都有字段,而这些在虚拟机中都会带来指针间接访问。对象的内存表示分散在堆上,需要不断解引用指针;Swift 却能使用紧密排列的数据结构,让数据装进 CPU 缓存行。因此,底层数据表示造成的性能困难,是这两门语言之间另一个非常突出的差别。

第 34 章

Huyen: 那反过来呢,Kotlin 哪些方面比 Swift 做得更好?

Jake: 这个问题很难回答。我其实认为 Swift 是一门设计得比 Kotlin 更好的语言,Kotlin 在语言本身上胜过 Swift 的地方并不多。

Kotlin 的优势更多来自语言之外:它的库生态、开源生态,当然还有工具。Kotlin 配合 IntelliJ IDEA 的工具体验,乃至构建系统,都远胜于 Swift 对应的工具链。要在大型 iOS 代码库里重构绝不是什么愉快的体验。Xcode 用了多少年才加入重命名重构?那几乎是 IntelliJ IDEA 二十年前最早拥有的功能之一。iOS 开发者为此欢呼时,我会想:“我真替你们高兴,但你们本可以在二十年前就拥有它。”

只看语言本身,我不认为 Kotlin 有太多方面明显胜过 Swift。真正让 Kotlin 使用体验如此愉快的,是语言周围的一切。哪怕你设计出了世上最好的语言,如果工具、库、静态分析,以及让语言真正用于生产所需的一切都没有成熟方案,也不会得到广泛采用。

别误会,Kotlin 是一门很棒的语言,Swift 也是。Kotlin 完善的周边生态,才真正把它提升到了如此令人愉快的高度。

第 35 章

Huyen: 你刚才提到了错误处理和失败模型。在你看来,哪门语言的错误处理做得最好?

Jake: 我喜欢 Rust。Rust 的许多设计决定都非常契合我的思维方式:当然应该在类型系统中表达这些事情;当然应该考虑所有权和借用;当然应该明确谁负责关闭那个文件描述符。

我之所以会这样想,是因为经历过痛苦:多年来使用这些不具备相应能力的语言时,我经历过资源泄漏、内存泄漏和文件描述符泄漏,遇到过空指针异常,也遇到过某个本以为不会失败的函数突然抛出非受检异常。当你一次次经历这些痛苦,就会开始思考有没有更好的方式。

许多语言都在尝试不同方案,但我认为 Rust 做得尤其好。它是一门很难的语言,需要跨过一道门槛,之后才会开始觉得它直观。我还没跨过去,也不擅长 Rust,但 Rust 的理念与我的思维方式非常契合。

我不确定它在语言层面的具体实现是否称得上最好,因为它实在太难学了;但在如何建模和表达这些问题上,我认为它是最好的。

第 36 章

Huyen: 谢谢你这么说。回到 Kotlin,你会在哪些场景中避免使用 Kotlin?

Jake: 我的日常工作会大量使用 Kotlin,所以做业余项目时,我想尝试非常不一样的东西。最近我在玩微控制器,这类设备的内存非常少。虽然可以让 Kotlin 将它们作为编译目标,但这稍微超出了 Kotlin 的舒适区:这门语言更希望周围有一个相对完整的操作系统。

所以,在嵌入式、非常底层的系统内部场景中,Kotlin 有些过重,不太适合用在那种资源受限的环境中。

我也不太喜欢在 Web 上使用 Kotlin。如果你已经有一个 Kotlin 代码库,想复用全部代码而不重新实现,或者想让某套业务逻辑拥有单一事实来源,那么选择 Kotlin 并让它编译到 Web 会是巨大的优势。

但如果我要从零开始构建一个 Web 应用,Kotlin 不会是我的首选。我认为 Compose UI 在 Web 上的设计并不真正遵循 Web 的原生机制。如果 Web 是唯一的目标平台,你大概不会优先选择 Compose UI 或 Kotlin。

当然,如果已经有了这些代码,只需像打开开关一样,就能把现有成果带到不同平台,这仍然很有价值。iOS 也是如此。坦率地说,除了 JVM 之外,对其他平台而言,共享既有代码的主要价值也在于此:能把已有代码拿过来,让它在 iOS 上运行,是一个巨大的优势。

我们在 Cash App 做这些事情时,目的并不是取代 iOS 工程师,而是把他们从重复工作中解放出来,让他们投入那些真正有趣、真正能让 iOS 体验出色的部分:用户界面、动态效果、动画、交互,以及这个平台独有的一切。他们不必再重复编写从服务器同步数据,或者实现应用后端逻辑的同一套代码。

因此,虽然 Kotlin 最终能在所有这些地方运行,但如果你正在构建的只是一个 iOS 应用,我不确定你会不会选 Kotlin。更稳妥的选择会是 Swift。

有趣的是,Kotlin 几乎能在任何地方运行,而“至少可以成为候选项”本身就是一项巨大优势。不过,那些平台之所以彼此不同,自然有它们各自的原因,对吧?如果没有自己的不同之处,它们也就不会存在了。所以,如果你要从零开始面向其中一个平台开发——嵌入式、Web、iOS,或其他类似平台——而且只以它为目标,那就应该尊重这个平台独特、不同的地方。Web 就是 Web;微控制器有它的种种约束;iOS 则有非常丰富的用户界面交互方式。在这些情况下,Kotlin 不会是我的首选。

Huyen: 对你来说,是不是应用领域决定了编程语言?比如你提到嵌入式编程,在那里你会选择什么语言?

Jake: 这很难回答。为公司正在打造的产品选择语言,和我自己当作爱好随便玩时的选择并不一样。做这类东西时,我一直在用 Rust。Rust 的嵌入式开发生态很棒,有很多库能以很有意思的方式,把硬件领域的问题呈现在语言中。

它们基本上是把 Rust 的异步概念映射到硬件上。比如,你可以直接 await 按钮按下事件,而不必自己轮询,也不必设置某种在事件发生时唤醒你的中断机制。基本上一行代码就能表达这件事。因为我日常工作用不到 Rust,而且就像我之前说的,这门语言的理念和价值观很合我的胃口,所以我选择它,一方面是为了完成自己想做的东西,另一方面也是想找个理由玩玩这门语言。

第 37 章

Huyen: 2020 年,你回到 Cash App,并在那里工作了五年。你做了什么?

Jake: 那段时间我做的主要项目,是一套用于业务逻辑的多平台方案。我们当时有个问题:需要以比应用商店发布更快的速度更新应用。这通常与某种法律要求有关。比如美国某个州会突然通知我们:“你们必须修改这里的措辞。”毕竟我们处理的是资金,有大量必须遵守的法律和监管规定。他们可能会说:“为了合规,你们必须修改这段文字或它的呈现方式,而且只有三天时间,否则我们会禁止你们在本州开展转账业务”,或者处以罚款,诸如此类。

因此,我们需要以更快的速度调整应用行为。倒不是说不可能这么快发布应用商店更新,但如果总要这样做、总要打乱正常的发布节奏,就会成为负担。所以,我们要构建一种方案,不经过应用商店更新,也能更新应用里的部分业务逻辑和用户界面。

我们评估了许多不同技术,最终选择了 Kotlin Multiplatform。我们主要以 JavaScript 作为执行引擎,因此 Android 和 iOS 应用都会内置一个 JavaScript 引擎。我们使用了 Compose,但没有使用 Compose UI:所有逻辑仍然用 Compose 编写,在 JavaScript 引擎中运行,然后与原生应用通信,并像操纵提线木偶一样驱动用户界面,改变内容的呈现方式。

这样一来,当需求发生变化时,甚至只是每周迭代功能时,我们都可以把变更作为更新发布,由客户端下载。下次应用重启时,新逻辑就会运行。界面仍然全部由原生 View 构成,感觉仍然是平台原生的;理想情况下,用户根本意识不到幕后发生了更新。也就是说,我们在 UI 与业务逻辑之间加了一层间接层,让业务逻辑可以通过应用商店之外的渠道更新。

当时真正可用的基本只有 JavaScript,所以我们先专注于它;等 WebAssembly 生态发展起来、更加成熟,真正成为可行选项之后,我们原本打算转向 WebAssembly。

从技术角度说,这套方案当然有局限,但最终非常实用。我们遇到的许多问题其实是人的问题:如何让产品的不同部门接受它,以及项目管理层不断更替等。就执行结果而言,它非常成功:我们确实完成并发布了它。它也真正承担了重任,支撑应用中一些非常关键的页面,每天有数百万人使用。

不过,随着公司发生变化,他们决定寻找另一种方案,于是这个项目最终被逐步终止。好在其中没有与具体产品绑定的东西,所以全部都开源了:我们构建的库和工具都已开源,项目还衍生出了一些其他库。它们现在仍然在那里。

这是一段非常有成就感的经历,因为它把你带出了熟悉的 Kotlin 舒适区。Kotlin 是你非常了解的东西,但你把它放进了一个非常陌生的环境——JavaScript 生态——而且还使用了不含 Compose UI 的 Compose。这是一次非常棒的学习经历。我觉得自己今天做的很多事情,都深受当时技术选择以及我们开源的那些库的影响。

第 38 章

Huyen: 我们先做个概述。这里谈的是 Kotlin Multiplatform,也就是 KMP。它解决了哪些 Flutter 和 React Native 也许没有解决的问题?

Jake: 我认为 Kotlin Multiplatform 相对独特的一点,是它选择如何面向各个平台。在 JVM 和 Android 上,Kotlin 编译成 Java 字节码;在原生平台上,无论是 iOS、PC 还是微控制器,它都通过 LLVM 编译成真正的原生代码;在 Web 上,它编译成 JavaScript,现在也可以把 WebAssembly 作为目标。

因此,它能使用各个生态中原生的代码执行方式,真正融入每个生态。相比之下,Flutter 虽然只用一种语言编写,但它只编译成原生代码。它本质上很像游戏:游戏拥有自己完整的渲染栈,是一个可以在任何平台上运行的原生程序;它带着自己的 UI 工具包,无论在哪里运行,看起来都还是那款游戏。Flutter 做的基本也是这件事,只不过对象变成了应用。

它并没有真正尊重各个平台独特的地方,因为它去除了平台内在的 UI 工具包,又重新实现了完整的渲染栈。如果准备这么做,那我们为什么还要有两个不同的平台?甚至把 Web 也算进来:为什么不干脆做一个到处都能运行的网站?

所以,当我比较这些代码共享方案时,会想到我们依赖的一些全球最大的库,比如 SQLite。它用 C 编写,到处都能运行。但在 Android 上使用它时,我们理所当然地认为,已经有人替我们完成了连接原生代码、绑定 C 库,以及在边界两侧封送对象的工作。Flutter 也有同样的跨边界问题,而 Kotlin 不会以这种方式与你的目标平台隔离。

Kotlin 在 iOS 上运行时,可以直接操作同一内存空间中的对象,也可以直接链接其他库,最后一切会共同编译进同一个二进制文件。在 Web 上,你可以调用 JavaScript,也可以公开 JavaScript API;最终它们会编译到同一个包里,性能特征也基本一致。你并不是在每个平台上运行一个类似“异物”的东西。

这就是 Kotlin Multiplatform 所做的选择,而 Kotlin 团队已经完成了实现它所需的艰苦工作。用 Flutter 时,你身处 Dart 生态,构建出一个庞然大物,然后把这一整坨东西带到所有平台。用 Kotlin 时,你可以选择要共享多少,不必共享一切。你可以只共享那些不值得写三遍、容易出错或出于其他原因适合复用的部分,把它们做成更小的可复用组件;然后在每个平台上采用所谓的原生方式,为 Web 或 iOS 上的用户提供最佳体验。你的应用会和平台上的其他应用感觉一样,用户不会察觉底层还有一层共享的 Kotlin 代码。

第 39 章

Huyen: 我看过你的一些演讲,感觉你很喜欢拿 React Native 开玩笑。

Jake: 比起 Flutter,我更喜欢 React Native。我觉得 Flutter 的某些技术决策甚至有些令人难以接受。你的公司得相当失调,才会在已经打造出人类历史上最流行的操作系统 Android,以及由 Chrome 主导的 Web 平台,并同时掌控这两个平台的情况下,又因为公司内部的失调造出第三个平台。相比之下,你绝不会看到 Apple 做这种事:他们不可能再做一个 Safari 和 iOS 的竞争对手并发布出去。

React Native 至少非常努力地使用各个平台的原生 UI 来渲染。你可以在 Web 上运行 React 业务逻辑,得到 DOM 元素;在 iOS 上运行,得到原生 UI View;在 Android 上运行,得到 Android View。这很难做到,需要投入大量工作。

我认为,我们 Android 开发者不喜欢它,是因为它又回到了前面说的问题:它削弱了原生平台开发的许多乐趣。但至少 React Native 的技术选择尊重各个平台,它非常努力地提供具有原生感的体验。你完全可以做出非常优秀的 React Native 应用,当然也能做出非常优秀的 Flutter 应用。不过 Flutter 应用我能认出来——我妈妈可能认不出来,但我能。React Native 则完全可能骗过行家,因为它用的就是普通的原生 UI 工具包。仅仅上手操作,你无法知道背后其实由 JavaScript 驱动。

归根结底,我们在 Cash App 构建的东西和 React Native 并没有相差太远。我们研究过 React Native,其中有许多东西是我们喜欢的,也有许多我们认为方向选错了的地方。React Native 让你能在每个平台上非常细致地控制 UI,可以设置各种属性,精确调整渲染效果。

但我们已经有一套设计系统,而且各个代码库里都已经实现好了。因此,我们最终选择严格限制共享代码能够决定的渲染细节。共享代码只能说“这是一个主按钮”,但不知道按钮是什么颜色、圆角半径是多少,也不能决定点击效果,或 Android 上的涟漪动画之类的东西。你什么都不能设置,只能说它是一个按钮。而在 React Native 中,你可以设置圆角半径等细节,所以它确实赋予了你很大的能力。

我们在 Android 生态里爱拿他们开涮,是因为彼此本质上是竞争对手。希望这是一种友好的竞争。当然,这又是极其严肃的事情,毕竟关系到你的生计。但可以肯定的是,比起使用 Flutter 应用,我更愿意使用 React Native 应用。

第 40 章

Huyen: 我想你说的是 Redwood,对吧?那个专注于原生渲染的多平台 UI 库。你已经解释了它是什么,但当初决定采用原生渲染,主要考量是什么?

Jake: 这又回到了我们当时的想法,也符合我个人的价值观:我依然认为原生 UI 是最好的 UI。我理解产品人员为什么希望应用在每个平台上看起来都一样。对他们来说,他们希望用户总能认出自己的产品,始终沉浸在自己的产品体验中,并熟悉产品的外观。

但并不是所有人——应该说,虽然确实有不少人会在平台间切换,但总体而言,大多数人不会不停地从 Android 切到 iOS,再切到 Web。他们通常只使用一个平台,并在这个平台上的二十个应用之间切换:从一个 iOS 应用进入另一个 iOS 应用,再进入第三个 iOS 应用;或者从一个 Android 应用进入另一个 Android 应用。

因此,真正让用户感到熟悉和安心的是平台内部的一致性。当按钮点击、列表滚动等操作在不同应用中有相同的行为时,用户就会感到熟悉,并能凭直觉知道接下来会发生什么。他们知道手指按下按钮时会有怎样的反应、看起来是什么样子,也知道各种控件和图标的含义。只要用户身处同一个平台,你就希望自己的应用与其他应用保持一致。

这就是背后的基本动机:我们希望每个平台的 UI 仍然是原生 UI,因此它们可以看起来不一样。但对背后的业务逻辑而言,我们只想表达“在屏幕上放一个按钮”或“放一个开关”。这个开关在 Android 上也许是横向的,在 iOS 上也许是纵向的;具体在每个平台上如何渲染,对共享的业务逻辑并不重要。

业务逻辑才是没人愿意重复实现三遍的东西。你不会想去问 iOS 团队的同事“这个情况你们是怎么处理的”,结果发现他们的处理方式完全不同——这正是我们想消除的问题。理想情况下,我们希望把开发者从重复业务逻辑的工作中解放出来,让他们真正把原生 UI 体验做到最好。

当然,这个要求很高。它和 React Native 不一样:你不能只是坐下来就往屏幕上摆像素。采用这种方案,实际上要求你已经建立了设计系统:应用有哪些可复用组件?哪些区块或其他元素会出现在多个页面?有哪些高层概念?又该如何建模,才能把它们暴露给可复用代码?

它完全不是开箱即用的方案,当时也不是。我们事先已经投入成本构建了这些东西,而 Redwood 是为了充分利用此前的投入,并进一步改进它。但如果从头打造一个新产品,我觉得你未必会选择这条路,因为仅仅为了在屏幕上放出第一个按钮,就得先构建并建模整套设计系统,工作量太大。

所以,这背后的核心理念就是提升各个平台的原生 UI,让它们可以提供相似、功能一致的体验,却不必以完全相同的方式渲染。

第 41 章

Huyen: 我在某处看到有人特意说明 Redwood 是一个库,而不是框架。看起来这是一个很重要的设计决定,是这样吗?

Jake: 总体来说,我们就是这样看待自己构建的东西。我们希望它们是能嵌入系统的一块砖,而不一定是承载一切的地基,因为事物总会变化。

如今许多应用已经有十年、十五年的历史。我们经历过不同的响应式建模方式,甚至彻底换过一门语言。很多代码库十五年前启动时用的语言,和我们现在使用的已经不同了,UI 工具包也变了。

把东西做成库而不是框架,确实会把负担转移给使用者。它不像是在应用中加一行代码,或者让所有类继承某个基类,就能毫不费力地获得全部能力。你必须稍微思考一下它要如何融入代码库的其余部分,可能还得编写谁都不太喜欢的胶水代码把它接进去。有时候,这种体验确实不太好。

不过,随着开发者的偏好改变、产品需求随时间演进,库能让你灵活地把它接入或移除。也许五年后你的观点变了,觉得当初做错了。如果它是框架,与代码库的一切都深度绑定,那么把它迁移为其他方案将是一项巨大的工程。如果它是库,而且你的系统以某种模块化方式构建,迁移仍然需要工作,但希望可以逐步完成。

以 Redwood 为例,我们把 JavaScript 部分,也就是动态更新部分,做成了完全独立的模块。因此,你可以完全以原生方式单独运行 Redwood,只使用它提供的设计系统抽象;然后用 Kotlin Multiplatform 编写业务逻辑,并单独把它完整编译成本地代码。

底层的可更新机制则是另一个名为 Zipline 的库,可以像另一块砖一样插在下面。Zipline 完全不了解 Redwood,Redwood 也完全不了解 Zipline。当然,你还得编写胶水代码,把这两块砖组合起来,最终创造出比两部分单独存在时更高的价值。

第 42 章

Huyen: 你个人的编程环境是什么样的?IDE、插件和工具呢?

Jake: 现在非常朴素。视项目而定,我使用原版 IntelliJ IDEA 或 Android Studio。插件非常非常少。我通常会安装 SQLDelight 插件,那是我参与开发的库之一,用来处理 SQL。

除此之外,我在 IDE 外使用 Ghostty 终端。IDE 里的新终端其实非常非常好,我只是已经习惯使用独立终端。另外,我会开着 Firefox 查文档。这三样东西就是我一整天来回切换的窗口。

第 43 章

Huyen: 所以你用 Firefox,而不是 Google Chrome。

Jake: 对。这又要说到道德层面的问题。实际上,正是浏览器市场的竞争成就了 Chrome;但后来它存在得足够久,最终也成了反派。Chrome 的市场份额高得不成比例,如今基本可以强迫整个生态接受它的做法,而不是以更健康的方式参与生态。

第 44 章

Huyen: Kotlin 社区里流传着一句话:“如果 Jake 的代码编译失败,那说明编译器里有 bug。”你怎么看待这件事?

Jake: 说到这种事,我有个有趣的故事。我在 Google 工作时,某个 subreddit 修改了页面 CSS,让每条评论显示的用户名看起来都是我的名字。于是就会有 Google 的同事不知道这是怎么回事,把一条据说是我写的评论截图下来;评论可能是在谈 Flutter。确实有很多谈 Flutter 的评论是我写的,但他们截到的往往是一条煽动性评论,或者是用一种我不该采用、更不该公开使用的措辞评价 Google 的产品,然后他们会把它举报给我的经理。我甚至不得不跟我经理的经理解释 Reddit 是什么,以及 CSS 怎么能把这些署名都改掉。我很幸运,开发这些库的许多尝试都取得了成功,也因为这些工作和参加大会演讲而获得了一些知名度。所以,确实会有人拿这件事开玩笑,我完全不介意。

第 45 章

Huyen: Kotlin 的哪个特性最让你恼火?

Jake: 过去我会说,我不太喜欢默认是 public;我觉得应该默认是 internal。这是我确实怀念 Java 的一点。我理解支持现状的理由,也可能是因为我更常做库,所以看法有所偏向:开发库时,必须非常谨慎地控制对外暴露的公共 API。但这是我以前的答案。现在的答案其实刚才已经谈到了:我觉得 Kotlin 对异常和错误处理并没有做出一个经过深思熟虑的选择。我认为那是一个不得不做的选择,因为 Kotlin 必须与 Java 互操作,而且构建在 JVM 之上、以 JVM 字节码为目标。

Jake: 语言确实需要正确地建模这些情况,也需要提供相应的工具,让我们能够表达许多操作都可能失败这一事实,而真正更重要的恰恰是如何处理这些失败。它们确实是异常情况,但异常发生时系统采取什么行为,结果会有天壤之别。大家可能都遇到过这种产品:所有按钮突然都没反应了。比如你正在买火车票,怎么点屏幕都没有反应,原因可能只是你不小心点了两下,某个不变量检查抛出了异常,后台线程崩溃,于是整个应用失去响应,因为开发者从没想过这种情况可能发生。一个不知从哪里冒出来、一路向上传播的异常,就这样拖垮了整个应用。

Jake: 网络也是一样。过去开发这些移动应用时,我们通常坐在家里或办公室,Wi-Fi 接入点就在六米外,还连着光纤网络。但真实情况是,我会在火车上使用你的应用;火车钻进地下,我的蜂窝网络时断时续,你的整个应用就逐渐卡死,功能也不断报错,最后完全无法使用。你其实只要告诉我当前没有网络就行。再比如买票,如果语言迫使你处理“这种情况可能发生”这一事实,你就会构建相应机制,让应用自行重启之类的。

Jake: 所以,我非常希望语言能够对操作的可失败性、错误和异常进行建模,并迫使开发者思考这些问题。尤其是,出错的位置和调用的位置往往相隔很远。你调用的一段代码可能在远处发起网络请求,而这个请求可能失败;在调用点,你未必知道它底层其实访问了数据库、远程服务或其他东西。如果语言能迫使你选择:要么以某种方式处理错误,要么把错误继续传给调用方——就像我们用静态类型处理正常路径上的其他一切一样——我希望这种能力能进入语言。异常一次又一次地让人吃亏,而语言目前为此做得还不够。不过还是有希望的,我们拭目以待。

第 46 章

Huyen: 我看到 Reddit 上有个热门帖子问:“使用 Kotlin 时,你最糟糕的经历是什么?”得票最高的回答是 Gradle。为什么是 Gradle?

Jake: Gradle 确实很容易引发争议。不过我觉得我们从中获得了巨大的价值。我在 Gradle 出现之前就开始做 Android 了,所以当时能有一个构建系统,是非常令人欣喜的。

Jake: 归根结底,我认为 Gradle 的一个问题,也是人们对它如此沮丧的原因,是他们早期关注的是构建脚本写起来有多容易、写法看上去有多讨巧,而不是正确性或性能。在过去十年里,他们不得不回过头来逐步补齐正确性和性能方面的短板。这意味着,你当初写下的那些简洁漂亮的写法,往往恰恰效率低下。因此这十年间有很多痛苦和反复变化:为了得到快速、增量、正确、可靠且高性能的构建,我们实际上不得不一点点重写这些构建文件。

Jake: 这与另一类构建系统形成鲜明对比,比如 Bazel:它们首先关注正确性和性能,但用户体验糟糕,写起来、用起来都非常痛苦。所以我觉得,Gradle 带来的痛苦主要就是这种变化,是它为了走到今天而不得不经历的调整。

第 47 章

Huyen: 你做 Android 开发快二十年了。是什么让你没有倦怠?

Jake: 我觉得在这段时间的前半程,Android 本身乃至整个移动领域一直在迅速演进,逐渐成为如今这个我们已经习以为常的样子。因此,仅仅在 Android 内部就有很多学习新东西、尝试新事物的机会。每年 Google I/O 到来时,大家都会为平台的新能力感到兴奋,这种状态支撑了我很长时间。

Jake: 后来我觉得,似乎没人告诉 Apple 和 Google,Android 和 iOS 已经差不多完成了。过去大约十年里推出的每样新东西,带来的感受几乎都反过来了,和现在看到产品更新时一样:你往往先感到害怕——他们这次又要拿走我的什么,又要强迫我做什么?

Jake: 所以我会转向别的东西。我一直在摆弄硬件。能够写一段代码,放到手机上,让别人实际与它交互,而且整个过程又快又真实,这当然非常棒。但硬件又多了一层真实感:它是实体,能触摸,还能以各种方式与现实世界互动,而不只是一块六英寸的像素屏幕。这是我探索的一条路径。

Jake: 与此同时,我也会研究和学习其他语言。有人问我,怎样才能成长,怎样才能更擅长 Android、Kotlin 或其他技术,我给的一条建议就是:真正去学另一门语言。比如我学习 Swift、Rust、Zig 或 C 时,并不需要精通它们;目标不是让自己使用另一门语言时也达到同样熟练的开发水平,而是打开思路,了解做事的不同方式。有些语言甚至更能“重塑你的大脑”。我们刚才谈过 Haskell,它就是另一个很好的例子,真的会教你用不同方式为问题建模。

Jake: 你可能没有意识到,在这个过程中获得的经验,会被你带回日常使用的语言中。遇到一个问题时,你会识别出熟悉的模式:“哦,这和我尝试 Swift 时遇到的东西一样”,或者“这和我写 Zig 时遇到的情况一样;Zig 当时选择用这种方式处理,但我不喜欢,所以这里要确保找到另一种办法。”你会把这些经验带回来。这有点像拓展自己的文化和知识背景,也是大学为什么要求你学习历史、数学、科学等不同课程:它会让你成为更全面的工程师,也让你有机会在某个时刻调用这些知识。

Jake: 这个过程不舒服,但令人兴奋。面对完全未知的东西,我知道学起来会很痛苦,但也会想:已经有成千上万甚至数百万人在使用这些语言,他们都学会了,那你也能做到,只是必须投入精力。然后,我喜欢把学习和自己当下感兴趣的事情结合起来。

Jake: 举个很具体的例子:我家有一套草坪喷灌系统,而我非常讨厌控制它的那台设备。但它实际上不过是一个微控制器加大约二十个继电器,所以我可以买一块硬件,装上自己的软件,自己把控制程序写出来。这就给了我一个理由去学习能在微控制器上运行的语言。我很小的时候接触过一点电子技术,这件事也让我有理由重新学习最基础的电路设计,比如把继电器放到电路板上,再配一块 Raspberry Pi 之类的设备。

Jake: 关键是这件事与我有关:我有完成它的理由,有一种内在动力。如果没有其他理由,我可能不会逼自己学习 Rust 或 Zig,尽管我认为那会有益处。但把学习和另一件本来就能激励我的事情绑在一起,我才能真正取得进展。最终,它也会成为我的一种娱乐:它让我保持投入,然后我又能把学到的东西带回日常工作。

Jake: 我觉得 Android 已经没那么有趣了;它某种意义上已经是一个完成了的操作系统。不过 Kotlin 仍然吸引我。现在我们已经越过 K2 这道坎,库团队和语言团队也明显加快了为语言添加新能力的节奏,这依然令人兴奋。所以,我会寻找与工作多少有些关联的东西。毕竟,编程本来是我的爱好,后来才变成工作。

Jake: 当然,如果有人为了避免倦怠,选择做与编程完全无关的事情,我完全支持。我也完全支持下班之后不再碰电脑。但对我来说,编程仍然能带来快乐。我觉得自己还有很多东西要学,只是现在需要走出日常工作的范围,到外面寻找这种灵感。

第 48 章

Huyen: 你在这里提到了很多编程语言。你觉得每位开发者学习不止一种编程语言都有益吗?

Jake: 肯定应该不止一种。当然,不一定要走到极端,去学五六种语言。但不要把自己完全困在一门语言里,不要把自己局限在唯一精通的语言里——无论那是什么语言。走出去接触其他语言非常有价值。不同编程语言的存在是有原因的。你只需浅尝一下,看看语言设计者做出了哪些选择,以及为什么这样选择;然后像我刚才说的,也许可以把这些思考带回你工作的语言中。这样做肯定没有坏处,我认为只会让你受益。

Jake: 奇妙的是,它会在一些意想不到的时刻发挥作用:你会突然意识到,“这正是那门语言从一开始就要解决的问题。”我们经常谈 Rust。Rust 显然是为了解决 C 和 C++ 中经常出现的许多问题而设计的。但我学习 Rust、研究所有权之类的概念之后,会把“所有权”这个概念带回 Kotlin、Java 和其他每一种语言,因为它实在太基础了:谁负责管理我刚分配的这个对象?把它传给那个函数以后,我还能继续使用它吗?清理资源或关闭连接之类的工作仍然由我负责,还是我已经把所有权转移给了那个函数?

Jake: 很多语言无法对这些关系建模。于是你会开始识别出一些风险:“这里很危险,因为我们表达不了这种关系。这个类、这些函数或者这些参数类型的设计方式有风险,有人可能会误用它。”而误用它的人通常不是现在的你,往往是六个月甚至三年后进来重构代码、却不知道这里存在隐含契约的人。这个例子虽然很具体,但结果可能是他们重构代码库后造成内存泄漏,或者过早关闭连接等问题。

Jake: 所以,你会把这些认识带回 Kotlin,尝试用一种能清楚说明所有权责任、所有权如何转移以及谁拥有什么的方式来建模。这只是一个例子。我认为,几乎任何其他语言都能反过来教你理解自己所用语言里的某些东西。学习 Java 或 Kotlin 时,你通常不会思考我们之前谈到的数据布局,也不会真正思考数据怎样到达正在执行的代码。

Jake: 但当你去用 C、Zig,尤其是 Rust、Swift 或类似语言时,就会看到非常紧凑的数据结构:每一个比特都得到利用,一条缓存行里能装下多个对象。这可能正是那门语言比你所用语言快八倍的原因,因为你的程序还在到处追逐指针,产生大量缓存未命中。其他语言中值得学习的东西多得数不完。所以我才会把学习与另一件能激励自己的事情联系起来,推动自己走出舒适区。我需要一个理由去尝试 Rust、Swift 或其他语言。具体选哪门几乎不重要,不过作为 Kotlin 开发者,我当然不会选 Java;至少应该选一门能给自己带来一点挑战,并有望打开思路、接触原本不会接触到的新事物的语言。

第 49 章

Huyen: 所以,你写 Kotlin 时,脑子里是不是有一个小型的借用检查器?

Jake: 我有一张梦想项目清单:假如哪天我还能照常领薪水,却不需要承担任何工作职责,我就会去做这些项目。其中一个基本上就是尝试把所有权引入 Kotlin。今年的 KotlinConf 上,有位研究人员提出了一个非常早期的设想;它甚至还算不上 KEEP,基本只是一些笔记,描述了把所有权语义引入 Kotlin 语言可能是什么样子。

Huyen: 带生命周期的 Kotlin。

Jake: 对。这种东西很有意思:一旦你看到了它,在某个瞬间真正理解了它,或者回想起那些本可以通过显式所有权避免的 bug,就会觉得它本该成为语言里明确表达的一部分。

Jake: Java 里有一种常见模式:别人给你一个列表时,你会做一次防御性复制,因为 Java 中所有列表都是可变的。有人把列表交给我,我不知道他会不会马上又往里面追加一个元素,所以收到列表时先复制一份,以避免这种情况。所有权可以消除这一整类问题。Kotlin 通过区分可变列表和只读列表,在这方面有一点帮助,但还没有完全解决。真正的所有权意味着:你把列表交给我,此后你就不能再碰它;或者你允许我借用列表,而我知道你仍有能力修改它。看清这些概念之后,你就会开始发现它们无处不在。

第 50 章

Huyen: 我们已经谈了你的开源工作。如今 Kotlin 在开源生态系统中的规模有多大?

Jake: Kotlin 有一个非常好的地方,就是我们可以利用 Java 的开源生态,Java 也可以反过来利用 Kotlin 的生态。我们把 Okio 和 OkHttp 之类的库用 Kotlin 重写时,确实有一部分人很不满。

Jake: 重写过程中,我们保持了严格的二进制兼容性。所以,如果有人通过传递依赖拿到了新版 OkHttp,或者只是有人升级了版本,无论如何,你的代码都应该继续工作:仍然能够编译、链接,并在运行时正常执行。当然,它确实会多出一个依赖,也就是 Kotlin 标准库,因此有些纯粹主义者对此颇有意见。

Jake: 对我来说,很难把 Java 开源生态和 Kotlin 开源生态截然分开。这其实要从语言的文化谈起:Kotlin 语言完全开源,整个开发过程也完全公开,你可以看到语言如何随时间演变。一个很容易想到的对比是 Swift。它过去更像是 Apple 的开发者每年把一个精雕细琢的成品交到你手里:“这是今年的新版本。”当然,如今 Swift 的很多开发工作已经转向公开,他们正在修正早期的方向。但最初,他们很排斥围绕语言建立这种开源社区的想法。

Jake: Objective-C 和 Swift 当然也有一些开源库,但远远不像 Kotlin。Kotlin 一旦能够用于 Android,就立刻涌现出大量用 Kotlin 编写的开源库。Kotlin 真正具备成熟的多平台能力后,大家又开始成批开发多平台库,满足编写多平台代码时那些非常基本的需求。

Jake: 我确实认为,这首先源自 JetBrains 以及他们管理这门语言的方式,也源自语言发展初期形成的氛围。最早加入的人在某种程度上会制定后来所有人共同遵循的不成文规则。如果一开始就形成公开协作的文化,这个循环就会不断自我延续。反过来,如果一个社区的文化是,这门语言只用于非常严肃的商业场景,使用者严密保护自身利益和知识产权,什么都不开源,那么这种特征也会反映在整个社区中。

Jake: Kotlin 所进入的领域原本就有大量开源实践,而 JetBrains 也选择把一切公开进行,两者彼此强化。因此,我不认为 Kotlin 是规模最大的开源生态,但它肯定属于较大的生态之一。

第 51 章

Huyen: 对开源来说,依赖似乎非常重要。你刚才也提到了依赖:你会依赖另一个库,但也有人认为,让项目依赖他人成果这件事有点吓人,比如可能存在安全问题。我记得就在最近,你刚才提到的 Ghostty,其作者写过自己的做法:每当他需要一个依赖时,就直接把它 fork 一份。

Jake: 对,然后永远不更新,因为他需要的就只有那些东西。

Jake: 这件事肯定有正反两面,有优势也有劣势。在别人已有工作的基础上继续构建,可以获得很多好处;但显然也可能失去很多。你实际上会受制于那个库,具体取决于你如何集成它。当维护者做出的决定不符合你对这个库发展方向的预期时,你可能会觉得自己遭到了背叛;他们也可能突然“釜底抽薪”,例如更换许可证,试图让项目本身能够持续运转。可对一直免费使用它的你来说,这件事或许从未进入过考虑范围。

我认为,问题还是源于人们对“使用开源库究竟意味着什么”的误解。你需要对它抱有责任感,把那部分代码视为与自己每天编写的代码完全相同的东西。因为最终所有这些代码都会被打包、发布给你的用户——也就是使用你产品或服务的人。他们并不关心你用了哪些库。有效地使用开源库,能让你更快地交付产品;但如果你也对那些代码负责,就会开始像对待自己日常编写的代码一样对待它们。

有一种观念是:“我得先获得许可,才能在工作时间为开源库做贡献。”这在我看来很不合理。因为如果不用那个开源库,你就得自己写出实现相同功能的代码,并对它负责;需要修改时,你也会直接修改。既然这个开源库会随你的应用一起发布,那么想改它时就去贡献代码好了。

这应该成为常态:因为它是你的依赖项,所以你对它有一定的主人翁意识;你应该像关注自己的代码库一样,关注这个项目发生了什么。当然,依赖项的分发机制会让这件事变得困难:只要在构建文件里加一行,所有东西就会自动下载下来,于是它感觉离你非常遥远。你显然从中获得了很多好处,可一旦踩坑,又会觉得是开源项目的错,怪他们没有理解你的需求。

但如果你把它当成自己有责任参与、维护和关注的事情,并确保它朝着你希望的方向发展,那么即使项目要走向你不赞同的方向、做出不符合你需求的改动,你也能提前看到。你可以预先规划,逐步应对;也有机会阻止或改变它,或者帮助开源项目找到一个既适合你、又能实现作者目标的方向。

最近还有人问我:如果 LLM 能直接生成代码库里那些乏味、重复、基础性的部分,让人只需专注于业务逻辑,我们还需要库吗?这种说法低估了共享同一份代码所带来的价值。也许有人修复了一个奇怪的 bug,你现在乃至过去都没有遇到它,但两年后的一次重构原本会触发这个 bug;因为你使用的是开源版本,它早已被修好了。又或者,有人把某个东西的性能提高了 15%,于是你代码库里的那部分也随之快了 15%。贡献可以通过这种方式分发到所有不同的代码库里。

所以,如果你既关注开源库带来的优势,又像对待自己日常维护的代码那样对待它们,那么面对它们随时间演进这件事,就会容易得多。

第 52 章

Huyen: 你曾经以开源为本职工作。通常是什么促使公司投资开源软件?

Jake: 开源带来的收益很难用一种适合填进电子表格的方式量化,因为它确实会增加工作量。额外的工作不算特别多,但也绝非微不足道。假设一个库已经存在,边界也比较清晰,相对独立;可正如我们刚才所说,文档通常没那么完善,测试覆盖率也可能不够。你还得搭建发布基础设施,并持续处理外部贡献和 issue。

不过,理论上你也会免费获得别人对代码库的改进。开源还会影响外界对公司工程文化的看法。人们可以查看一家公司发布的开源代码,然后根据你放出来的东西说:“哇,质量真高。”当然,也可能觉得质量很低——但我们希望是前者。它也可能带来人才。Google、Facebook 等公司曾经发布大量开源项目,人们能看到那里正在构建的酷东西,因此吸引到了很多人;至于今天是不是仍然如此,就得看具体公司了。

除此之外,作为工程师,能向别人展示自己做的东西,而不只是口头描述,感觉会很好。你可以说:“我做了个特别棒的东西,它能让人以一种新颖有趣的方式使用这项技术。哦,对了,它在公司的内部代码库里,我必须用公司配发的笔记本电脑进行双因素认证才能访问。”也可以直接说:“它就在 GitHub 上,去看看吧,研究一下你能怎么用它,或者能否基于它做出别的东西。”后者会带来一种兴奋感。

对工程师来说,能够这样做很有吸引力,但它并不适合所有人,也不应该强迫大家参与。我们刚才谈到个人价值观,比如希望加入一家做开源的公司;但公司不该为了让自己的工程团队看起来很厉害,就说“我们必须把这些东西开源”。这种方式是错的,会显得很虚伪。即使人们说不清原因,也往往能感受到这一点。

通常你会自然地遇到某样东西,然后意识到:“这是个很不错的可复用组件,别人也能从中受益。”也许它太过专用,别人实际用不上,但公开它对你没有任何损害,还能展示我们正在做的酷东西。对那些喜欢寻找这类成果、也乐于谈论自己工作的人来说,这会增加不少幸福感。

当然,也有人不想参与。他们不想公开露面,不想经营 GitHub 上的公开身份,也不想承担处理这类 issue 的责任和负担:“嘿,你把我们的应用弄坏了。你删掉了这个功能,做了这件事,所以我不喜欢你。”他们也不想处理一大堆 LLM 生成的低质量 PR,或者应付那些想把库带向自己并不认同的方向的人。这样的沟通很困难,因为它归根结底是人与人之间如何交流的问题。开源还会遇到很多语言障碍,因为你面对的是全世界,而不再只是身边的人。

不过,确实有一类人觉得这些事情有趣、好玩,而且能从中获得动力。再自私一点说,如果你在一家公司开源了很多东西,那么离职后还能在下一家公司继续使用。我自己的经历就是如此:凡是我构建并成功开源的东西,都不必留在前一家公司;到了下一站,我仍然能继续使用全部或部分成果。

第 53 章

Huyen: 很多人认为开源主要就是无偿的志愿劳动。现代开源软件里,究竟有多少是由公司出资或通过合同资助的?

Jake: 这里显然分成几个类别。我认为,如今很多开源工作实际上都得到了公司的间接资助,因为公司会直接全职雇用维护项目的人。我供职过的公司组织名下那些库,基本都是这样产生的:我在工作时间维护它们。即使有人提交的功能请求或 bug 与我们自己的代码库毫无关系,我仍然会在工作时间处理,我认为这没有问题。

麻烦通常出现在另一类情况:这是我业余做的个人项目,不适合放到公司名下,或者与公司的业务无关,后来却成了别人的代码库中不可或缺的关键依赖。我会出于刚才谈到的所有原因公开它:我喜欢展示自己的工作,而不是只靠口述;我也希望别人能在它的基础上发挥,甚至让它产生很大的价值。

但项目附带了许可证。以标准的 Apache License 为例,几乎所有许可证都会写明类似的内容:你和我之间没有合同关系;对于这份代码,无论明示还是默示,我都没有作出任何保证。问题是,我们没有很好地区分“我在业余时间随手做完并公开的项目”和“我在公司里构建并正式发布的库”。当问题发生在个人仓库里时,你可能是唯一的维护者,可能不堪重负;也可能在离开公司后,项目就无人维护了。

对于那些已经依赖项目的公司该如何帮助它恢复到健康状态,我们还没有一个好模式。他们可以出钱,但贡献并不一定非得是金钱。这又回到了我前面所说的参与开源:跑到一个你正在使用的库里提 issue,只说“我希望这个库增加某项功能”,与说“我想增加这项功能,我可以来实现吗?你们愿意接受这份贡献吗?”完全是两回事。然后你可以亲自完成开发;即使最终由维护者来做,你也仍然可以帮忙修 bug、分流和整理 issue。这同样是一种投入:你贡献了时间和工程投入,接手开源项目固有的部分基础工作,减轻了你所依赖的代码作者的负担,让他有余力完成你希望他做的事情。

当然,我非常希望我们能找到一种直接让开源开发者获得报酬的办法。有些被超大型公司使用的项目,基本上是由一个人构建的,只因为这个人对它充满热情。能有这种热情并构建出这样的项目当然很棒;当你在应用所使用的开源库名单中看到自己的名字,或者有人在会议上走过来聊他们如何使用你开发的库,那种感觉也非常好。

但除此之外,你并没有真正得到什么。你知道还有什么会让人感觉很好吗?因为这些使用量,我银行账户里的数字也能增加,而且我能把它当成一件可持续的工作。否则,我只能挤出业余时间,甚至试着从日常工作里“偷”出一点时间,去维护别人依赖且喜欢的东西。到最后,我对它感受到的就不再是兴奋,而是义务。

第 54 章

Huyen: Kotlin 的创造者 Andrey Breslav 在 2020 年离开了 JetBrains。一门语言能在没有最初创造者的情况下继续演进吗?

Jake: 我认为,一门语言必须能在最初的创造者离开后继续发展;一个人停止维护某样东西、转而去做其他事情,也完全没有问题。如果你构建的东西取得了成功,而你像他一样投入了十年的人生,然后觉得:“它现在很棒,但我想去做点别的。”那你就应该去做。

我们很幸运,Kotlin 平稳地经历了这件事——其实根本没有引发任何风波。恰恰相反,这证明了围绕这门语言建立起来的体系足够健全。我认为这对一门语言来说是健康的。你会发现,如今几乎所有大型、成功的语言都不再由一位“仁慈独裁者”掌控,而是由某种共享的组织结构来管理,并且最好能与社区协同。

Huyen: 我觉得 Zig 是目前唯一一个仍然由这种角色主导的例子。

Jake: 但它仍然很年轻,对吧?由 Andrew Kelley 直接说“我们要引入一种新的 I/O 概念,把 I/O 从隐式依赖变成显式依赖,因此要对整个代码库中的每个 API 作出破坏性修改;你们将不得不重写 100% 的代码,但这是这门语言所需要的”,会带来非常大的好处。

我记得 Zig 是由一个基金会持有的。Andrew Kelley 谈过 1.0;我希望当语言到达 1.0 时,这份责任能更多地由大家共同承担。哪怕只是为了减轻他的负担——我猜,为了把语言推进到 1.0,他需要付出极其艰巨的努力。他当然仍然可以参与,也可以继续做最终决策者;但把这份工作分担出去,只会让语言的未来更加稳定,因为你永远不知道会发生什么,也不知道人们什么时候愿意参与、什么时候选择离开。

第 55 章

Huyen: 你本人影响过 Kotlin 吗?比如影响过某项具体功能或决策?

Jake: 我愿意相信自己曾在几件事上稍微推了一把。其中一件最让我兴奋、也曾让我觉得绝不可能实现的事,是默认对 when 进行穷尽性检查,也就是说,你必须涵盖所有可能的分支。

这同样是你会在其他语言里看到的特性;体验过之后,你会觉得它很合理。如果我给密封接口添加了一个新的子类,或者给枚举增加了一个新变体,我希望编译器能指出所有没有正确处理它的地方。否则,代码可能落入某个分支,产生意外行为,或者直接抛出异常。

我们在 Square 时构建过一个编译器插件和工具,用来强制检查 when 是否穷尽。我原以为这个特性永远不会正式进入 Kotlin。后来我在 Google 时,Kotlin 的领导工作正从 Andrey Breslav 交给 Roman Elizarov。我记得自己和 Roman 谈过这件事,他说:“对,我觉得这是我们会去做的事情。”我的反应是:“太好了,拜托一定要做。”

当然,并没有任何语言特性可以直接归功于我。不过,让我一直留在 Kotlin 生态的一大原因,是他们多年来关于哪些东西应该加入语言、哪些不该加入的许多决定,都符合我对编程语言的价值取向:我希望语言替我做什么、不替我做什么,以及哪些责任应该留给程序员。

关于错误和异常有一份提案,已经提出一两年了;就在我们录制这期节目时,它刚刚得到更新。我希望它能继续推进,也希望自己能针对它提供一些有用的意见。我也鼓励其他人这样做。

毕竟,你们的代码库几乎全是闭源的,语言设计者看不到。你使用 Kotlin 的方式、采用的设计模式以及构建的东西,很多时候只需对语言做一点调整,就能变得更容易。但如果他们看不到这些,而你也不参与讨论、不去告诉语言团队你希望 Kotlin 为你提供什么,那就相当于放开缰绳,任由别人控制方向。

所以,我做的其实只有这些,我也鼓励其他人这样做:新提案出来时去读一读;看看 KotlinConf 上有关语言演进的演讲;KotlinLang Slack 里也有一些频道,会讨论语言未来的功能和方向。你只需要稍微参与一下,偶尔留一条只有一行的评论,说赞成或反对,再解释为什么。这样一来,你也在帮助塑造这门语言。

第 56 章

Huyen: 2026 年究竟是谁在掌舵 Kotlin——JetBrains、Google,还是社区?

Jake: 应该是三方共同掌舵。把 Kotlin 从 JetBrains 转移到 Kotlin Foundation,部分目的正是如此。基金会的组织结构使任何一方都无法独自掌控它。我的意思是,社区并没有基金会的正式成员席位,但我们的人数显然远远超过 JetBrains 和 Google 的员工。

如果他们称职,就既会倾听社区里的声音,也会把数量极其庞大的反馈梳理成可以消化的内容,从而推动语言前进。

这种安排也源于我们刚才谈到的 Google 采用 Kotlin 的经历。Google 已经用过一门由另一家公司拥有的语言,并为此卷入过一场大型诉讼。因此,如果要采用一门新语言,它就不能由另一家公司独自拥有,让对方将来可能反过来做出最终伤害 Google 的事情。所以,如果整个机制运作正常——而我认为现在确实如此——答案就是以上三方:JetBrains、Google 和社区。

第 57 章

Huyen: 如果 Kotlin 消失了,这个世界会失去什么?

Jake: 我认为那会是很大的损失,但我也认为,编程语言没有必要永远存在。我并不是说 Kotlin 应该很快消失;只是它不必无限膨胀,把每一种可能的使用场景都囊括进来。我们之所以拥有不同的编程语言,自然有其原因。如果有一天,编程发生了某种根本性的变化,以至于 Kotlin 不再适合,那也可以接受。

Huyen: 那对你个人来说,你会失去什么?

Jake: 我很可能会失去在任何地方找到工作的能力。我对其他任何语言都不够精通,恐怕没法真正靠它们挣钱。我算是把所有鸡蛋都放进 Kotlin 这一个篮子里了。

不过,我很高兴自己把全部努力都投入 Kotlin,把它当成与自己紧密绑定的东西。所以,请千万别让它消失。

第 58 章:如何评价 Jake 的观点——AI 原理、批判性思维与维特根斯坦

本章为阅读全文后补充的评论,不属于访谈原文。评价对象是论据和推论,而非 Jake 的人格;关于发言语境的判断以本文中文稿为依据。资料核对日期:2026 年 9 月 11 日;研究结果均保留其时间与适用范围。

Jake 关于长期维护、显式约束和开发者责任的论述值得重视;关于模型能力上限及行业必然走向的若干推论,则需要纠正或补充证据。 以下逐条区分事实错误、推论不成立、证据不足和价值取舍,并保留各项观点在访谈中的适用语境。

58.1 先区分事实、预测与价值选择

“Java 的所有列表都可变”是可以用反例检验的事实命题;“AI 成本一定上涨两个数量级”是需要条件、期限和数据的预测;“我愿意降薪,以避免为不认同的公司工作”则是价值选择。这三类话不能使用同一把尺子。个人择业原则可以讨论一致性和代价,但无须证明它适合所有人;技术治理的判断则需要考察实际权力与制度安排。要批评某个观点存在偏见或过度泛化,需要指出它在何处把特定经历或偏好当成了足以概括全局的依据,不能仅凭一个人有明确偏好就作出判断。

阅读全文尤其要避免两个误读。第 1 章“把工程师的工作都交给 LLM”是剪辑式开场,第 28 章才给出完整语境:Jake 正在批评这种做法。第 12 章“不要 AI”的口号,也必须结合第 262830 章理解:他认可可选而恰当的 LLM 功能,承认辅助编程和机械修改的价值。因此,对他立场较公平的概括是:反对强制使用、过度依赖和无人负责的交付,同时保留自己拒绝使用的权利。

不过,这种善意理解不能抹掉他确实作出的强断言。第 29 章关于“不能推理”和“必然坍塌”的说法,仍须按技术命题接受检验。

58.2 从 AI 底层原理看:概率生成意味着什么

这里讨论的是文章中的大语言模型,不把所有 AI 技术都归为同一类。以常见的自回归 Transformer 语言模型为例,文本先被切分成 token,转换为向量,再通过注意力机制等神经网络运算结合上下文,计算下一个 token 的概率分布。预训练通过调整参数,让训练文本中的后续 token 获得更高概率;生成时则按一定的解码规则逐步选择 token。Transformer 原始论文Llama 3 技术报告

它不是逐条查询原句的数据库,但训练可能造成对具体文本的记忆;研究者确实从语言模型中提取出过训练原文。因此,不能把所有生成都叫作复制,也不能声称模型绝不会复现原文。训练数据提取研究

因此,“下一段代码很像合理答案”与“代码满足业务约束”之间没有自动成立的等号。模型可以给出形式完整、解释流畅,却调用了不存在 API 或遗漏边界条件的实现。生成目标不是程序正确性的证明义务,这是 Jake 对责任问题保持警觉的技术基础。

但只描述预训练也不完整。模型还可以经过指令微调和强化学习;例如 DeepSeek-R1 的研究在数学和代码等任务中使用可检验结果作为奖励,报告了相应能力的改善。DeepSeek-R1 论文

部署后的系统还可以把模型与外部工具连接起来,交替生成行动、读取环境反馈并调整方案。在编程中,这种方式可以用于读取文件、编译和测试。因此,评价一个裸模型的一次回答,与评价包含工具和验证步骤的完整系统,应当区分。ReAct 研究

同样要区分“训练改变参数”与“推理时读取上下文”。把新代码、文档或测试结果提供给模型,并不要求它当场重新训练,也不代表它已经永久学会这些内容。第 29 章用“2022 年以前的人类成果”概括模型的信息来源,不能当成所有模型和系统共有的信息上限。例如,Llama 3 技术报告就说明其预训练数据的知识截止时间为 2023 年末。Llama 3 的预训练数据说明

这些机制既不保证模型总能推理正确,也没有证明模型只能复述过去。是否能够在未见任务上运用规则、处理新约束,必须通过实际表现检验;是否具有人的主观体验,是另一个尚不能由这些工程测试裁决的问题。

58.3 哪些观点是正确的,值得保留

第一,写出代码的速度不能代表软件的整体生产率。 第 30 章是全文最有说服力的部分之一。需求是否正确、边界如何划分、出了故障能否定位、几年后能否安全修改,都不会因为初稿生成得更快而自动解决。AI 可以减少某些成本,也可能把成本转移到审查与返工。合理的比较单位应是“完成并验证一个可维护的变更”,而非 token、代码行数或 PR 数量。

第二,类型系统和显式契约的价值不会被 AI 消除。32354548 章反复讨论可空性、错误传播和所有权。这些机制能把部分约束交给编译器检查,让后来修改代码的人不必全靠猜测。AI 生成的代码同样受益于这些约束。不过,类型检查只能覆盖已经表达出来的性质;程序通过编译,并不意味着业务逻辑、性能或所有异常路径都正确。

第三,生成代码不等于接管责任。 第 28 章反对让人发布自己无法判断的结果,这个原则成立。它同样适用于复制论坛答案、引入第三方库和接受同事的代码。真正的问题是交付团队是否有能力确认需求、发现错误并维护系统。责任可以由团队和流程共同承担,无须假定每个人都能独立重写全部依赖。

第四,AI 能重写功能,并不意味着开源库失去价值。515253 章抓住了“共享实现”与“各自拥有一份实现”的差别:共享库能够汇集不同用户遇到的边界情况,并分发修复、性能改进和兼容性经验。重复生成同类代码,未必获得同样的维护网络。反过来,使用库也不自动收到所有修复,还需要关注版本、及时升级并验证兼容性;小而稳定的功能是否值得引入依赖,仍应具体判断。

第五,保持退出能力和劳动边界是合理的工程与职业目标。142328 章提醒我们,不能只问工具是否好用,还要问成本变化、服务中断或人员离开后能否继续工作。第 363738394041 章关于尊重平台、逐步共享、减少框架绑定的讨论,与这种思路一致。尤其第 40 章主动说明 Redwood 依赖既有设计系统,并不适合所有新项目,体现了较好的边界意识。

58.4 哪些观点错误,哪些只是证据不足

1. “底层是统计,所以不能推理”:推论不成立。

第 29 章把实现机制与能力判断混在一起。概率方法可以用于搜索、决策和推断;采用统计学习,并不能单独证明一个系统无法完成具有推理要求的任务。反过来,某次答案正确也不足以证明系统掌握了稳定、可迁移的推理方法。需要检查它在新题目、改写后的约束、反例和分布变化下是否仍然可靠。

“不能保证百分之百正确”也不能推出“不会超过人类”。人类同样会出错,公平比较应看相同任务和验证条件下的表现。还应区分生成过程的不确定性与生成后程序的执行行为:概率生成的代码可以是确定性程序,确定性生成也可能稳定地产生错误。Jake 关于必须验证的结论正确,但用“统计”证明能力天花板,理由不成立。

2. “用模型输出训练模型,必然坍塌”:把有条件的结论绝对化。

模型坍塌是实际研究的问题。例如,反复用生成数据替代原始数据进行训练,可能逐代丢失低概率模式、放大误差,让分布失真。但这与“任何合成数据训练都必然失败”不是同一个命题。相关研究也专门比较了数据替代与保留真实数据、持续累积数据等不同设置,说明数据如何进入训练过程非常重要。模型坍塌研究数据累积条件下的研究

如果代码候选经过独立测试、数学解答经过验证,反馈来源就不只是模型对自己的认可。这些方法仍有验证器不完整、奖励被钻空子等风险,但已经足以说明:不能从一种封闭循环的退化,推导出所有后续训练都不可持续。这类坍塌实验也不足以判定未来创新必须采取哪一种人机分工。人类提供新问题、反馈或部分原创工作,可以与模型生成和工具验证结合。

3. 软件质量:需要区分对具体采用方式的批评与对 AI 的普遍判断。

第 12 章对 LLM 的长期质量收益作了较宽泛的否定,但访谈没有提供足以覆盖不同模型、任务、团队和维护周期的证据。第 28 章则有明确语境:企业大量裁员,让剩余人员承担更多工作,并让不充分理解代码的人生成 PR。他所预测的质量下降,针对的是这套组织决策及其采用 AI 的方式。

如果企业因为期待 AI 替代工程师而裁员,知识流失和维护能力下降就可能是这项决策的后果,评价时必须纳入。要研究模型本身的效果,需要区分人员、流程等因素;要评价整套采用决策,则需要考察这些因素共同造成的结果。因此,不能用“质量下降也可能来自裁员”来排除这套决策的风险,也不能把这种风险推广成所有 AI 用法共有的后果。

任务速度研究也呈现不同结果:2023 年一项包含厂商关联研究者的实验,在指定的 JavaScript HTTP 服务器任务上观察到 Copilot 使用组更快;METR 2025 年针对 16 位熟悉成熟开源仓库的开发者进行实验,却发现使用当时的 AI 工具平均慢了 19%。两者的任务和条件不同,都不能直接代表多年维护质量。METR 在 2026 年更新中还指出,后续实验受到选择效应和计时困难影响,无法可靠估计当时的加速幅度。2023 年实验METR 2025 年实验METR 2026 年更新

Jake 对削减验证和维护能力的采用方式提出警告,有合理依据;实际后果及其严重程度,仍需结合具体案例检验。他在第 28 章把质量下降说成必然,确定性过强,但这不削弱保留维护能力的必要性。访谈也不足以证明 AI 在不同组织和用法中都会使质量下降。判断时至少应同时看交付耗时、线上缺陷、审查返工和后续修改成本。

4. 使用成本上涨:计费变化已有实例,行业性暴涨的幅度和必然性仍缺证据。

第 28 章担忧的是:开发者和企业形成依赖后,是否还能负担维持现有工作方式的费用。这个问题需要考察套餐权益、调用量、模型选择和迁移成本,单看每个 token 的价格不足以回答。

这一担忧已有具体的计费变化作为依据。GitHub 在 2026 年 4 月 27 日的公告中表示,过去承担了部分不断增加的推理成本,原有按请求计费的方式已不可持续;6 月 1 日,Copilot 开始实施基于 token 消耗的 AI Credits 计费。这为“原先由供应商承担的部分费用可能转移给用户”提供了具体支持,但实际账单如何变化仍取决于使用情况。访谈中的个别账单数额及其使用条件,也需要独立核实。GitHub 的计费调整说明2026 年 6 月 1 日实施公告

另一方面,Stanford 的 2025 AI Index 记录:2022 年 11 月至 2024 年 10 月,达到特定 MMLU 成绩水平的模型,其每百万 token 调用价格下降超过 280 倍。这说明在这一基准所衡量的能力水平上,调用价格曾显著下降;它与用户因套餐权益改变而面临账单上涨可以同时成立,也不能直接代表同等编程能力或整个维护周期的成本。Stanford AI Index 2025

因此,成本转移和依赖风险应当认真对待;从这些实例进一步断言全行业的使用成本必定上涨十倍、百倍,或认定所有厂商都在执行同一种商业剧本,仍缺少依据。完整的成本比较还应包括集成运维、人工审查、返工与故障损失。更换服务、调整任务或部署其他模型可能提供退出路径,但切换也有成本,需要事先评估。

5. 责任边界:需要区分能力成长与无法脱离工具的依赖。

第 28 章把“如果没有 LLM,你根本做不成那件事”作为不负责任用法的判断依据,紧接着追问工具涨价后,开发者是否还能继续工作。这一语境的重点是依赖程度和退出能力。第 4748 章又明确鼓励学习陌生语言,因此不能把这句话直接解释为禁止借助工具突破原有能力的学习禁令。

不过,这句划界仍然过于宽泛,没有充分区分“借助 AI 逐步获得新能力”与“持续依赖自己无法理解、维护的产出”。一个人起初不会某种语言或算法,可以通过文档、实验、专家审查和测试逐步学会。责任判断应结合任务风险,考察交付时团队是否能够理解关键决策、验证结果和维护系统,以及工具不可用时是否有可行的替代方案。起点能力不足不等于交付时仍无能力负责,任务完成也不等于已经掌握了所需能力。

学习损失的风险也不能忽略。Anthropic 在 2026 年公布的一项小型随机实验中,让开发者学习陌生的 Trio 库,AI 辅助组在随后的即时测验中得分较低。这支持了“完成任务与掌握技能不是一回事”,但不能外推为所有 AI 辅助学习都无效,也没有证明某一种提问方法必然避免损失。AI 辅助与编程技能研究

6. 版权批评有合理关切,但事实与法律表述需要分开。

第 13 章强调“可以访问不等于可以任意使用”,这一点值得重视;创作者是否同意、是否得到回报,也不会因为模型有用就失去意义。但“整类技术建立在已经成立的版权侵权之上”过于笼统。美国版权局在 2025 年关于训练的报告预发布版本中明确区分了可能构成与可能不构成合理使用的情形;这是一份政策分析,不能冒充对所有模型的统一判决。美国版权局训练报告

Aaron Swartz 的类比也存在具体错误:美国司法部 2011 年列出的起诉罪名是电信欺诈、计算机欺诈等,并非文中所说的版权侵权指控。这不消除对起诉是否过度的质疑,但两个事件不能被当成法律事实完全相同的案例。当年的起诉公告

AI 之外,文中也有几处可以明确纠正的技术表述:

原文位置与说法 判断与修正
第 49 章:Java 中所有列表都是可变的。 错误。 List.ofList.copyOf 可以返回不可修改列表。真正的问题是 List 类型没有完整表达所有权;列表不可修改也不代表元素对象不可变。Java 文档
第 38 章:Flutter 只编译成原生代码。 错误。 Flutter 的 Web 目标可以使用 JavaScript 或 WebAssembly。编译目标与是否使用平台原生控件,应分别讨论。Flutter 架构文档
第 32 章:加一个问号,就能彻底消除一类 bug。 缺少边界。 空安全能排除大量错误,但 !!、Java 互操作和初始化问题等仍可能造成空指针异常。Kotlin 空安全文档
第 38 章:KMP 融入目标平台,不像其他方案那样隔离。 优势存在,不能扩大为没有互操作成本。 Kotlin/Native 的垃圾回收与 Swift/Objective-C 的 ARC 仍需协调,同一进程不等于相同的对象生命周期。Kotlin 与 ARC 的集成

这些修正并不否定他关于所有权、类型系统和平台适配的主要洞察,却提醒读者:资深工程师的口头概括,同样可能超出事实边界。

58.5 经验、偏好与治理判断的适用范围

维护者经验提供了重要依据,但不同任务仍需分别评估。 Jake 长期维护基础库,尤其熟悉兼容性、长期契约和低质量贡献的代价,因此对代码数量增长保持怀疑很有理由。一次性脚本、学习实验、原型验证与长期公共 API 的收益和风险不同,读者应用这些经验时需要重新评估。第 2630 章已经认可恰当的 LLM 功能和机械修改的价值,不能把他写成始终将所有使用场景一概而论的人。需要补充证据的是第 1229 章中的宽泛效果判断和能力断言。他在第 28 章承认从未使用编程智能体,这限制了可供他直接援引的使用经验,但不影响他作出伦理选择的权利。

自主权问题与工具效果需要分别讨论。1428 章把自下而上的技术采用与管理层推动 AI 对照起来,揭示了自主权问题。即使某种工具有效,员工仍可反对被强制要求使用它;这种反对本身不构成技术判断上的偏见。但要进一步判断工具是否有效、是否适合某项业务,就需要检验实际表现,推广者是 CEO 还是工程师都不足以决定答案。同样,对某位高管或公司的不信任可以解释择业选择,却不能单独作为其技术判断错误的证据。

原生平台偏好是明确的价值排序,需要结合产品目标取舍。383940 章重视平台内部的交互一致性,这是有理由的选择。Jake 也承认 Flutter 可以做出优秀应用、Redwood 未必适合新项目,这些限定应当保留。仅仅给原生体验较高权重,不足以认定他存在偏见。不过,“我能认出这是 Flutter 应用”仍不足以单独证明用户完成任务更困难;若要据此评价具体产品,还应比较无障碍、响应速度、稳定性、团队能力和交付成本。采用不同权重的团队,可能作出同样合理的其他选择。

治理愿景需要与正式权力区分。 第 56 章说三方“应该”共同掌舵,也明确承认社区没有正式成员席位。但他随后以社区人数更多来说明其作用,这不足以证明社区具有相应决策权。基金会官方结构区分董事会、首席语言设计师和语言委员会的职责,包括任命与否决不兼容变更等机制;提出意见、被倾听、拥有正式权力,是三种不同的参与。健康治理需要看这些机制如何运作,不能只看参与人数。Kotlin Foundation 组织结构

全文也包含明确的边界说明:第 1529 章承认自己的经济条件使强硬择业成为可能;第 34 章赞扬 Swift;第 3640 章承认 Kotlin 和 Redwood 的适用范围;第 45 章直接指出自己的库作者视角。评价时应同时考虑这些限定。职业经历可以帮助解释他的关注点,但不能代替对具体论点的检验,也不能要求他的个人择业原则成为所有人的共同标准。

58.6 用维特根斯坦重新整理这些争论

这里借用的是后期维特根斯坦澄清概念的方法,不是声称他预先回答了今天的 AI 问题。《哲学研究》§23 把语言放回活动之中;§43 把许多、但并非所有情形下词语的意义与使用联系起来。因此,“AI 会不会理解”“什么是更好的语言”,需要先明确这些词在具体场景中的判定方式。《哲学研究》相关原文斯坦福哲学百科的说明

以本文为例,“会编程”可能指生成一个函数、修改陌生项目、应对需求变化,或者长期承担产品责任。这些能力相关,却不等同。若只用“能生成函数”证明工程师可以全部替换,论证跨越了能力层级;若只用“没有人的主观体验”否定所有程序推理表现,同样没有检验具体能力。第 29 章需要拆开这些问题,而不是让“智能”这个词一次承担全部答案。

“原生”也有多种用法:编译成机器码、直接调用系统 API、使用平台控件、让用户感到熟悉。这些性质并不总是一起出现。比较 KMP、Flutter 和 React Native 时,分别说明这些性质,可以避免比较途中更换标准。同样,第 34 章谈“Swift 比 Kotlin 更好”时,已经区分了语言本身的设计与库生态、工具体验,这一限定应当保留。若进一步把这种比较用于项目选型,还需要明确目标平台、团队经验和产品约束。

规则遵循则提供了另一个切入点。《哲学研究》§202 区分遵循规则与自认为遵循规则,并强调实践。将这一点用于软件工程,可以得到一个有用的提醒:模型说“这个实现正确”,或者工程师确信自己理解了需求,都不能自行担保结果;需要能区分正确与错误的检验方式。McDowell 对规则遵循的讨论

例如,一个生成的转账函数可能语法正确、测试通过,却没有处理重试导致的重复扣款。它是否正确,要回到需求、交易语义、失败场景和真实使用中检验。人写的函数也应接受同样检验;多人赞同或测试全部通过,也不代表已经穷尽需求。这是本文对哲学方法的工程引申,不是维特根斯坦提出过的软件验证定理。

从这个角度看,第 30515253 章很有价值:代码的可靠性与意义,离不开使用、修复、协作和持续维护。AI 可以参与这些活动,但“能够生成代码”本身不能替代整套实践。与此同时,社区参与也不能被当作模型必定无法理解的证明;它告诉我们应到哪里检验能力与责任,而不是提前宣布答案。

58.7 给读者的最终判断

Jake 对长期维护、显式约束、独立判断和开源责任的坚持值得重视。他对统计机制和模型坍塌的过度推导,以及若干具体技术事实,需要纠正。 计费变化已经为成本转移的担忧提供了实例;削减验证和维护能力的采用方式,也值得警惕。这些依据仍不足以证明全行业成本必定上涨十倍、百倍,或所有 AI 用法都会使质量下降。原生平台偏好和择业标准应结合个人与项目目标讨论;治理愿景则需要通过实际权力与制度安排检验。

这篇访谈最适合被读作一位经验丰富的工程师对技术采用提出的追问。读者既可以接受他的责任标准,也可以拒绝没有充分证据的能力断言。更扎实的立场是:让 AI 的能力接受真实任务检验,让产出接受独立验证,让成本按整个维护周期计算,并让采用技术的人保有选择和退出的空间。




Enjoy Reading This Article?

Here are some more articles you might like to read next:

  • 确定性陷阱:保持生活的弹性
  • 从 LLVM 到 Mojo:Chris Lattner 谈 AI 时代的编程语言
  • 更多大师谈 AI 编程:播客与访谈实录
  • 五位软件大师谈 AI 编程
  • Linux之父:Linus Torvalds 谈 AI 与 Linux 内核开发