跳到主要内容

· 阅读需 8 分钟
Junlin Zhou

翻译自这篇文章

我最近接触到许多项目将 JSON 用作配置文件。我认为这不是一个好主意。

JSON 从设计之初就不是用于做配置文件的,这也不是它擅长的领域。JSON 的目标是 "轻量级数据交换格式", 同时具有 "易于人类读写", "易于代码解析和生成" 的特点。它在对 "人类而言的便利性" 和 "对机器而言的便利性" 之间取得了较好的平衡, 在许多应用场景下都是比 XML 更好的替代方案。

然而,将 JSON 用于其他目的有点类似于说 "嘿,这把锤子非常适合钉钉子!我喜欢它!为什么不用它来拧螺丝!" 当然它不是完全不能用,只是不合适做这样的工作。

目前为止,将 JSON 用作其它用途最大的问题在于不能在 JSON 文件中添加注释。某些特定的 JSON 解析器支持在 JSON 中添加注释,但是绝大部分的解析器都不支持。JSON 的发明者 Douglas Crockford 声称 JSON 最开始是支持注释的,然而由于一些原因,他特意移除了对注释的支持。想要深入研究的朋友可以看这里

我们在写配置文件时经常会遇到需要添加注释的场景。例如解释为什么将配置项设置为当前的值,添加一些助记符或是注意事项,对于错误配置的警告,在文件中保存一份基础的 changelog,又或单纯是在debug时需要注释掉一些配置项。

一个可行的解决方法是将原本的数据存储在一个 object 中,在这个 object 中通过两个条目分别存储数据和注释。例如原本的配置文件如下:

{
"config_name": "config_value"
}

修改后变成如下形式:

{
"config_name": {
"actual_data": "config_value",
"comment": "a comment"
}
}

但是在我看来这种方式丑的压批。

还有一些人指出可以通过 commit log 的形式来实现注释 (译者:不清楚他这里指的是不是 git commit log,如果是的话把这个当作注释方式好像十分难用吧?),但是又有几个人会去细读 commit history?

一些基于 JSON 进行扩展的格式,例如 JSON5HjsonHOCON,以及一小部分 JSON 解析器添加了对注释的支持。这很实用,但这些都属于 JSON 的变种,因此不在本篇的讨论范围之内。

同时我也发现手工编辑 JSON 的用户体验不是那么友好:你得留意行尾是否要添加逗号,得了解用不用引号对含义的影响,同时 JSON 也不支持字符串内换行。这些特性对于 "轻量级数据交换格式" 而言不是坏事,但是对于编辑配置文件这件事来说却不是那么可爱。总的来说,将 JSON 用作配置文件虽然可行,但并不优雅。

MediaWiki 的新扩展系统促使我写下这篇文章。旧的系统通过 PHP 文件来挂接核心代码,加载所需的依赖项等。新系统通过 JSON 文件实现这些配置。这样的更新损失了 PHP 那种能够巧妙解决与其他插件兼容性的能力。 (这段没看懂)

同时它也带来了更多实现复杂度。旧的系统在引入配置文件时仅仅需要一行代码:

require('plugin/foo/plugin.php');

而新系统却需要对 JSON 文件的内容进行解析。这在提升实现复杂度的同时,也提高了 debug 的难度。 (这段不太赞同,XML 作为配置文件,同样要进行解析,这不是 JSON 的问题。)

使用 JSON 文件存储基本元数据是可行的(更容易解析以及在网站上显示),但使用它来描述代码的工作方式对我来说是滥用 DC(Declarative configuration ,声明性配置)。毕竟,这是代码的工作。

许多人问我那到底该用什么(来做配置文件),这其实是个很复杂的问题,关系到你程序的应用场景、编程语言、库环境甚至一些社交因素(?)。最好的回答可能就是“找到能符合你需求的最简单的方案”。

有一些 JSON 的扩展格式更适合于人类进行编辑,例如 JSON5、Hjson 和 HOCON。这些看起来都是普通JSON的合理升级,尽管我自己没有使用过它们。特别是 JSON5 似乎是一个不错的选择,因为它对 JSON 的改动最少。我不能给出关于这些扩展格式的建议,因为我没有所有的格式进行深入的比较。只是看一眼格式规范并不能发现潜在的缺点(YAML 就是一个很好的例子)。我没有时间或是兴趣对所有替代方案进行全面深入的审查。

后记

这是我第一次做需要发布到网上的比较正式的翻译工作。虽然最早自己在读 paper 的时候因为英语生疏,也会边读边翻译一些,但是毕竟那是翻译给自己看的,只要自己能看懂就行了,也不用追求什么语句通顺之类的。然而要发布出来的文章不一样,至少要保证大多数读者能够看得懂。

整篇翻完回过头看看,还是有很多生硬似机翻的地方,主要原因可能还是自己的表达能力不够。翻译技术文章在我看来是个吃力不讨好的活,翻的再好也不如直接读原文来的清晰。至于为什么要做这样的事情, 我想有时间单独写一篇谈一谈。目前来看,就权当是对于自己表达能力的锻炼吧。

· 阅读需 1 分钟
Junlin Zhou

最近开始接触 Linux 运维的工作,第一件事情就是看看系统中跑了多少服务。

集群用的是 CentOS 7,可以通过 bash systemctl list-unit-files 这个命令查看所有服务,敲下回车后打印出来这么一堆玩应儿:

services

service 的 disabledenabled 状态都好理解,static 是个啥?在不存在的网站上一顿查找,找到如下这番解释:

"static" means "enabled because something else wants it". Think by analogy to pacman's package install reasons:

  • enabled :: explicitly installed
  • static :: installed as dependency
  • disabled :: not installed

意思是,状态为 static 的服务,是作为别的服务的依赖而存在。

· 阅读需 1 分钟
Junlin Zhou

org.springframework.data.annotation.Id

org.springframework.data.annotation.Id 是 Spring 定义的 annotation,用来支持 "没有像 JPA 那样的持久化 API" 的非关系型数据库或是框架的持久化,因此它常被用于其它 spring-data 项目,例如 spring-data-mongodb 和 spring-data-solr 等。

javax.persistence.Id

javax.persistence.Id 是由 JPA 定义的 annotation,JPA 仅适用于关系数据的管理。

Ref

· 阅读需 1 分钟
Junlin Zhou

If you installed Postgres from homebrew, the default user postgres isn't automatically created, you need to run following command in your terminal:

/Applications/Postgres.app/Contents/Versions/9.*/bin/createuser -s postgres

· 阅读需 1 分钟
Junlin Zhou

通过 ubuntucentos 的源安装的 vim 版本较老(好像是7.4.x)

8.0 之后的 vim,官网推荐的安装方式是从 git clone 源码编译

默认编译出来的 vim 是没有 clipboard support 的,无法通过寄存器与系统剪切板进行交互

在编译时增加 clip board support 需要的最小依赖为 xorg header filesx11 dbus

https://packages.ubuntu.com 里一通搜索发现 xorg header files 是在 libx11-dev 这个包里,而 x11 dbusdbus-x11

因此整个编译过程如下:

sudo apt-get install libx11-dev dbus-x11
./configure --with-features=huge
make
sudo make install