1995年,Niklaus Wirth在《Computer》杂志上发表了一篇名为《A Plea for Lean Software》的文章。他在文中感叹:软件已经膨胀到以兆字节计。他引以为傲的Oberon操作系统——包含编辑器和编译器——只有200千字节。

三十年过去了。今天,一个简单的"Hello World" Electron应用就需要244兆字节。Wirth在2024年1月1日去世,但他留下的定律依然在折磨着我们:软件变慢的速度,比硬件变快的速度更快

这不是夸张。这是一场持续了半个世纪的工程权衡。

一个被忽视的定律

大多数人熟悉摩尔定律:集成电路上的晶体管数量每18到24个月翻一番。但很少有人知道它的"邪恶双胞胎"——Wirth定律。

Wirth定律的表述是:软件变慢的速度,比硬件变快的速度更快。换句话说,硬件性能的提升,几乎完全被软件膨胀所抵消。

这个定律有一个更直白的名字:“软件膨胀定律”。

1995年,当Wirth抱怨软件达到"兆字节"级别时,他的读者可能会觉得这是危言耸听。但数据证明他是对的——而且比他想象的更糟。

微信:从457KB到257MB的十一年

2011年1月,微信发布Android 1.0版本,安装包大小为457KB。2022年7月,微信Android 8.0.24版本的安装包达到了257MB。

膨胀了575倍

这不是孤例。根据DT财经统计的50个用户规模过亿的手机App,初始版本的安装包加起来约1.14GB,但这些App现在的安装包加起来已经超过100GB。

操作系统:从50MB到64GB

Windows 95的标准安装需要50-55MB硬盘空间。Windows 11需要64GB——这是1000倍的差距

内存需求增长同样惊人。Windows 95最低需要4MB内存,Windows 11最低需要4GB——1000倍

操作系统 发布年份 最小内存 硬盘空间
Windows 95 1995 4 MB 50-55 MB
Windows XP 2001 64 MB 1.5 GB
Windows 7 2009 1 GB 16 GB
Windows 10 2015 2 GB 32 GB
Windows 11 2021 4 GB 64 GB

这不是微软一家的问题。macOS、Linux发行版都在沿着同样的轨迹膨胀。

膨胀的根源:不是懒惰,是选择

软件膨胀不是开发者懒惰的结果。它是无数个理性决策累积的后果。

抽象层的代价

现代软件开发建立在层层抽象之上。以一个典型的Web应用为例:

  1. 硬件层:CPU、内存、存储
  2. 操作系统层:进程管理、内存管理、文件系统
  3. 运行时层:Node.js、JVM、.NET
  4. 框架层:React、Angular、Vue
  5. 库层:成百上千的第三方依赖
  6. 应用层:业务逻辑代码

每一层都承诺"让开发者更高效",但每一层都带来开销。

Electron是这种抽象堆积的典型案例。一个Electron应用包含:

  • 完整的Chromium浏览器引擎
  • Node.js运行时
  • 应用自身的JavaScript代码

结果是:一个简单的桌面应用就需要200MB+的安装包,运行时占用数百MB内存。

依赖爆炸

2016年3月,一个名为Azer Koçulu的开发者从npm删除了一个名为left-pad的包。这个包只有11行代码,功能是将字符串填充到指定长度。

结果:全球数以万计的项目构建失败。React、Babel、Node.js——整个JavaScript生态都受到了影响。

这揭示了一个令人不安的事实:现代软件的依赖树已经深到没有人能完全理解。

根据Sonatype 2023年的研究,平均每个JavaScript项目包含42个直接依赖和683个传递依赖。这意味着你安装一个包,可能不知不觉引入了数百个其他包。

一个典型的node_modules文件夹动辄几百MB。这不是异常,这是常态。

开发效率与运行效率的权衡

当代码要被机器执行时,效率是第一要务。当代码要被人阅读和维护时,可读性是第一要务。

但在商业项目中,还有第三个更重要的维度:开发速度

一个功能,用C++从零实现需要两周,用React加现成组件库只需要两天。在市场竞争的压力下,选择哪个?

“快速上市"几乎总是击败"高效运行”。这不是开发者的错,这是商业逻辑的必然结果。

Wirth在1995年写道:时间压力可能是软件膨胀的首要原因。它阻碍了仔细规划,阻碍了对可接受方案的改进,鼓励快速构思的软件添加和修正。时间压力逐渐腐蚀了工程师的质量和完美标准。

安全:膨胀的隐性成本

软件膨胀不只是用户体验问题,它是安全问题的温床。

攻击面的指数增长

网络安全有一个基本原理:代码量越大,漏洞越多

这不是理论推测。假设每千行代码平均有5-50个漏洞,那么一个100万行代码的项目可能有5000到50000个漏洞。

问题在于:现代软件的代码量已经膨胀到令人难以置信的程度。

IEEE Spectrum的一篇文章指出:一个基于Electron的应用,如果算上所有依赖,可能包含超过5000万行代码。而这一切,只是为了打开一个车库门。

Apple的iMessage攻击案例说明了问题的严重性。苹果决定让iMessage支持大量图片格式的预览——包括带有嵌入式字体的PDF。结果是:攻击者可以通过发送一条消息,利用PDF解析器中的漏洞远程控制iPhone。

这个漏洞不是核心功能,而是"功能膨胀"带来的副作用。

供应链攻击的温床

依赖越多,风险越大。每个第三方库都是潜在的攻击入口。

2024年的研究表明,npm生态系统中有大量被劫持、植入恶意代码的包。开发者无法逐一审查数百个依赖,只能祈祷不出问题。

2018年的event-stream事件是一个典型案例:一个流行的npm包被黑客接管,植入了窃取加密货币钱包的恶意代码。数百万下载量,无人察觉。

环境:被忽视的代价

软件膨胀的环境影响很少被讨论,但数据令人震惊。

电子垃圾的加速器

2022年,全球产生了6200万吨电子垃圾,比2010年增长82%。预计到2030年将达到8200万吨。

软件膨胀是电子垃圾增长的重要推手。当操作系统和应用程序不断膨胀,用户的硬件更快变得"过时"。一台运行Windows 95的电脑只需要4MB内存,而Windows 11需要4GB——旧硬件被软件膨胀强制淘汰

根据联合国大学的数据,2022年全球电子垃圾的价值估计为910亿美元,但只有17.4%被妥善回收。

能源消耗的隐形增长

臃肿的软件消耗更多能源——不仅在终端设备上,更在数据中心。

全球数据中心消耗的电力占全球电力的约2-3%。虽然能效在提高,但需求增长更快。软件膨胀是需求增长的重要因素:每一个冗余的功能、每一个不必要的依赖,都在全球服务器上复制数百万次。

另一种可能:极简软件的证明

软件膨胀不是物理定律,它是工程选择。有证据表明,另一种方式是可行的。

Oberon:200KB的完整系统

Wirth在1995年展示的Oberon操作系统是一个完整的开发环境:操作系统、编辑器、编译器,总共200KB。

这不是玩具系统。Oberon被用于实际的教学和研究工作,证明了"小而完整"是可能的。

Trifecta:现代的证明

2024年,一位开发者为了证明观点,编写了一个名为Trifecta的图片分享服务:

  • 1600行新源代码
  • 约5个重要依赖
  • 总大小:3MB

对比:另一个类似的图片分享服务打包为288MB的Docker镜像,还有一个基于Node.js的解决方案包含1600个依赖,超过400万行JavaScript代码

Tauri vs Electron:架构选择的力量

Tauri框架展示了架构选择对软件大小的巨大影响。同样的应用:

指标 Tauri Electron
安装包大小 8.6 MB 244 MB
内存占用(6个窗口) 172 MB 409 MB
底层引擎 系统WebView Chromium

Tauri使用操作系统的原生WebView,而不是打包完整的Chromium。Rust后端编译为原生二进制,不需要JavaScript运行时。

结果是:安装包小了28倍,内存占用减少58%

为什么膨胀无法停止

知道问题不等于能解决问题。软件膨胀持续增长,有其深刻的结构性原因。

市场机制不支持效率

在大多数软件市场,效率不是竞争优势。用户选择应用的标准是功能、价格、易用性,而不是内存占用或安装包大小。

当效率不产生收益时,投入资源优化效率就是不理性的商业决策。

正如Electron的维护者Felix Rieseberg所言:用户,无论是消费者还是企业,都不在乎二进制大小。一小时4K Netflix视频约7GB,一次Call of Duty更新超过300GB。在实践中,我们没看到终端用户比关心其他任何事情更关心二进制大小。

开发者的激励机制

开发者的激励机制也不支持效率。

  • 功能越多,考核指标越好:完成的Story点数、新增的功能数量
  • 依赖越多,开发越快:使用现成库比自己实现快得多
  • 优化无产出:重构和优化代码需要时间,但不产生可衡量的"成果"

结果是:每个开发者都理性地选择"膨胀",集体结果却是灾难。

硬件的"纵容"

摩尔定律几十年的持续运作,让硬件性能提升成为软件膨胀的"安全网"。

“硬件会追上来的”——这句话成为了不优化代码的借口。

但摩尔定律正在放缓。2025年,PassMark首次记录到平均CPU性能的年度下降。硬件的免费午餐可能即将结束。

可能的出路

承认软件膨胀是理性决策的结果,不意味着接受它是不可改变的。

工程层面的策略

代码重构:定期清理冗余代码,移除未使用的依赖。这是一项需要持续投入的工作,但长期收益巨大。

模块化设计:将软件分为独立模块,每个模块可以独立更新、替换或移除。这减少了维护负担,也限制了问题的传播范围。

审慎使用依赖:不是每个功能都需要第三方库。有时候,几十行代码就能解决问题,而不需要引入一个可能带来安全风险的依赖。

选择高效框架:Tauri证明了跨平台开发不必以巨大开销为代价。在选择技术栈时,效率应该是一个考量因素。

组织层面的改变

建立效率指标:如果效率不被测量,它就不会被优化。安装包大小、内存占用、启动时间——这些指标应该被追踪和报告。

分配优化时间:在项目计划中,明确分配时间用于代码优化和依赖审计。将"技术债务偿还"作为正式的工作项。

建立依赖审查流程:引入新的依赖应该经过正式审查,评估其必要性、安全性和维护状态。

行业层面的推动

欧洲联盟的网络弹性法案(Cyber Resilience Act)要求软件供应商最小化攻击面。这可能是法规推动效率改进的先驱。

开源社区也在行动。越来越多的项目开始关注二进制大小、内存占用和启动时间。这种"效率意识"的传播是改变的基础。

结语

1995年,Wirth写道:软件膨胀的瘟疫不是自然法则。它是可以避免的,限制它是软件工程师的任务

三十年过去了,软件膨胀的速度丝毫没有放缓。如果有什么变化,那就是它加速了。

但这不意味着我们应该放弃。Wirth的Oberon、现代的Tauri、Trifecta等项目证明了"小而完整"依然是可能的。关键在于:我们需要重新审视那些被视为理所当然的权衡。

硬件性能不是免费的。依赖不是无成本的。开发速度不应以运行效率为代价。

当摩尔定律最终触及物理极限时,当能源成本和电子垃圾成为不可回避的问题时,软件效率将从"可选优化"变成"生存必需"。

在此之前,我们能做的是:在每一个决策中,问自己一个问题——这段代码、这个依赖、这个功能,是否真的值得它带来的开销?

也许,这就是Wirth留给我们最宝贵的问题。


参考资料

  1. Wirth, N. (1995). “A Plea for Lean Software”. Computer, 28(2), 64-68.
  2. IEEE Spectrum. “Why Bloat Is Still Software’s Biggest Vulnerability”. February 2024.
  3. Pandaily. “WeChat Installation Package Expands 575 Times in 11 Years”. July 2022.
  4. Sonatype. “2024 Software Supply Chain Report”.
  5. Rieseberg, F. “Things people get wrong about Electron”. January 2025.
  6. Gethopp Blog. “Tauri vs. Electron: performance, bundle size, and the real trade-offs”. April 2025.
  7. Emsisoft. “The Hidden Danger: How Software Bloat Poses a Security Threat”. March 2024.
  8. Wikipedia. “npm left-pad incident”.
  9. Wikipedia. “Software bloat”.
  10. Wikipedia. “Feature creep”.
  11. Wikipedia. “Planned obsolescence”.
  12. WHO. “Electronic waste (e-waste) Fact Sheet”. October 2024.
  13. United Nations Institute for Training and Research. “Global E-Waste Monitor 2024”.
  14. GWS Media. “How system requirements for Microsoft Windows have changed”. December 2021.
  15. Bundlephobia. “Size of npm dependencies”.
  16. Medium. “The Hidden Costs of NPM Dependencies”. April 2025.
  17. Reddit. “Is Wirth’s law true?”. February 2017.