【有感】JAVA程序员的可持续发展

发布时间:2026/10/27 1:59:06
【有感】JAVA程序员的可持续发展

《Sustainability for Java Developers》:一本 Java 社区写给自己的可持续发展指南

“Sustainable software development is not a single practice or technique—it is a way of seeing.”
——本书结语

谈到绿色软件、可持续发展,很多 Java 程序员的第一反应是:这和我写业务代码有什么关系?这本书的回答是:关系很大,而且大部分事情从明天就能开始做。

这篇文章会先介绍这本书的背景和结构,再按章节分享书里的主要内容,最后聊聊书中观点引出的一些我自己的想法。

关于这本书

《Sustainability for Java Developers: Towards an Understanding of Sustainable Java Software Development》由 foojay.io(Friends of OpenJDK)社区发起。社区里越来越多人在讨论"我们这个行业能为可持续做些什么",于是大家决定一起写一本书。

几个基本信息:

  • 免费获取:在 Leanpub 上免费提供 PDF、EPUB 等格式。
  • 持续更新:2026 年 1 月首发,2 月重写了架构一章,3 月新增了 Docker 镜像瘦身的内容,之后还会继续迭代。
  • 作者阵容:12 位来自不同公司和国家的作者,包括 A N M Bazlur Rahman、Frank Delporte、Geertjan Wielenga、Hanno Embregts、Jan Ouwens、Jan-Hendrik Kuperus、Ko Turk、Maarten Mulders、Markus Westergren、Simon Martinelli 等,其中多位是 Java Champion。
  • 开放投稿:只要和 Java 开发相关、对可持续有想法,就可以加入 Foojay 的 Slack 参与贡献。

作者们在前言里很坦诚:他们不一定是这些话题的权威专家,有些内容有明确的技术例子,有些更多是态度上的转变。各章可以独立阅读,所以这本书既能从头读到尾,也能当作"菜谱"按需翻阅。

全书结构

章节作者主题
引言 + 基础概念Jan-Hendrik Kuperus 等可持续的定义,全书共用的 19 个概念
第 1 章 Fair Trade SoftwareMaarten Mulders、Geertjan Wielenga开源生态的公平与正义
第 2 章 Stopping the Data MadnessFrank Delporte数据格式与传输开销
第 3 章 Impact of ArchitectureSimon Martinelli(含 Jan Ouwens 一节)架构如何决定资源消耗
第 4 章 Career and WellbeingMarkus Westergren程序员的职业与身心可持续
第 5 章 Java’s Evergreen AppealA N M Bazlur Rahman为什么 Java 是长期投资
第 6 章 Simple things you can do right nowJan Ouwens、Ko Turk构建缓存、镜像瘦身等速效手段
第 7 章 Java as a Scripting LanguageA N M Bazlur Rahman用 Java 25 写脚本
结语Geertjan Wielenga可持续是一种看问题的方式

可以看到,这本书的覆盖面很广:从开源伦理到 Dockerfile,从架构设计到个人作息。这种跨度一开始可能让人意外,但它正好体现了作者对"可持续"的理解。

一、先重新定义"可持续"

引言部分没有直接谈技术,而是先回答"什么是可持续"。作者对比了维基百科和剑桥词典的定义,然后给出了自己的版本:

Sustainability is the ability to create and maintain opportunities for human flourishing on a global scale, without discrimination.

这个定义包含三层意思:人能充分发挥潜力,环境适宜居住,经济是公平的。所以在这本书里,环境只是可持续的一个维度,开源维护者的处境、程序员的身心健康同样属于这个话题。

引言里还有两个值得一提的内容:

  • 数据:数据中心和传输网络约占全球用电量的 2%–4%,在 AI 竞赛的推动下,这个比例到 2030 年可能大幅上升。
  • 关于"AI 会解决气候问题":作者打了个比方,车正开向悬崖,修车师傅还在修刹车,你难道不先松一松油门,给他争取点时间?

我的想法:这个宽泛的定义有个实际好处,它让不同角色都能找到切入点。做架构的可以关注资源消耗,带团队的可以关注人的状态,做技术选型的可以关注依赖的健康度。可持续不再只是运维或基础设施团队的事。

二、开源依赖的"公平贸易"

第一章是全书视角最独特的一章。作者用公平贸易咖啡做类比:消费者愿意为公平贸易认证多付钱,是因为不想参与对生产者的剥削。那软件的"原材料"是什么?除了电力和硬件,还有每个项目里成百上千个开源依赖。它们背后是真实的人,很多人在业余时间无偿维护。

书中描述了"免费的悖论":开源刻意不定价,这是它能广泛传播的原因,却也让维护者很难获得公平的回报。作者举了 Log4Shell 的例子:漏洞爆发后,一些大公司要求小型开源社区在 96 小时甚至更短时间内答复,好赶上内部的报告期限,却没有提供任何报酬。

作者提出了"公平贸易软件"的四个方向:

  1. 公开透明地说明自己的软件供应链;
  2. 按获得的价值比例回馈;
  3. 尊重维护者,不要求即时响应,尊重他们设定边界的权利;
  4. 支持整个生态,而不只是最显眼的明星项目。

给组织的五条具体建议是:设立开源支持预算、审计依赖、回馈上游、有重点地赞助、把项目的可持续性纳入技术选型。

我的想法:

  • 依赖审计和供应链安全其实是同一件事。很多公司已经在做 SBOM(软件物料清单)和漏洞扫描,在这个基础上再加一列"维护者是谁、是否有资金支持",成本很低。用安全合规的名义申请开源赞助预算,也比单纯谈"公平"更容易被管理层接受。
  • 书里提到"有时自己写一个简单工具函数,比引入一个明年可能被弃用的包更可持续"。我很认同。每多一个依赖,就多一个需要升级、需要关注漏洞的对象。引入依赖前多问一句"真的需要吗",是成本最低的供应链治理。
  • 对个人开发者来说,最容易做的回馈是写一份可复现的 issue。这不花钱,但能实实在在减轻维护者的负担。

三、只有机器在读的数据,为什么要"人类可读"?

第二章的作者 Frank Delporte 平时用 Java 控制电子元件,他用一个很直观的例子说明数据格式的开销:数码管上显示数字 5,在电路里只需要 1 个字节0x6D。同样的信息换成常用的数据格式:

格式字符数压缩后
HEX0x6D1-
XML345150
JSON250118
YAML20299
Protobuf2444

两个细节值得注意:XML 比原始数据大了 300 多倍;对小数据压缩,体积反而会变大。

作者的核心问题是:“既然只有计算机在读,为什么要传输人类可读的数据?” 需要排查时,可以靠代码把字节解析成可读格式,也可以用 Wireshark 这类工具抓包。书中还引用了 LinkedIn 的案例:他们有超过 5 万个基于 JSON 的 API 端点,在微服务之间改用 Protocol Buffers 后,延迟最多降低了 60%。

我的想法:这个问题值得问,但答案要分场景。

  • 适合换成二进制格式:高频的内部服务调用、消息队列里的大量事件、物联网设备上报。在这些场景用 gRPC/Protobuf,体积和序列化开销都能明显下降,而且有 schema 约束,类型更安全。
  • 继续用 JSON 也合理:对外开放的 API、调用量很低的管理接口、需要和前端直接交互的接口。这些场景里,可读性和生态兼容性带来的价值,往往大于节省的那点带宽。
  • 换格式之前,可以先做两件更便宜的事:去掉响应里没人用的字段,避免重复调用。这两点在第三章也有讨论。

四、架构决定了可持续的天花板

第三章由 Simon Martinelli 撰写,2026 年 2 月做过一次大幅扩充,是全书技术密度最高的一章。全章围绕一个批发企业的 ERP 系统展开,核心观点是:

No amount of operational optimization can compensate for an architecture that requires all components to run all the time.

如果架构要求所有组件一直运行,运维层面再怎么优化也弥补不了。

从需求阶段开始区分

作者建议对每个模块问三个问题:用户什么时候用?中断会影响工作吗?停机会让公司亏钱吗?问完会发现,ERP 里只有订单模块需要最高可用性和弹性;产品和客户管理只在工作日办公时间使用;仓储和运输从清晨用到下午;财务模块每天甚至每月才出一次账单。

Stop Chasing Nines

这一节由 Jan Ouwens 撰写。他举了两个例子:荷兰一些严格的新教组织(包括报纸和网店)周日会关闭网站;乐高爱好者网站 BrickLink 每天有 10 分钟维护窗口。两者都提前告知用户,运营得也都很好。他的建议是:大多数应用 95% 的可用性就够了,只要沟通清楚,就能省掉冗余服务器和编排层的开销。

架构上的具体做法

  • 默认使用模块化单体:微服务的隐性成本包括网络调用和序列化、Kubernetes 控制面和 Sidecar、分布式追踪和日志、每个服务一个 JVM、每个服务一条流水线。作者推荐用 Spring Modulith,在测试中强制校验模块边界(ApplicationModules.of(ErpApplication.class).verify()),等有明确证据时再拆出独立服务。
  • 优先异步通信:A 同步调用 B,B 就必须在 A 运行的所有时间里在线。改成事件驱动后,订单模块把事件发到消息队列,仓储模块早上 6 点上班时再消费。这就是 Holly Cummins 提出的LightSwitchOps:不用的东西就关掉,就像离开房间时随手关灯。
  • 用数据冗余换取解耦:通过 ETL、CDC 或事件溯源,让模块持有本地数据。ETL 可以安排在可再生能源占比更高的时段运行;CDC 比轮询更省资源。
  • 高效使用资源:缓存优先用 Caffeine 这类进程内缓存,只有多实例必须共享状态时才用 Redis;API 支持分页和字段选择,避免 N+1 调用(100 个订单变成 101 次请求)。
  • 弹性伸缩:低频模块缩容到零,核心模块合理配置资源。作者特别提醒,自动伸缩往往扩容积极、缩容保守,而从可持续的角度看,缩容同样重要。

章末留了一个问题,很适合放进架构评审:

Does this design allow the system to use only the resources it needs, when it needs them, and nothing more?

我的想法:

  • "95% 可用性"对面向消费者的核心业务很难直接推行,但大多数公司都有大量内部系统、测试环境、预发环境和报表服务。从这些系统开始实践 LightSwitchOps,几乎没有业务风险,收益却很直接。
  • 缩容到零对 Java 一直不太友好,主要卡在启动时间。好在 CDS、AOT 缓存、CRaC、GraalVM Native Image 这些技术已经比较成熟,"Java 服务按需启动"不再是空想。
  • 这一章的思路和 DDD 里的核心域、支撑域划分很契合。不同的域本来就有不同的可用性要求,只是我们过去很少把这个差异落实到部署和资源配置上。

五、程序员自己也需要可持续

第四章由 Markus Westergren 撰写,是全书篇幅最长的一章。开头是一个很多人都经历过的场景:作者连续盯了 14 个小时屏幕,凌晨 3 点终于修好一个困扰了几周的竞态条件;第二天同事 review 代码时,在他的修复里发现了 3 个新 bug。

这一章的主要内容:

  • 代码质量和身心状态互相影响:休息充足的开发者思路更清晰,更注重细节,技术决策也更稳妥;反过来,整洁的代码能降低认知负担,减少救火。一旦进入负循环(疲惫 → 代码质量差 → bug 多 → 压力大 → 更疲惫),可以从技术和个人两头同时打破。
  • 健康债(wellbeing debt):我们定期重构代码来偿还技术债,也需要定期"重构"自己的习惯来偿还健康债。
  • 现代 Java 降低认知负担:lambda、Optional、模式匹配、虚拟线程都能让代码更简洁。作者的团队做过一次为期两周的"重构休整",把旧数据类改成 record,用模式匹配简化控制流,code review 变快了,团队士气也明显回升。
  • Inner Development Goals 框架:从 Being、Relating、Thinking、Collaborating、Acting 五个维度规划成长。
  • 具体习惯:20-20-20 护眼法则、专注时关闭通知、记技术日志、找导师也当导师、加入 JUG 等社区。
  • 行动计划:按 30 天、3–6 个月、6 个月以上分阶段列出行动项,并建议用"习惯叠加"把新习惯挂在已有习惯上。

书中引用了一个数据:62% 的科技从业者表示自己"身心俱疲"。

我的想法:这一章看起来和"绿色软件"关系最远,其实是全书的地基。结语里有一句话说得很直接:倦怠的开发者没有余力关心效率。一个天天被线上故障追着跑的团队,不可能有时间去调 GC、瘦身镜像、重新评估 SLA。从这个角度看,控制加班、保留还技术债的时间,同样是可持续工程的一部分。

作者讲的一段个人经历也很有参考价值:他在职业中期想一口气学完云原生和微服务,结果工作质量下降,学得反而更慢。后来改成每天只学一小时,在工作项目里实践新技术,效果好得多。面对技术更新,节奏比强度更重要。

六、Java 本身就是一种长期投资

第五章由 Bazlur Rahman 撰写。他的出发点是:学习时间是开发者最稀缺的资源之一,追逐一个两三年就过气的技术,学习投入很可能变成沉没成本。

他从几个方面说明 Java 为什么是长期投资:

  • 持续演进:从 lambda、Stream 到 record、模式匹配、虚拟线程、结构化并发,再到分代 ZGC 和 AOT 缓存,语言和 JVM 一直在进步;
  • 适用面广:企业系统、Android、大数据、金融交易、物联网都能用;
  • 生态稳定:JCP 机制,加上 Oracle、Red Hat、Amazon、IBM、Azul 等多家公司共同支持;
  • 过时得慢:向后兼容做得扎实,多年前写的代码往往改动很少就能运行,离开几年再回来,知识依然有用。

我的想法:这一章站在 Java 社区的立场,难免偏向 Java,读的时候要意识到这一点。但"技术选型要考虑长期维护成本"这个原则适用于任何技术栈。选型时,除了比较性能和功能,也值得评估:这项技术五年后还有人维护吗?团队换人后还招得到人吗?

七、把 Java 当脚本语言

第七章同样由 Bazlur Rahman 撰写。Java 25 引入了 JEP 512(紧凑源文件和实例 main 方法),一个完整的程序只需要这样写:

voidmain(){IO.println("Hello, World!");}

再加上单文件执行(JEP 330)、多文件执行(JEP 458)、模块导入(JEP 511)和 shebang 支持,Java 写小工具已经不比 Bash 或 Python 麻烦。书中给出了文件处理、HTTP 请求、调用系统命令、JDBC 查询、JSON 处理(借助 JBang 管理依赖)等常见模式,还建议团队建一个共享的脚本仓库。

作者从可持续的角度给出的理由是:

  • 代码寿命长:为 Java 25 写的脚本,在未来的版本上大概率还能运行,不会出现 Python 2 到 3 那样的大规模断裂;
  • 类型安全:错误在运行前就能发现,而不是脚本跑了几个小时才暴露;
  • 执行高效:JIT 编译后速度快,任务 10 秒跑完而不是 100 秒,CPU 就只做了十分之一的工作;
  • 平滑扩展:从单个文件长成多个文件,再到引入 Maven,都不需要重写逻辑。

我的想法:对短小、一次性的脚本来说,JVM 的启动开销可能抵消 JIT 的优势,Bash 依然更合适。但对于要长期维护、团队共享、逻辑稍复杂的运维工具,Java 脚本确实是个好选择,尤其是团队本来就以 Java 为主的时候,不用再额外维护一套 Python 环境和依赖。

八、马上就能做的几件小事

第六章由 Jan Ouwens 和 Ko Turk 撰写,是全书最适合直接动手的一章。作者引用 Holly Cummins 的观点:只要能让应用跑得更快,或者降低运行成本,你大概率就是在减少碳排放。

构建缓存

Maven 第一次构建会"下载整个互联网"。CI 环境每次都是全新的,这意味着每次提交都要重新下载一遍。在 GitHub Actions 里,加一行配置就能解决:

-name:'Set up JDK'uses:actions/setup-java@v5with:java-version:25distribution:temurincache:maven# 加这一行就够了

更进一步,可以启用 Gradle Build Cache(org.gradle.caching=true)或 Maven 的maven-build-cache-extension(需要 Maven 3.9.1 及以上),跳过没有变化的模块和测试,还能配置远程缓存在团队内共享。作者特别提醒:缓存配置很容易悄悄失效,要定期确认它真的生效了。

Docker 镜像瘦身

书中用一个 Hello World 程序演示了镜像一步步压缩的过程:

方案镜像大小
直接用 Maven 镜像构建并运行约 500 MB
多阶段构建397 MB
换成eclipse-temurin:25-jre-alpine227 MB
jdeps + jlink 裁剪运行时124 MB
GraalVM Native Image94.3 MB
Native Image 静态链接 +FROM scratch13.4 MB

镜像变小,存储、备份和传输的开销都会下降;去掉 shell 和包管理器,攻击面也更小。作者同时提醒了几个现实问题:原生二进制和平台绑定;反射较多的框架用 jlink 需要额外配置;如果线上需要进容器调试,就不能只放一个二进制文件;在公司内部,统一基础镜像可能比各项目各自追求最小镜像更划算,因为共享镜像只需下载一次、修补一次。

这一节的最后一句话很适合贴在工位上:

Whatever you do, don’t ship a 500MB Docker image for a 2.6kB jar file.

给慈善机构捐款

这条建议有点出人意料。作者引用 William MacAskill 在《What We Owe the Future》中的观点:开发者的收入通常高于平均水平,但缺少种树、游说、诉讼所需的时间和专业知识,慈善机构恰好相反。捐款能借助慈善机构的规模效应,产生个人难以达到的影响。

贯穿全书的几个概念

书的开头有一章"基础概念",列了 19 个概念,后面各章会反复引用。其中几个特别值得了解:

  • 5R 原则:Refuse、Reduce、Reuse、Repurpose、Recycle。顺序很重要,拒绝不必要的工作,比事后回收它产生的浪费有效得多。放到软件里,第一步就是不做没人用的功能。
  • 说"不"的能力:对范围蔓延、不必要的复杂度、"永远在线"说不。
  • 先思考,再编码:最可持续的代码,是根本不需要写的那一行。O(n) 和 O(n²) 在开发环境里感觉不出差别,到了生产规模就是巨大的浪费。
  • 边际收益的数学:1% 的优化,乘以每天数百万次执行、上千个应用和好几年的运行时间,就是可观的节约。反过来,一个被广泛使用的库里的小低效,浪费的能源可能比任何一个开发者一辈子能省下的都多。
  • 云的悖论:云让开一台服务器感觉毫无分量,无限容量的错觉会鼓励过度配置。要把资源当作稀缺的,即使它看起来是无限的。
  • 数据是有重量的:每一封归档邮件、每一个被遗忘的 Docker 镜像、每一份多余的备份,都在消耗存储和能源。
  • 集体行动放大影响:删除自己的旧邮件,远不如推动团队和组织一起改变。
  • 测量是优化的基础:我们对延迟和错误率追踪得一丝不苟,却很少测量能耗。被测量、被看见的东西,才会被管理。

延伸想法:书里没展开的几个方向

这本书提出了很多好问题,也有几个方向点到为止。下面是我顺着书里的思路想到的一些补充。

1. "测量"需要具体的工具

书中反复强调"测量是优化的基础",但没有具体介绍能耗测量工具。对 Java 开发者来说,可以从这几个层次入手:

  • 应用层:JDK Flight Recorder(JFR)、async-profiler,用来找出 CPU 热点、内存分配和 GC 压力。它们不直接给出能耗数据,但 CPU 和内存是能耗最主要的来源。
  • 能耗估算:JoularJX 这类 Java agent 可以把能耗估算到方法级别;Kubernetes 环境可以用 Kepler 估算 Pod 的能耗。
  • 云账单与碳排放:主流云厂商都提供碳足迹面板,开源的 Cloud Carbon Footprint 可以汇总多云数据。
  • 统一口径:Green Software Foundation 的 SCI(Software Carbon Intensity)规范,提供了"单位功能碳排放"的计算方法,适合用来对比优化前后的效果。

我的建议是先别追求精确的碳排放数字。先用 JFR 和云账单建立资源使用的基线,就已经能发现大部分浪费。

2. 成本是推动落地最好的抓手

书里有一个"可持续的商业论证"概念:高效的代码运行更快、成本更低,维护良好的系统需要更少的紧急干预。Jan Ouwens 在"Stop Chasing Nines"里也建议,算出降低 SLA 能省多少钱,这可能是说服决策者最有效的方法。

在大多数团队里,单纯谈环保很难排进迭代计划,但谈"每月能省多少云费用"就容易得多。可持续工程和 FinOps 在实践中高度重合:关停闲置环境、右调资源配额、精简镜像,既降低成本,也减少能耗。把两者放在一起推进,阻力会小很多。

3. AI 编程时代,"先思考再编码"更重要

书里提到"最可持续的代码是根本不需要写的那一行"。在 AI 编程助手普及之后,这句话有了新的含义:生成代码的成本越来越低,代码量很容易膨胀,而每一行代码都需要被审查、测试、运行和维护。

我的看法是,AI 让"能不能写出来"不再是瓶颈,"该不该写"和"写多少"变得更关键。5R 原则里的 Refuse 和 Reduce,在这个时代反而更值得强调。

4. 可持续是一个团队习惯

书里的建议大多是一次性动作,比如加一行缓存配置、改一次 Dockerfile。但缓存会悄悄失效,镜像会慢慢变大,测试环境会在某次需求后重新开着过夜。要让效果持续,最好把它变成流程的一部分:

  • 在架构评审模板里加一项"资源与可用性需求";
  • 在 CI 里加入镜像大小检查,超过阈值就告警;
  • 定期(比如每季度)回顾云资源使用和依赖健康度;
  • 在技术分享里固定留一个"可持续"话题。

这本书适合谁读

  • 刚接触绿色软件的 Java 开发者:先读引言、基础概念和第 6 章,能快速建立整体认识,并马上找到可以动手的地方。
  • 架构师和技术负责人:第 3 章值得精读,它提供了一套从需求分析到部署伸缩的完整思路。
  • 团队管理者:第 1 章和第 4 章分别讨论了开源依赖治理和团队的可持续状态,都和管理决策直接相关。
  • 对 Java 新特性感兴趣的开发者:第 7 章是 Java 25 脚本能力的实用教程。

需要注意的是,这本书由多位作者合写,各章风格和深度不太一样。第 3 章、第 6 章的技术细节很扎实,第 4 章更偏个人成长,第 5 章则带有比较明显的社区立场。按需挑章节阅读,体验会更好。

结语

这本书没有给出一套标准答案,它更想改变我们看问题的方式。结语里说,贯穿全书的主线是有意识地做选择,而不是把浪费当作默认。

这种浪费可能是一个 500 MB 的镜像、一个整夜空转的财务模块、一段只有机器在读的 XML,也可能是一个被要求 96 小时内答复的开源志愿者,或者一个凌晨 3 点还在盯着屏幕的开发者。

书的最后一句话是:

That is what sustainability means in practice: not perfection, but continuous, conscientious improvement—one line of code at a time.

不追求完美,只是持续、认真地改进,一行代码接一行代码。如果你对这个话题感兴趣,这本书免费、可以按章阅读,也欢迎加入 Foojay 社区参与后续内容的贡献。

参考

  • Sustainability for Java Developers(Leanpub)
  • Sustainability for Java Developers(foojay.io)