🗃️

YAMLガイド:設定ファイルの書き方からJSON比較、DRY原則、LLM活用まで!

に公開

はじめに

  • 「なんかよく分からんけど、設定ファイルでよく見る『.yml』って何?」
  • 「JSONより読みやすいって聞くけど、実際どう違うん?どっち使えばいいん?」
  • 「YAMLファイルがどんどん長くなるんやけど、もっとスッキリ書けへんの?」

ソフトウェア開発、特に設定ファイルの記述や構成管理、CI/CDパイプラインなどで広く使われているYAML (ヤムル)。そして、Web APIなどで頻繁に目にするJSON (ジェイソン)。どちらもデータを構造化するためのフォーマットですが、それぞれに特徴があり、得意な分野が異なります。

特にYAMLファイルは、プロジェクトが大規模化するにつれて設定が重複し、肥大化しがちですよね。しかし、YAMLにはこの問題を解決するための機能が備わっていることを知りました。

先日、YAMLのDRY原則 (Don't Repeat Yourself) を適用するテクニックとLLM(大規模言語モデル)を組み合わせることで、行数が膨らんだYAMLファイルの行数を減らし、機能ごとにファイルを分割して動くようにするリファクタリングに成功して感動しました。

この経験から、YAMLの便利さと可能性、JSONとの違い、そしてYAMLでDRY原則を実現することの威力を改めて実感しました。そこで今回は、YAMLとは何か、そのメリット・デメリット、基本的な使い方、JSONとの比較、そして注目すべきYAMLにおけるDRY原則の適用テクニック、LLMとの組み合わせによる効率化についてメモに残します。

YAMLとは? - 人間に優しいデータ記述言語

YAMLは "YAML Ain't Markup Language" (YAMLはマークアップ言語じゃないよ) の略で、データシリアライズ形式の一つです。簡単に言うと、人間が読み書きしやすいように設計された、データを構造化して表現するための書き方(フォーマット) のことです。

括弧 {} やカンマ , を多用するJSONに対し、YAMLは主にインデント (字下げ) を使ってデータの階層構造を表現するため、パッと見で構造を理解しやすいのが最大の特徴です。

YAMLの主なメリット

YAMLが多くの開発現場で採用されているのには、明確な理由があります。

  1. 圧倒的な読みやすさ: インデントで構造を示すため、プログラムコードのように視覚的に理解しやすいです。
  2. 書きやすさ: 括弧や引用符の使用が最小限で済む場合が多く、シンプルに記述できます。
  3. 表現力: 基本的なデータ型に加え、リストやハッシュも直感的に表現できます。
  4. コメントが書ける: # でコメントを記述でき、メンテナンス性が向上します。
  5. DRY原則の実現 (アンカーとエイリアス): YAMLには「アンカー (&)」と「エイリアス (*)」という機能があります。これを使うと、同じ設定の塊を何度も書く必要がなくなり、DRY (Don't Repeat Yourself) 原則に従った効率的な記述が可能です。これが、後述するYAMLでDRY原則を実現するテクニックの基礎となります。
  6. 複数ドキュメント対応: --- で区切ることで、一つのファイル内に複数のYAMLドキュメントを含められます。
  7. 幅広いサポート: 多くの言語やツール (Ansible, Kubernetes, GitHub Actionsなど) で標準的に採用されています。

YAMLの基本的な書き方

# 基本的なキーと値
name: Taro Yamada
age: 30
is_student: false

# ネスト (階層構造) - インデントが重要!
address:
  prefecture: Tokyo
  city: Chiyoda-ku
  zip_code: "100-0001"

# リスト (配列) - ハイフン(-)を使う
favorite_fruits:
  - Apple
  - Banana
  - Orange

# 複数行文字列 (|: 改行保持, >: 改行をスペースに)
description: |
  これは複数行にわたる
  説明文です。
summary: >
  これは長い要約文です。
  改行はスペースになります。

# --- YAMLでDRY原則を実現する基本: アンカー(&), エイリアス(*), マージキー(<<) ---
# 共通の設定ブロックをアンカー(&default_db)で定義
default_database_settings: &default_db
  adapter: postgresql
  encoding: unicode
  pool: 5

development:
  database:
    # マージキー(<<)とエイリアス(*default_db)で共通設定を展開・統合
    <<: *default_db
    database: myapp_development # 個別の設定は上書き・追加可能

test:
  database:
    # 同じ共通設定を再利用
    <<: *default_db
    database: myapp_test

ポイント:

  • : の後には半角スペースが必要。
  • インデントにはスペースを使用し、タブは使わないのが一般的です。スペースの数は揃えましょう(通常は2つか4つ)。
  • アンカー (&) で定義した設定は、エイリアス (*) で何度でも再利用できます。<<:マージキーと呼ばれ、エイリアスで指定したハッシュ(辞書/マップ)の内容を展開(マージ)する機能です。これらを組み合わせることで、設定の重複を避け、DRYな記述を実現します。

【比較】JSON vs YAML: それぞれの特徴

特徴項目 YAML JSON
主な目的 設定ファイル、人間による読み書き データ交換、プログラム間の通信
可読性 非常に高い (インデントベース) 高い (括弧とカンマ)
書きやすさ 比較的容易 (記号が少ない) 比較的容易 (構造が明確)
構造表現 インデント、ハイフン (-)、コロン (:) 波括弧 ({})、角括弧 ([])、コロン (:)、カンマ (,)
コメント 可能 (#) 不可 (標準仕様では)
データ型 文字列,数値,真偽値,null,日付,バイナリ等、型推論あり 文字列,数値,真偽値,null,オブジェクト,配列
高度な機能 アンカー/エイリアス/マージキー (DRY化), 複数ドキュメント なし
厳密性 やや曖昧な部分あり (型推論、インデント) 非常に厳密 (構文エラーになりやすい)
パース速度 JSONより遅い傾向 速い
エコシステム 設定/構成管理ツールで主流 Web API、多くの言語の標準ライブラリでサポート

JSONの例:

{
  "name": "Taro Yamada",
  "age": 30,
  "is_student": false,
  "address": {
    "prefecture": "Tokyo",
    "city": "Chiyoda-ku",
    "zip_code": "100-0001"
  },
  "favorite_fruits": [
    "Apple",
    "Banana",
    "Orange"
  ]
}

【使い分け】JSONとYAML、どっちを選ぶ?

YAMLが適しているケース:

  • 人間が頻繁に読み書きするファイル (設定ファイル, 構成管理, CI/CD定義 etc.)
  • コメントで設定内容の説明を残したい場合
  • 設定の共通化・再利用 (YAMLのDRY原則の活用) を行いたい場合
  • 可読性を最優先したい場合

JSONが適しているケース:

  • Web APIでのデータ交換
  • プログラム間での単純なデータシリアライズ
  • 厳密なデータ構造が求められる場合
  • エコシステムの広さや処理速度を重視する場合
  • コメントや高度な機能が不要な場合

YAMLでDRY原則を実現するには? - 設定ファイルを効率化するテクニック

さて、冒頭の体験談でも触れた、YAMLファイルが肥大化する問題への対策、すなわちYAMLにおけるDRY原則の適用について。

なぜYAMLでDRY原則が重要なのか?

Kubernetesのマニフェストファイル、GitHub ActionsやGitLab CIのパイプライン定義など、大規模な設定ファイルでは、どうしても似たような設定ブロックが何度も登場しがちです。例えば、複数の環境(開発、ステージング、本番)でほとんど同じだけれども一部だけ違う設定、複数のジョブで共通のステップ、などです。

このような冗長な記述は、以下のような問題を引き起こします。

  • ファイルが不必要に長くなり、見通しが悪くなる。
  • 修正が必要な際に、複数の箇所を変更する必要があり、手間がかかり、修正漏れのリスクも高まる。

YAMLでDRY原則を適用することは、これらの問題を解決するために重要です。主な目的は以下の通りです。

  • 構成の再利用: 共通の設定ブロックを一度だけ定義し、必要な箇所で参照する。
  • 定義の簡略化と可読性向上: 繰り返しをなくし、ファイル全体をスッキリさせる。
  • 変更時の一元管理: 共通部分の修正は一箇所だけで済み、保守性が向上する。

YAMLでDRY原則を実現するテクニック

YAMLには、DRY原則を適用するための標準機能が備わっています。

  1. アンカー (&) とエイリアス (*):
    最も基本的なテクニックです。共通化したいデータ構造(ハッシュやリストなど)に &名前 でアンカーを付け、参照したい場所で *名前 を使ってエイリアスとして呼び出します。これにより、同じ定義を何度も書く必要がなくなります。

    # 共通のジョブ設定をアンカーで定義
    job_defaults: &default_job_settings
      docker:
        - image: circleci/node:18
      working_directory: ~/repo
    
    build:
      # エイリアスで共通設定を読み込む (DRY!)
      <<: *default_job_settings
      steps:
        - checkout
        - run: npm install
        - run: npm run build
    
    test:
      # 同じ共通設定を再利用 (DRY!)
      <<: *default_job_settings
      steps:
        - checkout
        - run: npm install
        - run: npm test
    
  2. マージキー (<<) によるオブジェクト(ハッシュ)の統合:
    エイリアスで参照したハッシュの内容を、現在のハッシュにマージ(統合) する機能です。これにより、共通設定をベースにしつつ、個別の設定を追加・上書きできます。DRY原則を保ちながら、柔軟な設定を実現します。

    # ベースとなる設定
    base_config: &base
      timeout: 60
      retry: 3
    
    # 追加の設定
    logging_config: &logging
      level: info
      format: json
    
    # マージキーを使って複数の設定を統合・上書き (DRY!)
    service_a_config:
      <<: [*base, *logging] # 配列で複数のエイリアスを指定可能
      port: 8080
      retry: 5 # base_configのretryを上書き
    
    # 結果的に service_a_config は以下のようになる
    # { timeout: 60, retry: 5, level: info, format: json, port: 8080 }
    
  3. 構造のテンプレート化:
    アンカーとエイリアスを応用すると、単なる値だけでなく、設定の「構造」そのものをテンプレートのように扱い、再利用できます。これにより、より大きな単位でのDRY化が可能です。

    # Kubernetesのコンテナ定義テンプレート
    base_container: &container_template
      imagePullPolicy: Always
      resources:
        requests:
          memory: "64Mi"
          cpu: "250m"
        limits:
          memory: "128Mi"
          cpu: "500m"
    
    # アプリケーションコンテナ定義 (テンプレートを適用 - DRY!)
    app_container:
      name: my-app
      image: my-app:latest
      <<: *container_template
      ports:
        - containerPort: 80
    
    # サイドカーコンテナ定義 (同じテンプレートを適用 - DRY!)
    sidecar_container:
      name: my-sidecar
      image: my-sidecar:latest
      <<: *container_template
      env:
        - name: LOG_LEVEL
          value: debug
    

YAMLでDRY原則を適用する際の活用例と注意点

主な活用例:

  • CI/CDパイプライン (GitHub Actions, GitLab CI, CircleCIなど):
    • 複数のジョブで共通のセットアップ手順、環境変数、キャッシュ設定などを共通化。
    • ステージング環境と本番環境でほぼ同じデプロイ手順をテンプレート化し、環境固有の変数だけを差し替える。
  • 構成管理 (Ansibleなど):
    • 複数のロールやプレイブックで共通のタスクや変数を定義。
  • コンテナオーケストレーション (Kubernetes):
    • DeploymentやStatefulSetなどで、Podテンプレート内のコンテナ定義 (リソース制限、環境変数、VolumeMountsなど) を共通化。
    • Helmチャート内で、values.yamlの値を使ってより動的にYAMLテンプレートを生成する際にも、基本的な構造の共通化にアンカー/エイリアスが使われることがあります。

DRY原則適用時の注意点:

  1. YAML自体の注意点:
    • インデント依存: スペースの数が違うだけでエラーや意図しない構造になるため、エディタ設定の統一が重要です。
    • 型推論の曖昧さ: yes, no, 数字などが意図せず真偽値や数値として解釈されることがあります。文字列として扱いたい場合は "" で囲むか !!str タグを使う。
    • セキュリティ: 信頼できないYAMLファイルの読み込みは、ライブラリによっては脆弱性につながる可能性があります。
  2. DRY化テクニック適用時の注意点:
    • 可読性の低下リスク: DRY化は重要ですが、過度にアンカー/エイリアスを多用したり、ネストが深くなりすぎると、どこで何が定義されているか追いにくくなり、かえって読みにくくなることがあります。共通化する範囲や粒度を適切に保つバランス感覚が重要です。コメントで意図を補足するのも有効です。
    • デバッグの難しさ: エイリアスやマージが複雑に絡み合うと、最終的にどのような設定が適用されるのか把握しにくくなり、問題発生時のデバッグが難しくなることがあります。
    • スキーマ検証の複雑化: JSON SchemaのようにスキーマでYAMLの構造を検証する場合、アンカーやエイリアスがあると検証が複雑になることがあります。

YAML x LLM で開発効率をブースト! - リファクタリング支援ツールとしての活用

冒頭でお話ししたように、LLMはYAMLの扱いに長けています。特に、肥大化したYAMLファイルのリファクタリング、すなわちDRY原則の適用やファイル分割を支援するツールとして力を発揮します。

LLMをYAMLリファクタリング支援に使う際の典型的なステップは以下のようになります。

  1. 現状のYAMLを読み込ませる:
    対象となるYAMLファイルの内容をLLMにインプットします。「このYAMLファイルを分析して」のように指示します。
  2. 繰り返しパターンを抽出させる:
    LLMにファイル内の冗長な箇所や繰り返し現れる設定パターンを特定させます。「このファイル内で重複している設定パターンをリストアップして」
  3. テンプレート(アンカー&エイリアス)化を提案させる:
    抽出されたパターンを元に、アンカー (&)、エイリアス (*)、マージキー (<<) を使ったDRY化(テンプレート化)の具体的な方法を提案させます。「これらの重複箇所をアンカーとエイリアス、マージキーを使って共通化する方法を提案して」
  4. 意味的なファイル分割案を生成させる:
    ファイルが大きすぎる場合、関連する設定ブロックごとにファイルを分割する案をLLMに生成させます。「この設定ファイルを機能や役割ごとに意味のある単位で分割する案を出して」
  5. 新しい構造で再構築させる:
    提案されたDRY化やファイル分割案に基づき、LLMに新しい構造のYAMLファイルを生成させます。「提案された共通化とファイル分割を適用した新しいYAMLファイルを生成して」
  6. 変更差分を意味ベースで検証させる (補助):
    LLMは完璧ではありません。生成された新しいYAMLが元の設定と意味的に同じであるか、人間の目で確認する必要があります。(yamllintなどのツールでチェックするのも一つです)LLMに変更前後の差分を説明させたり、特定の機能に関する設定が維持されているか質問したりすることで、検証の助けになります。「変更前と変更後で、database設定に関する部分はどのように変わったか説明して」
  7. 必要に応じて再構成や補正を指示する:
    検証の結果、問題があれば、LLMに具体的な修正指示を出して再生成させます。「test環境のpool設定は10に修正して、再度生成して」

このように、LLMを対話的な支援ツールとして活用することで、複雑で時間のかかるYAMLのリファクタリング作業を大幅に効率化できます。

もちろん、リファクタリング以外にもLLMはYAMLに関して様々なタスクをこなせます。

  • 構文チェック・修正: インデントミスや書き方の誤りを指摘・修正。
  • フォーマット整形: 読みにくいYAMLを整形。
  • ドキュメント生成: 設定内容に基づいてコメントを自動生成。
  • 形式変換: JSONからYAMLへ、YAMLからJSONへの変換。
  • コード生成: 特定の目的のためのYAMLスニペットを生成。

LLMを活用することで、YAMLファイルの作成、修正、保守、そしてリファクタリング(DRY化)にかかる時間を大幅に削減し、より本質的な開発作業に集中できるようになります。

おわりに

YAMLは、その可読性の高さ記述のしやすさから、特に設定ファイルや構成管理の分野で強力なデータフォーマットです。コメント機能や複数ドキュメント対応も便利です。

一方、JSONWeb APIなどプログラム間のデータ交換においてデファクトスタンダードであり、その厳密性処理速度エコシステムの広さにメリットがあります。

両者の特性を理解し、目的に応じて適切に使い分けることが重要です。

そして、YAMLを使いこなす上で非常に強力なのが、DRY原則を適用するためのテクニックです。アンカー (&)、エイリアス (*)、マージキー (<<) を活用することで、設定ファイルの冗長性を排除し、保守性が高く、見通しの良い設定ファイルを作成できます。

さらに、LLMのような新しい技術と組み合わせることで、YAMLファイルの作成・修正、そしてDRY原則に基づいたリファクタリング作業も、これまで以上に効率的に行えるようになります。

最後にこの記事のざっくりまとめをYAMLで記載して締めくくります。笑

# --- 記事まとめ (YAML形式でお届け) ---

# 結局、この記事で言いたかったこと:
topic: YAMLとJSONの違い、そしてDRY原則とLLMの話

# 各フォーマットの印象 (超ざっくり):
formats:
  yaml:
    nickname: ヤムルさん
    personality: |
      読みやすさ重視の親切設計。
      インデント命。コメント好き。
      たまに '&' と '*' で分身の術を使う (DRY!)。
      設定ファイル界の人気者。
    strength: 人間に優しい、DRY原則
    weakness: たまにインデントで迷子になる、厳密さでJSONに劣るかも?
  json:
    nickname: ジェイソンくん
    personality: |
      カッチリ構造命。括弧とカンマが好き。
      コメント?なにそれ美味しいの?状態。
      プログラム間のデータ交換で大活躍。
    strength: マシンに優しい、厳密、速い
    weakness: コメント書けない、ちょっと読みにくい時も?

# YAML使いこなし術のハイライト:
yaml_techniques:
  dry_principle:
    using:
      - anchor: "&" # 目印つけるやつ
      - alias: "*"  # 目印を参照するやつ
      - merge_key: "<<" # 合体させるやつ (便利やけど対応注意)
    benefit: "コピペよさらば! 設定ファイルがスッキリ!"
    caution: "やりすぎると暗号みたいになって読めなくなるかも?"

# 最近のトレンド?:
trends:
  llm_support:
    role: "YAMLリファクタリングの優秀なアシスタント"
    tasks:
      - "重複箇所の発見"
      - "DRY化の提案"
      - "ファイル分割案"
      - "構文チェックとか色々"
    important_note: "最終チェックは自分の目で! (LLMは万能じゃない)"

# 結論 (一言でいうと):
conclusion: |
  YAMLとJSON、適材適所で使い分けよう!
  YAML書くならDRY原則を意識すると幸せになれるかも。
  困ったらLLMに相談してみるのもアリ!

# このYAML自体が、ある意味ブログ内容の「まとめ」になってる...?
meta_comment: "この記事をYAMLで書くとこうなる、という実演でした(笑)"

以上、YAMLについて参考になれば幸いです!

Discussion