【FCon上海】与行业领袖共话AI大模型、数字化风控等前沿技术。 了解详情
写点什么

为什么配置模式令人抓狂?尝试用编程语言来写吧

  • 2020-04-29
  • 本文字数:4317 字

    阅读完需:约 14 分钟

为什么配置模式令人抓狂?尝试用编程语言来写吧

AI 大模型超全落地场景&金融应用实践,8 月 16 - 19 日 FCon x AICon 大会联诀来袭、干货翻倍!

本文将试着解释为什么大多数配置格式用起来都不太舒服,作者建议大家尝试使用一门真正的编程语言(例如,像 Python 这样的通用编程语言)来编写配置,通常这是一种可行的选择,且使用过程更感愉悦。


大多数现代配置格式都很糟糕

本节,我主要针对 JSON/YAML/TOML/ini 文件,这是我遇到过最常见的配置格式。


我们暂将这种配置称为常见配置(如果有更好的名字,欢迎在评论中留言,谢谢)。


大家可能遇到过如下情况:



例如,虽然 YAML 在理论上支持重用/引用配置(他们称之为),但有些软件(如Github Actions)却并不支持。通常,开发者无法重用配置的一部分,必须复制粘贴。


  • .gitconfig 使用一个自定义语法来合并这些配置

  • 不能包含任何逻辑


很多人认为这是一种积极的做法,但我认为,如果不能定义临时变量、辅助函数、替换字符串或连接列表,那就有点差劲。变通方法(如果有的话)通常也不好用,因为它们额外增加了认知开销。于是,出现了一批重新发明的编程语言:



此外,他们有自己的一套函数来处理变量。你得为此学习一门从来都未曾想过要学习的新语言。


  • 范围

  • 例如,在 Github 操作中有几个针对于env指令的自定义作用域。

  • 控制流

  • for 循环:构建矩阵和“排除”总是让人头疼不已

  • if 语句:例如,CircleCI 中的when

  • 无法被校验。可以校验配置语法本身(例如,检查 JSON 串的正确性),但无法做语义检查。这是因为在配置文件中没有逻辑。通常情况下,你必须编写一个辅助程序来检查配置,并在传递给程序之前调用。很少有程序会遇到这个问题,通常,使用简单的类型系统就可以发现程序中的细小错误。

  • YAML 的隐式转换和可移植性问题非常突出。这一点已经饱受非议,所以在此只提供一个相关链接,供感兴趣的读者自行了解:“YAML:可能没那么好


总结:我们在花时间学习没什么用处的语法,而不是在富有成效地完成工作

解决方法

当遇到这些问题时会出现什么情况呢?通常最终会使用一种“真正的”(即通用的、图灵完备的)编程语言来解决问题:


  • 编写一个过滤自定义注释语法的程序;

  • 编写一个合并配置或使用模板引擎的程序;

  • 编写一个“evaluate”配置的程序,在此过程中,常常需要为一门简单的函数式语言重新实现一个解释器

  • 编写一个校验配置的程序。


在大多数情况下,它就是类型检查的样板文件。你不仅要处理已解决的问题,而且得到的错误消息质量也不高,所有这些事情都会分散你在主要目标上的注意力。

使用一门真正的编程语言

其思想是用目标编程语言编写配置。这里我将使用 Python,但是,这一思想也适用于其他语言,只要足够动态即可(比如 Javascript、Ruby 等等)。这样,只需 import 或 evaluate 配置文件就可完成。


一个小例子:


config.py


from typing import NamedTupleclass Person(NamedTuple):    name: str    age: intPEOPLE = [    Person('Ann'  , 22),    Person('Roger', 15),    Person('Judy' , 49),]
复制代码


使用这个配置(如果你想知道为什么我使用 exec 而不是 import,请看看这个回复):


from pathlib import Pathconfig = {}exec(Path('config.py').read_text(), config)people = config['PEOPLE']print(people)
复制代码


[Person(name='Ann', age=22), Person(name='Roger', age=15), Person(name='Judy', age=49)]
复制代码


我觉得它很简洁。让我们看看如何解决上文所述问题:


  • 注释:很明显,不需赘述

  • 包含:很简单,使用 import


你甚至可以 import 正在配置的包,可以针对配置定义一个 DSL,它将在配置文件中进行导入和使用。


逻辑


你可以使用语言的语法和库。例如,单独使用像pathlib之类的可以节省大量重复配置。


当然,随意乱用可能会让人难以理解。就我个人而言,我宁愿接受语言被滥用,也不愿受限制。


校验


你可以将逻辑校验保留在配置中,以便在加载时进行检查。成熟的静态分析工具(如 JS flow、eslint、pylint、mypy)对此可以有所帮助。

缺点

互操作性


如果程序是用 Python 编写的,那没什么问题。但如果不是,或者稍后将以另一种语言(比如 C++之类的编译语言)重写它,该怎么办呢?


将来,软件是否无需解释器即可运行?现代的 FFI 很是繁琐,链接配置将相当棘手。


我们特别以 Python 为例,大多数现代 OS 发行版中都有它。那么,你可以按以下方式来做:


  1. 使 Python 配置可执行

  2. 在 main() 函数中构建配置,转换为 JSON 串并输出到 stdout


由于 Python 是动态的,所以无需样板文件即可执行此步骤。


  1. 在代码中执行 Python 配置(比如,使用 popen()),读取原生的 JSON 串并予以处理。仍然需要手动在代码中将配置反序列化,但这至少不像只使用 JSON 并手动编辑它那么糟。


通用编程语言很难推理


这多少有点主观。就我个人而言,我更有可能被一个过于冗长的普通文本配置搞得不知所措,我一直都更喜欢简洁的 DSL。其中一个重要因素是代码风格:我确信你可以使配置文件在几乎任何编程语言中都具有可读性,甚至根本不熟悉该语言的人也能够看得懂,最大的问题可能是安全性和终止检查。


安全性


例如,如果配置可以执行任意代码,那么它可能会窃取密码、格式化硬盘等。


如果配置是由你不信任的第三方提供的,那么,我认为普通文本配置更安全。然而,通常并非如此,一般都是用户自己控制自己的配置。


此外,也可以通过沙箱解决这一问题,是否值得这样做取决于项目的性质,但是如果你使用像 CI executor 之类的东西,无论如何都需要它。


另外要注意,使用普通文本的配置格式不一定能躲过这些麻烦。参见“YAML:一般并不安全”。


终止检查


即使不关心安全性,也不希望配置会挂起程序。我个人从来没有遇到过这样的问题,但这里有一些潜在的解决方法可供参考:


  • 为加载配置指定显式的超时时间

  • 有些语言能够有所帮助,例如,Bazel Skylark


有人知道在通用语言中检查终止的保守的静态分析工具的例子吗?注意,使用普通文本配置并不意味着它不会无限循环,参阅"Accidentally Turing complete".


配置会花很多时间去 evaluate,虽然技术上需要在有限的时间内完成,请参阅"Why Dhall advertises the absence of Turing-completeness"。虽然Ackermann函数是一个人为设计的例子,但它表明如果你真的关心恶意输入,那么无论如何都要做沙箱处理。

为什么是 Python?

我发现出于以下原因,大家都特别喜欢用 Python 来编写配置文件:


  • 几乎所有的现代操作系统中都有 Python

  • 大家认为 Python 语法很简单(不是件坏事),所以 Python 配置很有可能不会比普通配置更难理解

  • 数据类、函数和生成器构成了精简的 DSL 的基础

  • 类型标注同时用作文档和校验


其实,你可以在大多数现代编程语言中获得类似的愉快体验(只要它们足够动态)。

还有谁在做这件事?

一些项目允许用代码作为配置:


  • Webpack,Web 模块打包器,使用 Javascript 作为配置

  • setuptools,安装 Python 包的标准方法


允许同时使用 setup.cfg 和 setup.py 文件。这样的话,如果你不能以普通文本配置完成你的需求,那么可以在 setup.py 中进行调整,从而使你可以在声明式和灵活性之间取得平衡。



使用一个python文件配置输出。


  • Emacs:大家都知道使用 Elisp 进行它的配置


虽然我一点也不喜欢 Elisp,但它确实使 Emacs 非常灵活,可以实现你想要的任何配置。另一方面,如果你曾经读过其他人的 Emacs 设置,那么你可以发现,当你允许使用通用语言进行配置时,有些事情可能很难操控。



有些语言是专门为配置而设计的:



虽然为了确保终止检查和确定性而特意对 Bazel 进行了限制,但是配置 Bazel 比我使用过的任何其他构建系统都要愉快得多。


  • Meson构建系统:借鉴 Python 的语法

  • Nix:专门为 Nix 包管理器设计的语言


虽然弄一门全新的语言让人感觉有点大材小用,但是仍然好过用普通文本来进行配置。


  • Dhall:专门为配置文件设计的语言


Dhall 宣称自己是“JSON +函数+类型+导入”。的确,它看起来很棒,解决了我上文列出的大部分问题。



它们之间的具体区别,请参阅其他配置语言间的比较


这种语言的缺点是还没有被广泛使用。如果你没有绑定目标语言,那么需要二次解析 JSON。


但是,至少它能使你可以愉快地编写配置。


然而,如果你的程序是用 Javascript 编写的,并且不与其他语言交互,那么为什么不直接用 Javascript 编写配置呢?

如果一个也不选要怎么办?

在使用普通文本配置的时候,我找到了一些减少那些问题的方法:


尽量少写配置文件


这通常适用于 CI 流水线配置(例如 Gitlab、Circle、Github Actions)或 Dockerfiles。通常情况下,这样的配置使用了大量的 shell 命令,如果不逐行复制,就不可能在本地运行。


是的,的确也有调试的方法,但是它们的反馈周期非常慢。


  • 使用更适合设置本地虚拟环境的工具,如tox-dev/tox

  • 更多地采用 helper shell 脚本,并从你的流水线中调用它们


这多少有点令人沮丧,因为它引入了间接而分散的代码。但是,同时它也是一个优势,你可以剥离(例如 shellcheck)你的流水线脚本,使它更容易在本地运行。有时,如果你的流水线很短,你可以视情况做出自己的判断。让 CI 只负责为你设置 VM/容器、缓存依赖项和发布构件。


生成而不是手动编写


这样做的缺点是,相比于手工编辑而言,生成的配置可能会更分散。


你可以添加警告注释,提醒该配置是自动生成的,并附上生成器的链接,同时将配置文件设置为只读,以防止有人手动编辑。


此外,如果你正在实行 CI,可以将一致性检查作为流水线本身的一部分。

参考资料


总体上,我同意这一观点,但是仍然有些情况是不适用于标记的。


它也容易泄露机密(密钥、令牌、密码)——无论是在你的 shell 历史记录中还是通过 ps 都可以看到。


  • Xmonad:配置文件可执行文件


一个有趣的方法,但不一定总是可行的,例如,你可能没有安装编译器。


  • Mage:以 Go 编写用于 makefile 的工具

  • Dhall wiki:可编程的配置文件

  • 扩展语言的演变:Lua 的历史——显然 Lua 已经开始成为配置语言

  • Cue:定义、生成和验证数据的语言


我在网站上找了很久才找到一个代码例子,就在这里


最后的问题

之于现在为什么 YAML 成为一个主流选择,我还没有答案。我相信,Ansible/CircleCI 或者 Github Actions 都出自于非常优秀的工程师之手,他们应该考虑过使用 YAML 的利弊。


欢迎大家在评论区留言,分享你在做配置时经受过的痛苦,以及是如何解决它的。


原文链接:Your configs suck? Try a real programming language.


2020-04-29 16:359209
用户头像
赵钰莹 InfoQ 主编

发布了 880 篇内容, 共 619.5 次阅读, 收获喜欢 2674 次。

关注

评论 3 条评论

发布
用户头像
这不可能吧,写配置都上 py?
2020-06-21 12:21
回复
用户头像
其实是个代码化选型的问题,一般来说这些场景中DSL强于通用编程语言强于标识性语言
2020-05-10 00:35
回复
用户头像
怎么感觉有点文不对题?
2020-04-30 08:03
回复
没有更多了
发现更多内容

介绍一下链游GameFi的玩法和类型有哪些

区块链开发团队DappNetWork

精彩收官!北京中医药大学第五届“和鲸杯”医学数据分析大赛落幕

ModelWhale

人工智能 机器学习 数据分析 数据科学竞赛

【YashanDB知识库】PHP使用ODBC使用数据库绑定参数功能异常

YashanDB

数据库系统 yashandb 崖山数据库

打破数据孤岛,驱动车企增长--数造科技网联大数据平台实战解析

数造万象

车联网 数字化 案例分享 汽车 制造业

win版IObit Driver Booster Pro(驱动管理工具) v11.5.0.85便携版

iMac小白

win版Gihosoft TubeGet Pro(YouTube 视频下载工具) v9.3.88 专业激活版

iMac小白

2024 AIIA先锋案例 | “AI Infra”专项征集工作正式启动

中国信通院AI Infra工作组

和鲸科技执行总裁殷自强:面向空间数据协同分析场景的模型生命周期管理方法

ModelWhale

人工智能 大模型 生命周期管理 地球科学

会议通知 | 大模型算力平台标准研讨会即将召开

中国信通院AI Infra工作组

达梦公开上市,首日收盘市值达182亿;Oracle云上将支持Oracle Database@Google Cloud

NineData

oracle Google 国产数据库 达梦 数据库上市

Vellum for Mac——打造专业级3D渲染的利器

影影绰绰一往直前

Vellum下载 Vellum for mac Vellum激活 Vellum破解版

天猫搜索API返回值解析:关键字搜索在电商市场趋势预测中的作用

技术冰糖葫芦

API Explorer API 安全 API 文档 API 开发 pinduoduo API

观测云产品更新 | BPF 网络日志、智能监控、告警策略等

观测云

win版IObit Driver Booster Pro(驱动更新软件) v11.5.0.85 特别版

iMac小白

基础大模型纵横天下,垂直大模型各领风骚,专注一域称尊

松子(李博源)

大数据 大模型 agent 职场影响

数据管理优化,支持从 API 和对象存储更新数据集|ModelWhale 版本更新

ModelWhale

人工智能 对象存储 模型训练 数据集 API

和鲸科技携手浙江大学地球科学学院,助推地球科学研究范式变革

ModelWhale

战略合作 地球科学 浙江大学 重点实验室

win版R-Wipe & Clean(磁盘清理) v20.0.2461 激活版

iMac小白

关于个人信息安全,这68项标准不容错过!(附下载)

极盾科技

数据安全

Invisor for Mac——轻松掌控Mac健康的守护者

影影绰绰一往直前

Invisor下载 Invisor for mac Invisor 破解版 Invisor激活版

介绍一下链游GameFi的玩法和类型有哪些

区块链开发团队DappNetWork

链游Gamefi,NFT游戏都有什么特点或优势,能吸引玩家呢

区块链开发团队DappNetWork

链游Gamefi,NFT游戏都有什么特点或优势,能吸引玩家呢

区块链开发团队DappNetWork

win版PanoramaStudio Pro(全景图像制作工具) v4.0.6.413 激活版

iMac小白

win版GoodSync(文件同步备份工具) v12.6.8.8便携版

iMac小白

win版HD Video Converter Factory Pro(高清视频转换器) v27.6特别版

iMac小白

探索国产化项目管理工具:6款顶尖系统全面对比

易成管理学

项目管理 系统 国产

拆解元宇宙:什么是链游gamefi,nft游戏

区块链开发团队DappNetWork

DAPP系统开发 元宇宙游戏 区块链开发DAPP开发 区块链kaifa链游开发 链游开发dapp开发

主动元数据平台详解(下):BIG 十一问,详解定位、对接、血缘保鲜等问题

Aloudata

数据管理 数据血缘 主动元数据

链游gamefi,NFT游戏经济模型定制设计开发

区块链开发团队DappNetWork

为什么配置模式令人抓狂?尝试用编程语言来写吧_语言 & 开发_佚名_InfoQ精选文章