爱恨信 do Json
Source: Dev.to
使用 JSON 作为配置格式是一个错误。
是的,一个错误。不是偏好。不是风格选择。是一个架构错误。
这句话往往会让人不舒服,因为 JSON 能用。而当某件事能用时,业界往往会停止质疑它是否真正合理。
JSON 作为传输格式绝对成功。它可预测、确定、易于解析,几乎是通用的。在机器之间,它表现出色。问题出现在我们决定把这些相同的特性也用于让人类编写、阅读、版本控制和维护时。
事实并非如此。
JSON 刚硬、冗长且刻意受限。它不允许注释,不传达意图,不提供上下文,也不容错。这些特性在追求互操作性时是优点,却在表达规则、配置或领域结构时变成了纯粹的摩擦。
尽管如此,我们仍把 JSON 当作配置格式、临时 DSL,甚至作为需要人类花数小时阅读和编写的系统的创作层。它能工作吗?能。但它工作得很差——而且我们已经把这种痛苦常态化,并不会 magically(神奇地)把它变成良好的工程实践。
本文并不是在攻击 JSON,而是批评在错误的地方坚持使用合适的工具,然后对编写它的人感到痛苦却感到惊讶的做法。
为什么 JSON 能胜出
JSON 并不是因为它美观、优雅或富有表现力而获胜。它之所以获胜,是因为它乏味、受限且可预测——当问题是系统间通信时,这是一大优势。
- 它是一个小而封闭的格式,没有任何有意义的语法歧义,易于实现且不易误解。
- 它大幅压缩了创造的空间,这正是当两个互不认识的进程需要在不协商意图、上下文或隐含含义的情况下交换数据时所需要的。
从机器对机器的通信角度来看,JSON 几乎是理想的。它强制使用简单结构,不允许奇怪的快捷方式,不携带隐式语义,也不试图聪明。它本质上是原始数据的可预测封装。机器喜欢它,编译器喜欢它,基础设施喜欢它。
当有人说 “my API speaks JSON”,每个人都确切知道这意味着什么。没有惊喜,没有创意解释,没有 “是的,但在这种情况下…”。这是一份合同。而僵硬的合同在没人想在运行时进行协商时非常优秀。
作为一种传输格式,JSON 值得所有的尊敬。
一切开始出错的地方
问题始于有人看到这种格式——显然是为机器对机器通信而设计的——并认为它同样适合人类创作。
这通常并非出于恶意,而是源于架构上的懒惰。理由很简单:如果系统消费 JSON,就让人们编写 JSON。听起来合乎逻辑,却也是个糟糕的主意。
JSON 需要绝对的语法精确度,即使是最小的意图也不例外。一个逗号放错位置、一个引号缺失、一个括号闭合不当,整个就会崩溃。没有“稍微坏一点”的说法。要么解析错误,聊天结束。
这种行为对机器来说可以接受,但对人类而言却是敌对的——而这正是来自于那些实际上喜欢强类型和明确契约的人。
JSON 对人类结构上不友好
这不是品味问题,而是结构性问题。
- JSON 不允许注释。
- JSON 在其规范形式中不允许尾随逗号。
- JSON 不允许快捷写法。
- JSON 不允许语法放宽。
- JSON 不允许上下文。
- JSON 不允许意图 —— 只接受结构。
这迫使编写者不断思考语法而非意义。与其在领域上进行推理,你必须在脑中验证是否已闭合所有括号、是否在每处使用了双引号、以及是否没有遗漏逗号。这对本已复杂的任务来说是很高的认知负担。
当你看到一份手写的大型 JSON 文件时,它很少传达出清晰的信息。它传达的是阻力,传达的是有人在苦苦挣扎。
JSON 配置是一个被规范化的错误
JSON 配置文件可能是这种功能失调最常见的例子。它们无处不在,能够工作,且大家都把它们当作“理所当然的方式”接受。这并不意味着它们是一个好的解决方案。
配置,按照定义,是人类会读取、编写、审查、版本控制并讨论的东西。它承载意图、上下文,并且常常需要解释性注释。JSON 并不提供这些。
结果是产生冗长的文件,在 Pull Request 中审查时痛苦不堪,无法进行适当的评论,并且充斥着外部约定,例如“这个键是可选的,但仅在某种情形下可选,具体在别处的 README 中解释”。
它能工作。但它是靠怨恨驱动的工作。
支持 JSON 的论点
“但是 JSON 很简单。大家都懂它。”
是的。大家都懂它。但这并不意味着它合适。
这是一种薄弱的论点。
大家也都懂汇编语言——这并不意味着我们要用它来编写业务规则。
熟悉程度不是选择工具的标准。适合问题的才是。
JSON 对消费来说很简单,但对生成来说并不简单。
这种区别的重要性远超表面看起来的程度。
编写格式的存在是有原因的
当你使用 TypeScript、YAML、TOML、HCL 或任何其他体面的 DSL 来定义复杂结构时,差异立刻显现。这些格式的设计初衷是 让人编写、阅读和维护。
- 它们支持注释。
- 它们提供一定的灵活性。
- 它们更清晰地传达意图。
- 它们降低了编写时的认知成本。
- 最重要的是,它们让人先思考问题本身,再考虑如何表示。
许多这些格式最终 在内部被转换为 JSON 并非偶然——这是一种健康的架构。

Source: …
避免不必要痛苦的流水线
在设计良好的系统中,流程通常简单且可预测:
- 人类编写 表达性强、可验证且舒适(通常是键入)的内容。
- 机器验证、转换并标准化 该结构。
- 仅在需要在系统之间传输或持久化为契约时 使用 JSON。
这种分离不是官僚主义;它是对人类局限的尊重。
- 如果你在为机器编写 强类型配置,TypeScript 表现极佳。
- 如果你在编写 需要被读取和维护的配置结构,YAML(或类似的)更合适。
- 如果 机器需要向另一台机器发送数据,JSON 是完美的选择。
当你构建 API 时,例如,你会处理对象、类型、验证和抽象。JSON 在流程的最后一步生成,跨网络传输,在另一端被解析,并立即不再是人类关注的对象。没有人会直接触碰那个 JSON——这正是关键所在。

仇恨者还是粉丝?
我仍然喜欢在合适的场景下使用 JSON:传输、契约、序列化、系统间通信。
当有人期望我在 JSON 中编写、审查并维护复杂结构时,我仍然 讨厌 JSON,因为那并不是一种可接受的体验。
这不是固执。
这不是潮流。
这也不是技术精英主义。
这是一种对必须处理代码的人的基本尊重。
JSON 不需要无处不在才能保持价值。它只需要出现在合适的地方——而那个地方绝对 不是 凌晨两点你和键盘之间的那段时间。
注意: 本文中的所有图片均由 Nuno Banana 生成。

