Cofig with ini,xml,json,yaml,toml

23-08-29-config.md
TLDR: 选TOML类型

关于参数

众所周知, 写代码有的东西 可能会变

而 常用的方法有, 写死, 写死但是一个全局的变量, 接受环境变量, 接受命令行参数, 接受接口参数, 接受配置文件

对于 参数优先级

1
2
3
4
5
6
命令行参数(api参数)
命令行指定的配置文件
环境变量
本地配置文件(如果存在), (当前目录,当前project目录)
全局配置文件(如果存在), (当前用户根目录,PATH目录)
内置默认值

就python的cli程序而言

那么对于 命令行参数,有 argparse/click/自己解析argc,argv

环境变量 有 os.getenv()

内置默认值, 怎么写其实都行

那么本文主要关注的是, 配置文件

配置文件

同语言

对于python的配置文件, 其实完全可以用python来写, 也就是用同语言直接来写,同理ts的软件的配置可以用ts来写,

优点是,支持了复杂性,易读(本身是逻辑语言),而且如果本身用户也是 从编码层面使用会很方便

缺点是,对于简单的配置不必要,用户不需要学相应的语言,有些语言是编译语言, 而如果真的是这种情况,可能你更需要的是开发一个配置管理界面,而不是考虑配置文件格式?


而其它配置文件, 如果层级缺失, 当工程变大时, 多个配置项的交叉发生时,容易出现 “配置的表述” 和 “期望的逻辑” 之间的 不一致, 这个时候你还需要去理解工具的工作原理, 反而把本来只需要理解配置的工作扩大成理解工具了

比较

其实除了 同语言,其它都是”简单的配置文件”了, 而关于模块化,应该是工具关心的不是格式关心的?

  • 环境变量(1979)
  • ini(1981), initialization
    • https://en.wikipedia.org/wiki/INI_file
    • 其中wiki里 parser的部分可以看到不同parser的支持程度不同
    • 虽然有支持section nesting的parser, 但是 书写上还是 Key/Value的形式, 在书写上看不见层级
    • 另外虽然configparser提供了getboolean/getint/getfloat, 但实际上 直接读取还是字符串
  • xml(1996), Extensible Markup Language
    • https://en.wikipedia.org/wiki/XML
    • 层级!层级!层级!
    • 主要就是靠start-tag/end-tag
    • 而本质上还是没有类型规范
    • 同时还有 字符串转义的问题
  • json(2000), JavaScript Object Notation
    • https://en.wikipedia.org/wiki/JSON
    • 类型!类型!类型!
    • 从名字可以看出和js有关,而这关联性,让它的类型系统更明确了
    • 有了 (string,number,object(字典),array,boolean,null),同时python和其它语言也有支持的库
    • 而且从书写上讲, 上面的start-tag/end-tag需要重复的内容,这里书写上更简洁了
    • 然后不能注释,也是问题所在,虽然现在有jsonc可以写注释了,例如tsconfig.json中可以了,但是还没有变成默认标准
    • 同样,因为有了 花括号 双引号这些,你可以一定程度上多行写成一行
  • yaml(2001),yet another markup language
    • https://yaml.org/
    • 书写上可以比json少不少 可见字符,(花括号,双引号)
    • 类型上多了date/timestamp
    • 还提供了inheritance/reference, 的操作符号 &/*/<<
    • 然而经常被大家说的还是 yaml的类型, 单引号,双引号,无引号都可以是字符串, 然而如果有一天,一个人想把 版本号 3.10.3(字符串) 改成 3.10 那么这将是浮点类型 而不是字符串
    • 很依赖于缩进
  • toml(2013), Tom’s Obvious Minimal Language
    • https://toml.io/en/
    • 在yaml的类型上多了table
    • 比yaml的类型系统的书写更精确
    • 不依赖缩进,而层级可以自由选择是否tab,也可以链式写法
  • custom
    • proxychains
    • apt
    • nginx
    • 有自己的语法,和特殊的支持,有的因为历史原因,有的自己东西做大了可以自己实现解析器,而conf也可以是ini格式
- 环境变量 同语言 ini xml json yaml toml custom
层级支持 半支持 ?
类型系统 字符串 同语言 字符串 字符串 string,number,map,array,bool,null 比json多date,timestamp 比yaml多了table,而类型描述的书写更精确 ?
注释支持 ?
现有工具 os.getenv() 不需要额外工具 configparser xml json pyyaml tomllib ?
实际例子 http_proxy flask config,webpack.config.js desktop.ini,setup.ini pom.xml 前端配置,前端RESTFUL接口 docker compose,github actions,jenkins pyproject.toml /etc/proxychains.conf,/etc/apt/sources.list,/etc/nginx/sites-available/default
其它 - 非编译语言会采用 - - - 类型书写不够明确,引用感觉多余 - -

锐评

当一个配置文件提供层级,但是相关软件滥用层级时,不是配置文件的问题,是软件设计的问题

另外,当配置出错时,你的程序也应该提示配置错误会更好,而不是简单的炸掉

有的时候可能同时采取多个,例如同时支持命令行参数+环境变量+配置文件, 但配置文件就不要多个类型了,求求了

其实从功能上讲, json+注释+日期类型 就很理想了, yaml的 引用感觉太重了,到这种程度就还不如直接用your language,或者用户配置面板, 而除了功能以外,就是书写上了, toml 可以说即精确又小巧