JSON vs YAML vs TOML: 設定形式の6ヶ月間の本番運用レビュー

Programming tutorial - IT technology blog
Programming tutorial - IT technology blog

クイックスタート: 設定形式の選び方(5分で読めます)

多くのITエンジニアと同様に、私も設定ファイルの調整に countless hours を費やしてきました。JSON、YAML、TOMLの各選択肢は、それぞれシンプルさと明瞭さを約束します。しかし、実際にはその影響は大きく異なります。過去6ヶ月間、これらの形式を様々な本番システムに深く組み込む中で、それぞれの真価がどこにあるのかをより明確に理解することができました。

一目でわかる概要は次のとおりです。

  • JSON (JavaScript Object Notation): データ交換の標準形式。簡潔で遍在し、主に機械可読性が高いため、APIやウェブサービスに最適です。
  • YAML (YAML Ain’t Markup Language): 人間が読みやすい設定によく利用されます。インデントベースの構造とコメントのサポートにより、特にDevOps環境での設定ファイルに非常に価値があります。
  • TOML (Tom’s Obvious, Minimal Language): 設定のために特別に設計されており、人間が読みやすいことに重点が置かれています。明確でシンプルな構文のため、プロジェクトのマニフェストでよく見られます。

最小限の例

「アリス」というユーザーの簡単な設定が各形式でどのように表示されるかを見てみましょう。

JSONの例


{
  "user": {
    "name": "Alice",
    "age": 30,
    "is_active": true,
    "roles": ["admin", "editor"]
  }
}

YAMLの例


user:
  name: Alice
  age: 30
  is_active: true
  roles:
    - admin
    - editor

TOMLの例


[user]
name = "Alice"
age = 30
is_active = true
roles = ["admin", "editor"]

これらの短いスニペットは、すでに各形式の核となる哲学を示唆しています。JSONは構造化データのように感じられ、YAMLは読みやすいドキュメントのように、そしてTOMLはパワーアップしたINIファイルのように感じられます。

詳細な掘り下げ: 構文、機能、哲学

長期的な保守性を確保するには、各形式のニュアンスを理解することが重要です。私の経験から、これを習得することは不可欠です。初期段階での選択を誤ると、後々大きな問題につながる可能性があります。

JSON: データ交換の標準

元々はJavaScriptの一部でしたが、JSONはすぐに言語に依存しないデータ交換の標準へと進化しました。その厳格で予測可能な構文は、信頼性の高い機械間通信にとって大きな利点です。

主な特徴:

  • 構文: オブジェクトには波括弧{}、配列には角括弧[]を使用し、キーと値のペアはコロン:で区切られます。キーはダブルクォーテーションで囲まれた文字列である必要があります。
  • データ型: 文字列、数値、ブール値(true/false)、null、オブジェクト、配列をサポートします。
  • コメントなし: 機械可読性のための意図的な設計上の選択です。これは、人間が編集する設定ファイルにとっては厄介な点となる可能性があります。
  • 普遍的なサポート: ほぼすべてのプログラミング言語に、堅牢なJSONの解析および生成ライブラリがあります。

JSONを使用するケース:

  • API: RESTful APIのリクエストとレスポンスのデファクトスタンダードです。
  • ウェブ設定: フロントエンドアプリケーションの、シンプルでコメントが少ない設定の保存。
  • プロセス間通信: 2つのプログラムが構造化データを確実に交換する必要がある場合。

典型的なAPIレスポンスを考えてみましょう。


{
  "status": "success",
  "data": {
    "items": [
      {
        "id": "item-101",
        "name": "Laptop Pro",
        "price": 1200.00
      },
      {
        "id": "item-102",
        "name": "External Monitor",
        "price": 300.00
      }
    ],
    "total_items": 2
  },
  "timestamp": "2026-03-21T10:30:00Z"
}

YAML: 人間に優しい設定

YAMLは人間の可読性を明示的に目的として設計されており、JSONよりもデータ表現が自然に感じられることがよくあります。DevOpsの世界で急速に普及しました。これは、人間が頻繁に読み書きする設定ファイルに非常に適しているためです。

主な特徴:

  • 構文: 構造を示すためにインデント(タブではなくスペース!)を使用します。キーと値のペアはコロンで区切られます。
  • コメント: #をサポートし、設定ファイルを自己文書化できます。
  • 豊富な機能: データ再利用のためのアンカー(&)とエイリアス(*)、および様々なスカラー形式(ブロック、折りたたみ、リテラル)をサポートします。
  • JSONのスーパーセット: JSONは技術的にYAMLの有効なサブセットであり、JSONファイルはYAMLとして解析できることが多いです。

YAMLを使用するケース:

  • 設定ファイル: Docker Compose、Kubernetesマニフェスト、Ansibleプレイブック、CI/CDパイプライン。
  • データシリアライゼーション: データが人間による編集とバージョン管理が容易である必要がある場合。
  • コメント付きの複雑なデータ構造: 設定に構造とコンテキストの両方が必要な場合。

典型的なDocker Composeの例です。


version: '3.8'
services:
  web:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf # カスタムNginx設定をマウント
    depends_on:
      - app
  app:
    build: .
    environment:
      DATABASE_URL: postgres://user:password@db:5432/myapp
      API_KEY: ${MY_API_KEY} # 環境変数のインジェクション
    volumes:
      - .:/app
  db:
    image: postgres:13
    environment:
      POSTGRES_DB: myapp
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password

TOML: 設定のための最小限で明白な言語

TOML (Tom’s Obvious, Minimal Language) は、設定ファイル形式という特定のニーズから生まれました。その核となる設計目標は、ハッシュテーブル(または辞書)構造に直接かつ簡単にマッピングできることでした。YAMLよりも表現力は劣りますが、多くの設定タスクにおいてJSONよりも読みやすいことがよくあります。

主な特徴:

  • 構文: キーと値のペア(key = "value")を重視し、セクション([table_name])を使用してネストされた構造を作成します。配列もサポートされています(list = [1, 2, 3])。
  • コメント: #をサポートし、設定を簡単に説明できます。
  • 明示的な型: データ型は推論されることが多いですが、非常に明示的(例: 整数、浮動小数点数、ブール値、datetimeオブジェクト)にすることもできます。
  • 可読性重視: 人間が読みやすいように設計されており、アプリケーション設定に適しています。

TOMLを使用するケース:

  • アプリケーション設定: Pythonpyproject.tomlやRustのCargo.tomlのようなプロジェクト設定ファイル。
  • シンプルな階層データ: YAMLやJSONの複雑さや冗長性なしに、構造化された設定が必要な場合。
  • より構造が必要なINIライクなファイル: 従来のINIファイルに代わる、モダンで改良された代替手段。

Pythonプロジェクトの典型的なpyproject.tomlです。


# 基本的なプロジェクト情報
[project]
name = "my-awesome-app"
version = "0.1.0"
description = "A minimal example application"
authors = [
  { name = "Alice Developer", email = "[email protected]" }
]
dependencies = [
  "requests",
  "fastapi >=0.68.0",
  "uvicorn[standard] >=0.15.0"
]

# ツール固有の設定
[tool.poetry]
packages = [{ include = "my_awesome_app" }]

[tool.pytest.ini_options]
addopts = "--strict-markers"

高度な使用法: 状況に応じた適切なツールの選択

「最適な」形式というものはなく、常に状況によって異なります。これらの形式を数多くの開発およびデプロイサイクルで実際に見てきた結果、私はそれらの高度な応用についてより明確な感覚を持つようになりました。

JSONを好む場合

JSONの厳格さ?それがプログラムによる利用における強みです。コメントがないため、パーサーはオプション要素を処理する必要がありません。これにより、デシリアライズが高速になり、はるかに予測可能になります。HTTPを介して通信するマイクロサービスや、JSON型をネイティブにサポートするデータベースにアプリケーションの状態を保存する場合、JSONは他に類を見ません。JSON Schemaのようなツールは、信じられないほど成熟したバリデーションを提供し、堅牢なデータ整合性チェックを可能にします。


import jsonschema

schema = {
    "type": "object",
    "properties": {
        "name": {"type": "string"},
        "age": {"type": "integer", "minimum": 0}
    },
    "required": ["name", "age"]
}

# 有効なデータ
valid_data = {"name": "Bob", "age": 25}
jsonschema.validate(instance=valid_data, schema=schema)
print("有効なデータ: ", valid_data) # 出力: Valid data: {'name': 'Bob', 'age': 25}

# 無効なデータ
invalid_data = {"name": "Charlie", "age": -5}
try:
    jsonschema.validate(instance=invalid_data, schema=schema)
except jsonschema.ValidationError as e:
    print("バリデーションエラー: ", e.message) # 出力: Validation Error: -5 is less than the minimum of 0

YAMLを好む場合

YAMLは、複雑で人間中心の設定を扱う場合に真価を発揮します。Kubernetesで数十のコンテナをオーケストレーションしたり、複雑なCI/CDパイプラインを定義したり、環境固有の設定を管理したりする状況を想像してみてください。YAMLはここで優れています。コメントを含める機能とアンカー/エイリアスを使用する機能は、重複を劇的に減らし、保守性を向上させます。

しかし、YAMLの空白の感度は悪名高い両刃の剣です。単一のスペースの配置ミスが設定を完全に破壊し、信じられないほど苛立たしいデバッグセッションにつながる可能性があります。だからこそ、yamllintのようなツールは不可欠です。


# 構文エラーを検出するためにYAMLファイルをリンターにかける
yamllint my-k8s-deployment.yaml

# yqを使用して値を抽出する例
yq '.services.app.environment.DATABASE_URL' docker-compose.yaml

TOMLを好む場合

TOMLは、多くのアプリケーションレベルの設定においてちょうど良いバランスです。設定が主にいくつかのネストされたセクションと明確なキーと値のペアで構成されている場合、TOMLは優れた選択肢です。INIファイルよりも構造があり、JSONよりも冗長ではありません。重要なのは、YAMLのインデントの落とし穴を回避しながら、優れた可読性を提供することです。

Rust (Cargo) やPython (Poetry, Hatch) でのプロジェクトマニフェストにおける広範な採用は、ここでのその有効性を明確に示しています。過度な定型文なしに、関心の分離(例: [project][tool.mypy])を明確にすることができます。


import toml

# TOMLファイルから設定を読み込む
config = toml.load("pyproject.toml")
print(config["project"]["name"]) # Output: my-awesome-app
print(config["tool"]["pytest"]["ini_options"]["addopts"]) # Output: --strict-markers

設定形式を扱うための実用的なヒント

私の経験に基づき、あなたの作業をより簡単にするための実用的なヒントをいくつかご紹介します。

一般的なアドバイス

  • バージョン管理: 設定ファイルは常にバージョン管理下に置いてください。これは当たり前のことのように聞こえますが、数え切れないほどの時間を節約できます。
  • 環境変数: 機密データ(APIキー、データベースパスワード)には環境変数を使用してください。設定ファイルにハードコードしないでください。YAMLの例のように、設定ファイルはそれらを参照すべきです。
  • バリデーション: 可能な限り、設定ファイルをバリデートしてください。JSONにはJSON Schemaが堅牢です。YAMLとTOMLには、カスタムスキーマバリデーション、または少なくともリンティングを検討してください。

JSONのヒント

  • 整形出力: 特にAPIからの大きな出力の場合、jqのようなツールを使用してJSONデータを整形出力およびクエリしてください。
  • ミニファイ: ネットワーク伝送の場合、ペイロードサイズを削減するためにJSONをミニファイしてください。
  • 大規模な手動編集ファイルは避ける: JSONにはコメントがないため、複雑で人間が保守する設定には不向きです。

# JSONファイルを整形出力する
cat my_data.json | jq '.'

# 特定のフィールドを抽出する
cat my_data.json | jq '.data.items[].name'

YAMLのヒント

  • リンターを使用する: CI/CDパイプラインにyamllintツールを導入することは必須です。実行時エラーになる前にインデントエラーを検出します。
  • YAMLサポート付きエディタ: 構文ハイライトとインデント支援のために、優れたYAMLサポートを備えたIDEまたはテキストエディタを使用してください。
  • 過度な複雑さは避ける: 強力ですが、よりシンプルな構造で十分な場合は、YAMLの高度な機能(アンカー、エイリアス)を使いすぎないでください。これは新規参入者にとって可読性を低下させる可能性があります。

TOMLのヒント

  • シンプルに保つ: TOMLの強みはそのシンプルさです。設定に深くネストされた構造や広範なデータ再利用が必要な場合は、YAMLの方が適しているかもしれません。
  • 標準化: プロジェクト全体で標準化が有益なプロジェクトレベルの設定(例: Pythonのpyproject.toml)にTOMLを活用してください。
  • コマンドラインパーサー: jq/yqほど一般的ではありませんが、言語固有のTOMLパーサー(Pythonのtomlライブラリなど)はプログラムによるアクセスに効率的です。

最終的に、最適な設定形式は、プロジェクトのニーズ、チームの習熟度、および作業している特定のエコシステムに合致するものです。「唯一の最適な」答えはありません。しかし、各形式の長所と短所をしっかりと理解することで、情報に基づいた意思決定を行うことができます。

Share: