【有感】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 Software | Maarten Mulders、Geertjan Wielenga | 开源生态的公平与正义 |
| 第 2 章 Stopping the Data Madness | Frank Delporte | 数据格式与传输开销 |
| 第 3 章 Impact of Architecture | Simon Martinelli(含 Jan Ouwens 一节) | 架构如何决定资源消耗 |
| 第 4 章 Career and Wellbeing | Markus Westergren | 程序员的职业与身心可持续 |
| 第 5 章 Java’s Evergreen Appeal | A N M Bazlur Rahman | 为什么 Java 是长期投资 |
| 第 6 章 Simple things you can do right now | Jan Ouwens、Ko Turk | 构建缓存、镜像瘦身等速效手段 |
| 第 7 章 Java as a Scripting Language | A 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 小时甚至更短时间内答复,好赶上内部的报告期限,却没有提供任何报酬。
作者提出了"公平贸易软件"的四个方向:
- 公开透明地说明自己的软件供应链;
- 按获得的价值比例回馈;
- 尊重维护者,不要求即时响应,尊重他们设定边界的权利;
- 支持整个生态,而不只是最显眼的明星项目。
给组织的五条具体建议是:设立开源支持预算、审计依赖、回馈上游、有重点地赞助、把项目的可持续性纳入技术选型。
我的想法:
- 依赖审计和供应链安全其实是同一件事。很多公司已经在做 SBOM(软件物料清单)和漏洞扫描,在这个基础上再加一列"维护者是谁、是否有资金支持",成本很低。用安全合规的名义申请开源赞助预算,也比单纯谈"公平"更容易被管理层接受。
- 书里提到"有时自己写一个简单工具函数,比引入一个明年可能被弃用的包更可持续"。我很认同。每多一个依赖,就多一个需要升级、需要关注漏洞的对象。引入依赖前多问一句"真的需要吗",是成本最低的供应链治理。
- 对个人开发者来说,最容易做的回馈是写一份可复现的 issue。这不花钱,但能实实在在减轻维护者的负担。
三、只有机器在读的数据,为什么要"人类可读"?
第二章的作者 Frank Delporte 平时用 Java 控制电子元件,他用一个很直观的例子说明数据格式的开销:数码管上显示数字 5,在电路里只需要 1 个字节0x6D。同样的信息换成常用的数据格式:
| 格式 | 字符数 | 压缩后 |
|---|---|---|
HEX0x6D | 1 | - |
| XML | 345 | 150 |
| JSON | 250 | 118 |
| YAML | 202 | 99 |
| Protobuf | 24 | 44 |
两个细节值得注意: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-alpine | 227 MB |
| jdeps + jlink 裁剪运行时 | 124 MB |
| GraalVM Native Image | 94.3 MB |
Native Image 静态链接 +FROM scratch | 13.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)