10,000 Lines Later: When a Tool Became a Compiler - Rob Durst - Gleam Gathering 2026

Lobsters Hottest 事件

摘要

Rob Durst 在 Gleam Gathering 2026 上分享了如何用 Gleam 将 YAML-to-Terraform 的配置工具重写为编译器,并从中体会到类型驱动设计和解码器模式的力量。

<p><a href="https://lobste.rs/s/snppmc/10_000_lines_later_when_tool_became">Comments</a></p>
查看原文
查看缓存全文

缓存时间: 2026/05/24 14:58

**TL;DR:** Rob Durst 分享了他如何将一个 YAML-to-Terraform 的配置工具用 Gleam 重写为真正的编译器,并在此过程中从 Ruby 程序员转变为 Gleam 拥护者,体会了类型驱动设计和解码器模式的力量。 ## 引言:成为 Gleam 程序员 “什么让一个人成为 Gleam 程序员?”演讲以一个互动问题开场。有人喊出“大眉毛”、“静态类型”、“赞助商”,引来阵阵笑声。但 Rob 认为,成为 Gleam 程序员或许就只是写 Gleam 而已。而 Gleam 本身——是一种编程语言,一个社区,一场会议,还是它的文档?他希望听众带着这个问题听完整个演讲。 Rob 是一名站点可靠性工程师(SRE),来自美国犹他州盐湖城。为了铺垫背景,他需要简短介绍 SRE 领域的工作。核心思想是:他在构建一个工具,工具的具体内容并不重要,重要的是它如何演变成一个编译器。 ## 背景:SLO 与点击按钮的困境 在日常工作中,Rob 帮助团队落地所谓“服务等级目标”(SLO)——一个用来回答“正在运行的系统是否按预期工作?”的工具。通过观测用户关键旅程的可衡量指标,确保用户期望的行为在一定比例时间内成功。最初,落地方式就是去观测工具里点按钮。 但按钮越点越多,流程无法扩展。用户需要点击按钮来创建配置,于是 Rob 团队决定换一种方式:把“E”放回 SRE(工程化),构建了一些自动化工具。他们发现设置 SLO 需要回答大约 20 个问题,而其中真正有意义的只有 5 个。于是他们建立了一个规范,目标是制造一个“成功之坑”——让成功成为默认结果。 ## 当工具变成编译器 团队用 Ruby 写了一个工具:从 YAML 规范生成 Terraform 配置,再打上标签。原本那些“写了但没人读”的最佳实践文档,现在被固化到代码中,一旦提交就能自动生效。执行 Terraform 后,结果一致,但你可以直接写并提交代码。 这时 Rob 意识到:**他们意外地造了一个编译器!** 前端是 YAML 规范,中间有处理层,后端生成输出。这个工具试图解决创建简单 UI 并持续维护的问题。但维护这个 Ruby 工具变成了一种负担。问题不在 Ruby,而在于构建方式。工具需要维护,但 Rob 希望他能赋能成功而不是成为累赘。 ## 选择 Gleam:一个函数式、有类型的语言 Rob 跟老板说:“我喜欢编程语言,能不能就写个语言?”他之前写过玩具语言,但没人用过。而这次,有人必须用他的语言工作。他创建了一个叫 **Caffeine** 的开源编译器:从服务等级/期望定义(无类型声明式 YAML)生成可靠性工件(SLO)。 既然是业余时间写的,用什么语言?Rob 希望是函数式的,因为编译器有很多阶段,最好彼此隔离且纯净;需要类型,因为类型让编译器更容易写;特别想要代数数据类型和模式匹配。有一天他跑步时听播客《Type Theory for All》,其中一集是 Ryan Brewer 讲自学编程语言。听到一半,提到一种叫 **Gleam** 的语言:“函数式、有类型、代数数据类型、模式匹配不错。” Rob 心想:“全中。” ## 重写:解析 YAML、测试与类型強制 为什么仍然选用 YAML?因为大家喜欢 YAML。更实际的原因:可读性还行、大多数语言自带 YAML 解析器、如果想在 GitHub 上有语法高亮需要 200 多个仓库,如果自己写前端会等到猴年马月。第二点让 Rob 有点担心:Gleam 当时不到两年,他找到的第一个 YAML 库只有 7 颗星、11 次提交。但 Gleam 可以互操作 Erlang,这个库实际是构建在成熟的 Erlang 库 Yamerl 之上,只是 Rob 的“Ruby 脑”觉得不对劲。后来一切顺利,他超爱那个库。 至于后端,发现没人写 Terraform 生成器库,这似乎是普遍问题,不止 Ruby。 测试方面,作为 Ruby 程序员,Rob 习惯 BDD 风格(`describe`/`it`)。他写了一套测试工具并在 Discord 上问:“怎么没人这么做?”7 分钟内有人回复,也是一位从 Ruby 转过来的程序员,非常同理心地说:“我懂你,但别这么做。”这是绝佳建议。Rob 戏剧性地转为“表驱动测试”(源于 Go 世界,Dave Cheney 有篇好文章):一个数组里的元组(测试名、输入、输出),加上提取器。虽然丑但很有效,或许是一个值得社区发展的微模式。 最终,**一周内 Rob 就用 Gleam 写完了编译器**。这个工具虽不在生产环境但接近生产,人们必须用它,因为这是公司做可靠性的方式。 ## 类型驱动设计:从提取器到解码器 既然有了编译器,就该做编译器的事。最初要点击 20 次,后来规范语言只有 5 个问题。Rob 看到一篇文章谈到“类型驱动设计”,核心是“非法状态应不可表达”。他想把类型引入之前无类型的规范语言。比如阈值应该是一个浮点数,但在旧语言里你可以给苹果、梨,甚至你喜欢的咖啡馆列表——这不好。 如何实现?一开始 Rob 用了 `panic`(那是他使用 Gleam 的第三天)。形成“提取器模式”,使用 Glamour 库,获取节点并断言它是浮点数。他觉得这是最棒的,于是 fork 了 Glamour,心想全世界都应该用这些提取器。但很快出现了组合爆炸:每个可能的组合都需要写提取器,坏到他自己都不想用这个库了。 他看别人怎么做的。Gleam 编译为 Erlang,运行在 BEAM 上,很多人构建 Web 服务,喜欢 JSON。有个 Gleam JSON 库,星星和活动更多。在 Ruby/Rails 世界常说“约定优于配置”,这里也适用:走别人常走的路,概率上更多人走过。 在 JSON 库页面往下翻,看到“解码器”(decoders)。之前有提取器,但解码器更好。标准库提供了从 `dynamic` 类型解码的机制。可以把 `extract_float` 换成 `decode_float`,并修复 `panic`,正确返回 `Result`。 现在用更地道的 Gleam,牺牲 YAML 换 JSON(实际上“一样丑”)。有了类型强制,开始加更多类型,让语言成为“成功之坑”。从解析阶段到语义分析阶段,依赖一个全局可接受的类型。所有需要转字符串或解析类型的地方都用这个类型,于是可以完全覆盖模式匹配,得到一份要实现的清单。超级棒。 **添加一种类型大约只需 100 行代码**。而在 Ruby 世界(没好好建模),类似改动要五倍以上的差异。最终 Rob 添加了自己的前端,使用 `result.try` 用法模式,在递归下降解析器中很有帮助。 ## 经验与成就 这个编译器虽然规模不大,但标志着 Rob 从 Ruby 走向 Gleam。通过构建编译器,他学会了类型驱动设计、解码器模式,并且真正理解了“成功之坑”的含义。演讲最后,他以一句调侃结束:“希望今后每次 Gleam 会议都引用我的原话。” **Source:** [https://www.youtube.com/watch?v=wVQLEAHrwrI](https://www.youtube.com/watch?v=wVQLEAHrwrI)

相似文章

@tonygentilcore: https://x.com/tonygentilcore/status/2075234683202531403

X AI KOLs Timeline

Glean 的工程博客详细介绍了他们的新代理框架,该框架通过代码执行实现 100% 程序化工具调用,与标准工具调用相比,减少 24% 的 Token 使用量。该框架通过工具截断和沙箱文件系统管理上下文,适用于长时间运行的复杂工作流。

Gleam Gathering 2026 Lighting Talks

Lobsters Hottest

Gleam Gathering 2026 的闪电演讲涵盖了开放遥测封装、Luster HTML 与 SPA 对比、收据打印机 DSL、本机后端的幽默构建过程以及 Minecraft 数据生成,展示了 Gleam 生态中的实用工具和实验性项目。