为什么 JSON 不适合作为配置语言?

640?wx_fmt=gif

640?wx_fmt=jpeg

许多项目用 JSON 作为配置文件。也许最著名的例子就是 npm 和 yarn 使用的 package.json,还有许多其他项目也用 JSON,如 CloudFormation(最初仅支持 JSON,现在还支持 YAML)和 composer(PHP)。

但是,有几个原因表明 JSON 其实非常不适合作为配置语言。不要误会,我很喜欢 JSON。它非常灵活,而且机器和人类读起来都很容易,是个非常好的数据交换和存储的格式。但作为配置语言,它有许多缺点。


640?wx_fmt=png

为什么 JSON 成了流行的配置语言?


JSON 被用于配置文件有好几个原因。最大的原因就是很容易实现。许多语言的标准库都支持 JSON,标准库不支持 JSON 的语言也会有非常易用的 JSON 包。其次就是开发者和用户都已经很熟悉 JSON 了,不需要再为产品学一种新的配置格式。更不用说 JSON 的各种相关工具,包括语法高亮、自动格式化、验证工具等等。

这些都是很好的理由。可惜这种格式真的不适合作为配置文件。


640?wx_fmt=png

JSON 的问题


没有注释

配置语言的一个绝对必要的功能就是注释。注释非常有用,它能标识出配置项的可能的值,以及选择某个值的原因,还有最重要的一点就是临时注释掉某部分配置以方便测试和调试。而作为数据交换格式的 JSON 完全没有使用注释的必要。

当然也有方法解决这个问题。最常见的方法就是在对象中使用特殊的键作为注释,如"//"或"__comment"。但是,这种语法并不是很易读,而且如果要想在同一个对象中使用多个注释,就得给每个注释使用唯一的键。David Crockford(JSON的发明人)建议使用预处理器去掉注释(https://plus.google.com/+DouglasCrockfordEsq/posts/RK8qyGVaGSr)。如果你的应用程序要求 JSON 作为配置文件,那么我建议使用这种方法,特别是如果有某种构建过程的话。当然,这会给编辑配置带来一些额外的工作,因此如果你正在创建的应用程序需要解析配置文件的话,不要依赖用户去做这项工作。

一些 JSON 库允许使用注释。例如,Ruby 的 JSON 模块,以及 Java 的 Jackson 库加上启用 JsonParser.Feature.ALLOW_COMMENTS 功能,就能支持在 JSON 中使用 JavaScript 风格的注释。然而这并不是标准,许多编辑器也不能正常支持 JSON 文件中的注释,使得编辑配置文件比较困难。

过分严格

JSON 的标准非常严格。严格的目的是为了方便 JSON 解析器的实现,但我认为,它也影响了易读性,而且或多或少地使得人类书写 JSON 更困难。

低信噪比

与许多其他配置语言相比,JSON 的噪声很大。许多标点符号尽管使得机器很容易实现,但完全不能帮助人类阅读。具体来说,对于配置文件而言,对象中的键几乎必然是标识符,因此键的引号是完全不必要的。

而且 JSON 要求在整个文档外面使用大括号,这样做的目的是使之(几乎)成为 JavaScript 的子集,并且在发送多个 JSON 对象时易于分隔各个对象。但作为配置文件,最外层的大括号是完全无用的。键值对之间的逗号大部分情况下也没有用。通常,每一行就是一个键值对,所以完全可以把换行符作为分隔符。

说起逗号,JSON 还不支持末尾逗号。如果要求每个键值对都以逗号结尾,那么至少应该接受末尾逗号吧,因为末尾逗号使得在末尾添加新项目很容易,而且能更容易地比较不同版本的差异。

过长的字符串

JSON 作为配置文件的另一个问题是它不支持多行字符串。如果要在字符串中使用换行,就得转义成“\n”,而且更糟糕的是,如果想在文件中写一个跨行的字符串,那是完全没办法的。若是配置文件里没有特别长的字符串的话还好。但如果配置文件里包含长字符串,比如某个项目的描述,或者 GPG 秘钥,你肯定不希望把所有行都放在同一行里并用“\n”连接起来。

数字

此外,JSON对于数字的定义在某些场合下很有问题。根据JSON标准,数字是任意精度的有限浮点数,以十进制表示。大多数情况下这没什么问题。但如果你需要十六进制表示,或者需要无穷大、NaN等值,那么TOML或YAML能更好地处理这些输入。

 1{
2  "name""example",
3  "description""A really long description that needs multiple lines.\nThis is a sample project to illustrate why JSON is not a good configuration format. This description is pretty long, but it doesn't have any way to go onto multiple lines.",
4  "version""0.0.1",
5  "main""index.js",
6  "//""This is as close to a comment as you are going to get",
7  "keywords": ["example""config"],
8  "scripts": {
9    "test""./test.sh",
10    "do_stuff""./do_stuff.sh"
11  },
12  "bugs": {
13    "url""https://example.com/bugs"
14  },
15  "contributors": [{
16    "name""John Doe",
17    "email""johndoe@example.com"
18  }, {
19    "name""Ivy Lane",
20    "url""https://example.com/ivylane"
21  }],
22  "dependencies": {
23    "dep1""^1.0.0",
24    "dep2""3.40",
25    "dep3""6.7"
26  }
27}


640?wx_fmt=png

那应该用什么?


配置语言的选择取决于应用程序。每种语言都有自己的长处和短处。下面这些语言都可以考虑。这些都是专用于配置文件的语言,都比原本用于数据的 JSON 要好。

TOML

TOML(https://github.com/toml-lang/toml)作为配置语言日渐流行。它的使用者包括Cargo(Rust的编译工具)、pip(Python包管理器)和dep(golang 依赖管理器)。TOML 有点像 INI 格式,但与 INI 不同的是,它有自己的标准,而且对于嵌套结构有很好的支持。它要比 YAML 简单得多,所以当配置文件很简单时,TOML就很合适。但如果配置文件有大量嵌套结构,那么 TOML 可能会显得有点啰嗦,此时其他语言如 YAML、HOCON 可能是更好的选择。

 1name = "example"
2description = """
3A really long description that needs multiple lines.
4This is a sample project to illustrate why JSON is not a \
5good configuration format. This description is pretty long, \
6but it doesn't have any way to go onto multiple lines."""

7
8version = "0.0.1"
9main = "index.js"
10# This is a comment
11keywords = ["example""config"]
12
13[bugs]

14url = "https://example.com/bugs"
15
16[scripts]

17
18test = "./test.sh"
19do_stuff = "./do_stuff.sh"
20
21[[contributors]]

22name = "John Doe"
23email = "johndow@example.com"
24
25[[contributors]]

26name = "Ivy Lane"
27url = "https://example.com/ivylane"
28
29[dependencies]

30
31dep1 = "^1.0.0"
32# Why we depend on dep2
33dep2 = "3.40"
34dep3 = "6.7"

HJSON

HJSON(https://hjson.org/)是个基于 JSON 的语言,但更灵活,因此更容易阅读。它支持注释、多行字符串、不带引号的键和字符串,以及可选的逗号。如果你喜欢 JSON 的简单结构,但希望更适合配置文件的话,可以试试HJSON。它还提供命令行工具将 HJSON 转换成 JSON,因此如果你的工具要求 JSON 的话,你可以用 HJSON 写配置文件,并在构建过程中转换成 JSON。与 HJSON 相似的另一个选择是 JSON5(https://json5.org/)。

 1{
2  name: example
3  description: '''
4  A really long description that needs multiple lines.
5
6  This is a sample project to illustrate why JSON is 
7  not a good configuration format.  This description 
8  is pretty long, but it doesn't have any way to go 
9  onto multiple lines.
10  '''

11  version: 0.0.1
12  main: index.js
13  # This is a a comment
14  keywords: ["example""config"]
15  scripts: {
16    test: ./test.sh
17    do_stuff: ./do_stuff.sh
18  }
19  bugs: {
20    url: https://example.com/bugs
21  }
22  contributors: [{
23    name: John Doe
24    email: johndoe@example.com
25  } {
26    name: Ivy Lane
27    url: https://example.com/ivylane
28  }]
29  dependencies: {
30    dep1: ^1.0.0
31    # Why we have this dependency
32    dep2: "3.40"
33    dep3: "6.7"
34  }
35}

HOCON

HOCON(https://github.com/lightbend/config/blob/master/HOCON.md)是为Play框架(https://www.playframework.com/)设计的配置语言,但在Scala项目中非常流行。它是JSON的超集,所以可以兼容JSON文件。除了注释、可选逗号、多行字符串等标准功能之外,HOCON还支持从其他文家中导入,引用其他值的键以避免重复代码,以及使用点分隔的键指定到某个值的路径,这样用户就不需要把所有值直接放在大括号对象里了。

 1name = example
2description = """
3A really long description that needs multiple lines.
4
5This is a sample project to illustrate why JSON is 
6not a good configuration format.  This description 
7is pretty long, but it doesn't have any way to go 
8onto multiple lines.
9"""

10version = 0.0.1
11main = index.js
12# This is a a comment
13keywords = ["example""config"]
14scripts {
15  test = ./test.sh
16  do_stuff = ./do_stuff.sh
17}
18bugs.url = "https://example.com/bugs"
19contributors = [
20  {
21    name = John Doe
22    email = johndoe@example.com
23  }
24  {
25    name = Ivy Lane
26    url = "https://example.com/ivylane"
27  }
28]
29dependencies {
30  dep1 = ^1.0.0
31  # Why we have this dependency
32  dep2 = "3.40"
33  dep3 = "6.7"
34}

YAML

YAML(YAML Ain't Markup Language,“YAM不是标记语言”,http://yaml.org/)是个非常灵活的格式,它几乎是JSON的超集,许多著名的项目都使用YAML,如Travis CI、Circle CI和AWS CloudFormation。YAML的库几乎和JSON一样流行。除了支持注释、换行符分隔、多行字符串、不带引号的字符串和更灵活的类型系统之外,YAML还可以引用之前定义过的结构,从而避免代码重复。

YAML的主要缺点就是它的标准太复杂,导致不同实现之间的不一致。它的缩进层次还有重要的语法意义(类似于Python),这也是褒贬不一的地方。复制粘贴YAML也比较困难。关于YAML的缺点可以参考“也许不是那么好的YAML”(https://arp242.net/weblog/yaml_probably_not_so_great_after_all.html)一文。

 1name: example
2description: >
3  A really long description that needs multiple lines.
4
5  This is a sample project to illustrate why JSON is not a good 
6  configuration format. This description is pretty long, but it 
7  doesn't have any way to go onto multiple lines.
8version: 0.0.1
9main: index.js
10# this is a comment
11keywords:
12  - example
13  - config
14scripts: 
15  test: ./test.sh
16  do_stuff: ./do_stuff.sh
17bugs: 
18  url: "https://example.com/bugs"
19contributors:
20  - name: John Doe
21    email: johndoe@example.com
22  - name: Ivy Lane
23    url: "https://example.com/ivylange"
24dependencies:
25  dep1: ^1.0.0
26  # Why we depend on dep2
27  dep2: "3.40"
28  dep3: "6.7"

脚本语言

如果你的应用程序是用某种脚本语言写的,如 Python 或 Ruby,而且配置文件的来源可信,那么最好的选择就是用那种语言本身编写配置文件。对于编译语言,如果需要真正灵活的配置选项,也可以嵌入类似 Lua 这种脚本语言。这样可以享受到脚本语言的灵活性,而且比使用另一种配置文件更容易。但使用脚本语言的缺点就是它可能过于强大,而且如果配置语言的来源不可信,这样做会引入很严重的安全问题。

编写自己的配置语言

如果出于某种原因,键值配置格式不符合你的要求,并且由于性能或大小限制不能使用脚本语言,那么可能自己写一个配置格式更合适。但在这样做之前,务必要认真考虑,因为这样做不仅需要自行维护解析器,还需要让你的用户熟悉一种新的配置格式才行。


640?wx_fmt=png

结论


有了这么多配置语言的选择,使用JSON并不是个好注意。如果你要创建新的应用、框架或库,需要一个配置文件,那么选择JSON之外的格式吧。

原文:https://www.lucidchart.com/techblog/2018/07/16/why-json-isnt-a-good-configuration-language/

作者:Thayne McCombs© Lucidchart。

译者:弯月,责编:屠敏

640?wx_fmt=gif

640?wx_fmt=gif

展开阅读全文

为什么Linux不适合你?

02-12

Why Linux is Not for Yourn为什么Linux不适合你?rnrn本贴原文请见: http://epesh.com/linuxforyou.htmlrnrnTranslated by yilong, 2/12/2002rnEmail: yilong@gmx.netrnrn现在有很多关于Linux的极端的宣传,一些是积极的,也有一些是消极的。但可以肯定的一件事是:没有人在对待Linux的问题上是不明朗的。Microsoft在尽力说服大家NT的技术更好一些,而且不怀好意或极力利用自己的行销能力来证明他的说法。哦,我当然比Microsoft好不了哪里去,但他是正确的。Linux在很多方面都不尽令人满意,如果不是,那现在大多数用户就不会把它抛在一边不用。一个简单的事实是Linux对于一小部分人是合适的,即那些能忍受它奇怪特性的人。这部分人有两种:开发人员和Linux发烧友。“Linux发烧友”是一种含糊的说法,但我们能进一步的指出这群发烧友的少数几个特征。rnrn最简单的特征就是如果你现在仍不知道Linux是否适合你,Linux可能真的就不适合你。rnrnLinux不适合多数人的最主要问题是简单的:大多数人并不在意使用的操作系统,没有人真的对使用BSD型的多线程应用程序感到激动;他们在使用电子表格程序输入数据的时候,而后台正在计算(原理实际上是一样的,但没人在意;它只是完成了,如此而已)。电子表格程序不是IBM-PC上的DOS,也不是DOS在几百万桌面系统上的翻版,它是Lotus 1-2-3和WordPerfect(及后来的Windows上的程序)。这里有一个决定性的观点:运行一个另类操作系统可能很酷,但你确实不必为想让操作系统做什么而操心--运行哪个应用程序。这包括游戏,字处理,多线程,帐户处理等等。不过操作系统的绝大部分市场还是集中在Windows,而不是Linux,最大的市场往往能吸引最好的应用程序。rnrn迄今为止,一些Linux上的应用程序在和Windows中的类似程序竞争(如:GIMP)。但Linux上没有哪个应用程序能像在Windows上那样被普遍使用(是的,我忽略了TeX-如果平均100人中,有3人知道TeX是什么就已经很幸运了,知道如何使用它的人就更少了。你会发现其它的应用程序比这个结果也好不了那里去)。所以很难从纯粹软件的观点找个理由去使用Linux,而不使用Windows。你会认为Mail,Webervices,News之类的服务器程序是Linux的强项。“啊哈”,你说。“我用这些程序,Linux表现得很出色”。你仍然错了,Linux的确在这些应用上做得很好,Linux开放源代码的天性当然不会伤害这些可用性(如:Apache)。但是在一个生产环境里,其它的Unix甚至是免费的Unix通常是首选。rnrn对于Linux,因为它的“whitewater”开发模式使得每个人都可以开发它(与BSD截然不同,BSD有专门的开发队伍支持),而且那些糟糕的文档让人发狂。“whitewater”开发模式(也被认为是“集市”,出自Ericymond's《大教堂与集市》)更容易写出不稳定的代码。在“whitewater”或“集市”里,你可以发行糟糕的代码,让这些代码表面上看起来像是在为你工作(实际上这只是在骗人),然后可能就会有其他的人来修补它。BSD的“大教堂”开发模式与Linux的“whitewater”开发模式形成鲜明对照,在BSD里代码是稳定的,而且bug尽可能的少。FreeBSD有同样的效率和性能,而且它有专门的开发人员,这就使它远离一般的公众都可以参与开发,使得它更稳定。rnrn当然,如果你是开发人员,而且愿意走在“流血”边缘--Linux可能很适合你。我一直都用Linux(真的),我能用三倍的可利用时间(大约200天)和Linux在一起(现在影响我的首要因素是电,电力供应总是和我的可利用时间闹别扭)。另外,我的行为常常超出我的期待。如果你过去使用Unix,Linux的免费和自由的天性也可能对你有吸引。注意Linux,尽管价格免费,但不是使用上的免费--另一方面需要时间投资。Linux文档可能质量不一。有时即使一个解决办法被清晰的解释时,它却在不合适的地方解释。rnrn从统计学的角度看上面所说,Linux适合一小部分用户,这意味着Linux上的开发人员有一个很有限的市场,限制了Linux的广泛应用,这是一个自我消费的过程。即使对开发人员来说,Linux无疑还有缺点。它在某种程度上趋向于跟踪最新和最伟大的思想。如果你试图呆在“流血”边缘,那要很谨慎……它能毁了你。跟随最新的技术,意味着呆在那些未经测试的技术上。人们总是诱惑不住去依赖那些新开发出来的特性,这意味着你已经被卷入Linux,或者你在等待其他的Unix人员去开发程序。以我的观点,这违背了Unix的哲学,如果你是这些新特性的开发人员,那很好。总之,除非你被卷入到开发新技术中,否则就没有必要去尝试新技术。(如果你真的是这样的人的话,我真的认为你没必要读这篇文章,立即停止阅读。)如果这些新技术与你有关,而且你想在跨平台,请再次考虑FreeBSD。BSD对Linux来说可能有点过时,但是过时的事物往往容易得到在各种平台上广泛运行的能力。 论坛

没有更多推荐了,返回首页