YAML と JSON と TOML — どの設定フォーマットを使えばいいのか?
YAML、JSON、TOML はすべて設定を保存します。これらは互換性を持ちません。YAML は国コードを静黙的にブール値に変換します。JSON はコメントを許容しません。TOML はあなたのチームで誰も使ったことのないものです。正しいものを選ぶ方法を紹介します。
2015年に、Ansibleのプレイブックがこの行によって破綻した。
country: NO
設定はエラーなく読み込まれた。パーサーからのコンプレインはなかったが。 country 文字列に設定されていなかった。 "NO"。それは falseに設定されていた。 NO YAML 1.1では、 yes, on, off, yと、 nは論理値である。
これはノルウェー問題であり、何年も間違った設定を静かに腐敗させている。
同じ設定、3つの方法
これはYAMLのバグ報告ではありません。これは、あなたがこれからする決定のためのフレームワークです:次の設定ファイルにYAML、JSON、またはTOMLを使用するか?それぞれには実際のトレードオフがあり、「エコシステムが使っているものを使うだけ」の答えは常に適用されません。
ヤム
# App configuration
app:
name: my-api
port: 8080
debug: false
database:
host: localhost
port: 5432
name: mydb
pool_size: 10
logging:
level: info
format: json
outputs:
- stdout
- /var/log/app.log
翻訳
{
"app": {
"name": "my-api",
"port": 8080,
"debug": false
},
"database": {
"host": "localhost",
"port": 5432,
"name": "mydb",
"pool_size": 10
},
"logging": {
"level": "info",
"format": "json",
"outputs": [
"stdout",
"/var/log/app.log"
]
}
}
トムル
# App configuration
[app]
name = "my-api"
port = 8080
debug = false
[database]
host = "localhost"
port = 5432
name = "mydb"
pool_size = 10
[logging]
level = "info"
format = "json"
outputs = ["stdout", "/var/log/app.log"]
バケーション以前、同じアプリケーションの設定をすべての3つのフォーマットで書いたものを見てください。
YAMLは最もコンパクトだが、構文的に最も負担がある。JSONは最も冗長だが、最も明確である。TOMLは中間にある:YAMLの暗黙的な型変換を避けて読みやすい。
YAMLはCI/CDパイプライン(GitHub Actions、GitLab CI、CircleCI)、Kubernetesマニフェスト、Ansibleプレイブック、およびほとんどの開発ツールのデフォルト選択肢である。あなたはYAMLを選ぶのではなく、YAMLが選んでくれる。
危険な特徴、公式に記載されている:
1. ボーリアン問題(ノルウェー問題)
YAML 1.1 — ほとんどのパーサーが実際に実装している仕様 — は、多くの文字列を論理値として扱う。
# YAML 1.1 boolean values (all parsed as true or false)
enabled: yes # true
disabled: no # false
active: on # true
paused: off # false
valid: true # true
invalid: false # false
# The Norway Problem in practice:
country_codes:
NO: Norway # Key "NO" is fine, but value "NO" becomes false
SE: Sweden
YES: Yemen # "YES" also becomes true
# The fix: quote your strings
country_codes:
NO: "Norway"
SE: "Sweden"
YAML 1.2(2009年にリリース)はこれを修正した — しかしそのうち true と false のみが論理値である。問題は、PyYAMLが1.2の振る舞いを完全に採用するまで2021年のバージョン6.0までだったこと、そしてGoのポピュラーな gopkg.in/yaml.v2 は2024年現在まで1.1のセマンティクスを使用している。RubyのPsych 4.0未満または6.0以前のPyYAMLを使用している場合は1.1にいる。
2. タブはあなたの設定を殺す
YAMLはタブ文字をインデントとして許可していない。スペースのみが有効である。あなたのエディタはタブとスペースを同じように表示するかもしれないが、ファイルが正しいように見える場合でも、YAMLは次のエラーを投げてしまう。
yaml.scanner.ScannerError: while scanning a block mapping
found character '\t' that cannot start any token
これは若手開発者が自分のキャリアを選択を疑問視させる原因となるエラーである。YAMLファイルでエディタをタブをスペースに展開するように設定してください。すべてのエディタはこれをサポートしているが、すべてのエディタがデフォルトでそうしているわけではない。
3. マルチライン文字列は明らかではない
# | (literal block): preserves newlines exactly
description: |
Line one.
Line two.
Line three.
# Result: "Line one.\nLine two.\nLine three.\n"
# > (folded block): folds newlines into spaces
short_desc: >
This will all become
one long line.
# Result: "This will all become one long line.\n"
# Trailing newlines: | adds one, |+ adds all, |- strips them all
desc_stripped: |-
No trailing newline.
誰もこれを暗記しない。私が使っているメモリックは: | は改行のように見え、 > は何かが圧縮されたように見える。3年経ってもまだ混乱している。
YAMLが勝つ場合
- Kubernetesマニフェスト、GitHub Actionsワークフロー、またはAnsibleプレイブックを書いている場合、選択肢はありません。
- あなたの設定には、非自明な値を説明するコメントが多く含まれている。YAMLはインラインコメントをサポートしており、JSONおよびTOMLもサポートしているが、コメントが多めの設定ファイルにはYAMLが最も自然に感じられる。
- あなたのデータには、TOMLのフラットテーブルで見ると悪く見えるような深層構造がある。
- チームがすでに熟練しており、パイプラインにリンター(yamllint)がある。
JSON:単純で信頼性の高いワークホース
JSONはデータ交換フォーマットとして設計されたものであり、設定ファイルとしての用途はなかった。ダグラス・クロックフォードはコメントを意図的に省いた。彼の主張は、コメントがパーサーによって異なるディレクティブに使われるためである。そのため package.json にはコメントがなく、 tsconfig.json は技術的にはJSONコメント(JSONC)であり、ほとんどのJSONパーサーはこれをサポートしていない。
JSONが設定ファイルにとっての本質的な問題は:
- コメントがない。 なぜ
"maxRetries": 3が5でないことを説明できない。TODOを残すことができず、フィールドを廃止としてマークすることができない。これは、著者が亡くなった後も生き残る設定ファイルにとって本当に痛い問題である。 - 終端のコンマがない。 配列にアイテムを追加するには、前の行を変更してコンマを追加しなければならない。すべてのJSONの差分は2行の変更になる。すべてのマージコンフリクトは、必要以上に悪化する。
- ネストされたデータに対して冗長である。 6行のブレースとブレケットが、YAMLが3行のインデントで行うものに匹敵する。
- すべての数値は同じタイプである。 JSONは整数と浮動小数点数を区別しない。
1と1.0はどちらも単なる数値であり、あなたの言語がそれらをデシリアライズする方法はパーサーによって決まる。
しかし、JSONの予測可能性もその主な特徴である。すべての言語にはJSONパーサーがある。仕様は明確であり、暗黙的な型変換はない。文字列は常に文字列である — "yes" は決して静かに trueに変換されない。プログラムでJSON設定を検証する必要がある場合、 IO Tools’ JSON Formatter は、プロダクションに到達する前に構文エラーを検出できる — 手動で設定を編集した人が終端のコンマを忘れた場合に特に役立つ。
JSONが勝つ場合
- 複数の言語/サービスが消費するAPI応答または設定ファイル。JSONは普遍的であり、TOMLのサポートはいくつかのエコシステムで不十分である。
- 厳格な型保証が必要。JSONスキーマ検証は成熟しており、広くサポートされており、よく使われている(VS Codeは設定自動補完に使用している)。
- 設定はマシンによって生成されている。マシンが手動でJSONを書くことは避けるが、マシンはそれを生成するのに十分である。
- Node.jsまたはフロントエンドJavaScriptで作業している場合。
TOML:意見をもつ設定、正しく実装されたもの
TOML(Tomの明白で最小の言語)は、Tom Preston-Werner、GitHubの共同創業者が設定ファイルのために特別に作成した。2021年1月にv1.0を達成した。それはRustの Cargo.toml、Pythonの pyproject.toml、およびHugo静的サイトのデフォルトフォーマットである。
TOMLの設計哲学:型は明示的で、構造は可能な限りフラットで、そして任意の設定値を書くためにちょうど一つの明白な方法があるべきである。
# Types are unambiguous in TOML
name = "my-app" # string: always quoted
port = 8080 # integer
threshold = 3.14 # float
enabled = true # boolean: only true/false, no yes/no
created = 2024-01-15 # date: native type
tags = ["api", "prod"] # array
# "yes" is just a string. Always.
country = "NO" # string "NO", no boolean nonsense
粗いエッジ:
- テーブルの配列構文は本当に不自然である。
[[products]]と[products.details]は見た目が似ているが、まったく異なる振る舞いをする。仕様は意味があるが、視覚的な違いはない。 - 深層ネストが冗長になる。 YAMLが5行のインデントで行うものに対して、TOMLは3つのセクションヘッダーで行う。3レベル以上のネストの設定では、TOMLが間違ったツールに感じるようになる。
- パーサーの可用性。 TOMLパーサーはすべての主要言語に存在するが、仕様の適合性は異なる。 TOML適合性テストセット は定期的にエッジケースを明らかにする。JSONパーサーは、使用量の規模で何十倍もテストされている。
- チームの慣れ。 TOMLをRustまたはPythonエコシステム以外で使用する場合、少なくとも1人のチームメンバーが「これは何ですか?」というPRを開くことを期待する。
TOMLが勝つ場合
- Rustプロジェクト —
Cargo.tomlは標準であり、ツールは優れている。 - Pythonプロジェクトの設定(Black、Ruff、mypy、pytestなど)を使用する場合
pyproject.toml(PEP 518) — これは現在、ツール設定の標準である。 - YAMLのインデント感度がリスクになるようなシンプルでフラットな設定。
- あなたがネイティブの日時サポートを必要とする場合。
迅速な決定ガイド
- Kubernetes / CI/CDパイプライン / Ansible? YAML。選択肢がない。
- 複数のサービスに消費されるAPI設定? JSON。
- Rustプロジェクト? TOML(Cargo.tomlの慣例)。
- Pythonプロジェクトの設定(リント、フォーマッタ、ビルドツール)? TOML(pyproject.tomlは現在の標準)。
- 静的サイト設定(Hugo、Zola)? TOMLだが、これらは通常すべての3つをサポートしている。
- Node.jsプロジェクトの設定? JSON(package.jsonエコシステム)または、コメントが必要な場合はYAML。
- 人間が頻繁に編集し、ノートを残す必要がある? YAMLまたはTOML(どちらもコメントをサポート)。JSONではない。
- 厳格な型安全性とスキーマ検証が必要? JSON + JSONスキーマ。
新プロジェクトの誠実な答え:主な言語のエコシステムが期待するものを使用する。RustはTOMLを期待し、PythonツールはTOMLまたはYAMLを期待し、Node.jsはJSONを期待する。言語に依存しないものを書く場合、人間が編集する設定にはTOML、マシンが生成または消費する設定にはJSONが合理的なデフォルト分割である。
恵 スコアボードが到着しました!
スコアボード ゲームを追跡する楽しい方法です。すべてのデータはブラウザに保存されます。さらに多くの機能がまもなく登場します!
