又一天,又一次关于依赖关系的咆哮。从我这里。这次我会要求你们在依赖关系方面开始并支持氛围转变。
您可能熟悉“依赖流失”的概念。这是永不停歇的更新、补丁、审核和传递依赖项的跑步机,我们作为开发人员喜欢以生产力的名义随意安装。谁不喜欢等待另一次货物升级,这样您就可以修复您根本没有的错误?
在大多数拥有良好包装解决方案的生态系统中,这都是一个瘟疫。 JavaScript 和 Rust 受此影响尤其严重。一个全新的 Tokio 项目会拖入 28 个板条箱,一个新的 Rocket 项目会增加到 172 个板条箱,而像 MiniJinja 这样的小型模板引擎只需一个依赖项即可存在,而其 CLI 变体则增加了 142 个。
如果这听起来没什么大不了的,让我们考虑一下terminal_size 。它是一个板条箱,其功能正如其名称所暗示的那样:它计算出您的终端尺寸。它使用的底层 API 自计算终端诞生之初就一直有效稳定——什么,50 年左右?然而,对于一项功能,终端大小会设法引入三到四个额外的板条箱,具体取决于您的操作系统。这会引发整个连锁反应,因此您最终会编译数千个其他函数,只是为了确定您的终端是 80×25 还是 120×40。该箱子有 26 个版本。我自己的版本在 10 年前的一个项目中保留了下来,无需任何更新即可运行。因为令人震惊的是:关于计算终端尺寸的一切都没有改变。
那么既然terminal-size这么稳定,为什么还会有这么多更新呢?因为它是建立在不断变化的平台抽象库之上的,所以它需要更新以避免代码重复和进一步延长编译时间。
但“大供应链”会告诉你,你必须这样做。您不敢将该函数复制粘贴到您的库中吗?或者你自己约会时不要使用“不安全”。你没有足够的资格来编写不安全的代码,让平台抽象架构师来做吧。不然别人会打你的。有些公司靠向你提供解决依赖问题所需的工具为生。以安全的名义,我们被迫拥有依赖项并保持它们最新,尽管大多数依赖项是安全问题的主要根源。
在很多方面,代码的目标应该是以不需要更新的方式编写。它最终应该达到某种程度的稳定性。在 Rust 生态系统中,稳定的代码会受到惩罚。如果您有一个完美工作的依赖项,但您有一个不太活跃的错误跟踪器,RUSTSEC 将会过来并给您一个块评级。
但还有一条更简单的途径。你自己写代码。当然,前期工作还比较多,但是一旦写下来,就完成了。不需要新的箱子,不需要等待上游作者来修复这个边缘情况。如果它对你来说坏了,你就自己修理。有效的代码不一定需要维护跑步机。你的代码有一个极端的情况吗?谁在乎。这就是 Rust 世界中我们需要的氛围转变:庆祝更少的依赖,而不是更多。
在大多数生态系统中,我们正处于这样一个阶段:引入库不仅仅是默认操作,而且是积极的:“看看我的代码是多么模块化和可组合!”实际上,这可能只是不想输入超过几行的症状。
现在有人会说,写完所有这些需要花费很多时间。现在是 2025 年,对我来说,让 ChatGPT 或 Cursor 快速实现这些常用功能的无依赖性实现比我开始找出依赖性要快。对于许多这样的小功能来说,维护开销很小,并且比实际处理依赖项的不断升级要低得多,这是有道理的。代码只有几行,您还可以获得不再需要为单个函数编译数千行其他人的代码的好处。
但让我们面对现实:企业代码审查文化也感染了开源软件。公司更有可能奖励工程师,而不是责备他们引入新的“闪亮库”来解决他们实际上从未遇到过的问题。这就产生了问题,因此 dependentabot 和朋友诞生了。今天,我只是害怕收到依赖机器人的拉取请求,但在项目上,但我必须接受它。我是我的东西生态系统的一部分,而这个生态系统就是流失、流失、流失。在公司中,您还可以让整个内部工程团队忙于供应商依赖性、内部审计和整个公司的升级。
这场战斗是异常艰难的!每个新员工都接受过这样的培训:依赖关系是伟大的,代码重用是伟大的。保留旧代码是糟糕的工程文化的标志。
在开源中也很难解决这个问题。几年前,我写了sha1-smol ,最初被称为sha1 。它成为计算 SHA1 哈希值的标准包。最终,我被迫将该包名称捐赠给 rust-crypto,并依赖于加密生态系统的其余部分,因为它是这样建立的。如果您想使用新的 sha1 箱子,您可以享受 10 个依赖项。但没有办法解决这个问题,因为注册表中的这个名字很珍贵,而且人们也希望具有特征兼容性。成为对话中唯一一个努力降低流失率和降低依赖性的人感觉很累。
是时候换个新视角了:我们应该向那些自己编写小函数而不是陷入可传递的板条箱网络的工程师致敬。我们应该对大板条箱图持怀疑态度。值得庆祝的是最小的依赖关系,只是安静地完成工作的不起眼的功能,多年来不需要修改的代码,因为它一次就完成了。
当然,这不是黑白分明的。有一些重要的库可以解决难题。图形库抽象了复杂的驱动程序、HTTP 和 QUIC 等协议的实现。我无法摆脱 tokio,而且我也不想这么做。但是,当您最终使用了一个函数,但又编译了数百个函数时,应该会响起一些警钟。
我们需要这种氛围转变。在适当的时候庆祝自己建造它。表彰构建低依赖性甚至无依赖性开源库的库作者。
例如,minijinja 在自述文件中对此进行了庆祝:
$ 货物树 最小 v0.1.0(示例/最小) └── minijinja v2.6.0 (minijinja) └── serde v1.0.144
并且它有一个 PR 最终摆脱了最后一个依赖。今年的某个时候,我将把自豪地前进并削减项目中所有多余的东西作为我的目标。