“强力文集”系列是源自于“强力宣言”的一系列虚构作品,作为强力宣言的主要价值观、原则和观点的展示。
⚠ 本故事纯属虚构。
作者:Strengthful Alliance
翻译:KimmyLeo
上篇
已经不再是几十年前内存和带宽匮乏的时代了,通用的数据序列化格式非常常见,比如 XML、JSON、YAML 等。这其中,XML 是早期企业级开发的时候常用的各式习惯,现在已经比较少见,JSON 仍然是通信和序列存储中的主流(其中还包含很多衍生格式和扩展,比如 BSON、json5 等),而 YAML 则是同类中的怪胎。
YAML 源自于 Standard ML 和 Perl 社区,直接的前任是 Perl 的Data::Denter
模块。后者用于在 Perl 中序列化对应的数据结构:
use Data::Denter;
print Indent bless {foo => 42,
bar => [ 'happy', undef, [], 'sad' ],
baz => "Bozo the Clown",
}, "Small::Example";
对应的输出结果:
%Small::Example
bar => @
happy
?
@
sad
baz => Bozo the Clown
foo => 42
可以看出来除了部分符号之外,已经跟 YAML 的形态很接近了。
我们来看一下作为主动在规范里面朝敏捷表示亲近的 YAML,有哪些问题。
易读?
YAML 的 7 个主要目标里面,第一个就有明显的问题:易于被人阅读(easily readable by humans)。
这样一个错误的假设让很多软件决定采用 YAML 来作为配置文件,结果陷入了后面 YAML 诸如编码问题或者格式错误的坑,也因此产生了各种懒惰性的决策。
作为数据序列化用的交换格式,费尽心机地考虑可读性和直接提供一个更简单的浏览/查询接口相比,后者要容易得多,这也是为什么 JSON 要远更流行的原因之一。YAML 在这个层面上选择的是一条非常绕的路子,还把自己给推到了坑里。
敏捷语言?
YAML 的第三个目标说,匹配“敏捷语言”的内建数据类型(matches the native data structures of agile languages),即:
- 序列结构
- 映射结构
- 标量
且不说这里提及的几个类型基本是每一种编程语言(C 语言除外)的标配,其“敏捷语言”的概念也仅限于参考的那几种,感觉是在给“敏捷”定范围。而众所周知的敏捷社区所青睐的 Java,显然是不在所谓的“敏捷语言”的列表里。
易于实现和使用?
第七个目标是易于实现和使用(easy to implement and use)。这个在我调研过绝大部分 YAML 社区版本实现以后发现是个完全不匹配的说法。
其一,YAML 设计非常复杂,为了表现其“可读性”,特别设计了流格式(flow style)和块格式(block style)两种表示方法:而这两种表示方法相互之间又非常容易混用,导致解析器实现要远比其他格式复杂得多。
其二,YAML 在数据格式表示层面上引入了“指令”(directive)的概念,企图去引导解析器的实现控制内容解析的目的。这就导致一方面容易把数据内容本身设计复杂,另一方面解析器不得不考虑进来这一层的影响额外多做很多事情。
其三,因为本身结构上遗留的坑,YAML 引入了版本化来解决,而 1.2 版本(草案)的内容事实上是没办法做到前向兼容的,但混杂着各种版本格式的 YAML 脚本(没错,各种 YAML 格式已经复杂倒像是在实际写代码一样了)还是要考虑做到兼容。哦还不止,1.2 版本的其中一个目标是达到一个让 JSON 作为 YAML 子集的这样一个虚妄目标。
应该是什么样子的?
诚然,回顾一下会发现 JSON 也有很多设计的坑,而且一部分直接源自 JavaScript。但业界worse is better的原则让 JSON 成功淘汰了更为完备的 XML。但这个行业不应该顶着一个有缺陷的工具裸奔。
我们会在下篇继续探讨,一个设计良好(well-design)的数据序列化/交换格式应该是什么样子的。
下篇
前文主要说了YAML这种数据格式的设计问题,下面我们单纯地通过其所要解决的问题来看看到底应该如何设计一个数据序列化/交换格式。
使用场景
这些序列化和交换格式的使用场景非常广泛。常见的应用程序中所涉及到的数据格式化存储、配置文档的管理、数据交换和通信中都会有其常见的应用。在一些特殊场景中也会把这些格式作为内嵌的文档放置在其他文档的内部,比如Markdown文档的front matter、React程序中的JSX脚本等。
但总结起来,其基础的作用无非就是用来表示某种特定结构的数据,再这之上再有额外的假设所设计出来的格式,都无可避免地变成了领域特定格式。比如toml,这样一个值观的配置定义格式,确实很大程度上做到了比JSON还要紧凑,但这也决定了其只能作为替代ini文档作为更高级的配置文件来用。