公開日 · 読了時間 1 分
JSON vs YAML vs CSV: どのデータフォーマットを使うべきか?
JSON、YAML、CSVは重なる問題を解決しますが、同じ仕事のために設計されたわけではありません。文法、ファイルサイズ、ツール、本番でチームを噛む落とし穴を比較し、自信を持って正しいフォーマットを選べるようにします。
数年以上ソフトウェアを出荷してきたなら、これら3つのフォーマットすべてを一度はファイルに書き込んだことがほぼ確実にあるはずです。JSONはあらゆるREST APIから流れ出します。YAMLはKubernetesマニフェスト、GitHub Actionsワークフロー、インストールするCLIの半分の共通語です。CSVはマーケティングが「生データ」をくれと言ったときに送られてくるものです。互換性があるように感じられ、Multilitiesのようなツールで相互変換は簡単ですが、変換できることと適当に選んでいいこととは別物です。
本記事では、各フォーマットが実際にどう動くか、どこで輝き、どこで崩れるか、そして経験豊富なチームがどれを選ぶかの目安を解説します。同じデータセットを3通りに表現し、トレードオフを抽象論ではなく具体的に見ていきます。
簡単なメンタルモデル
文法の海に溺れる前に、フォーマットを次のように頭に入れてください:
- JSONは構造化オブジェクトのシリアライズフォーマット。マシンが別のマシンと話す必要があり、人間が時々出力を読む程度の場合に手を伸ばすもの。
- YAMLは人間が手で設定ファイルを編集することに最適化された、JSONの実質スーパーセット。人がスクロールし、差分を見て、レビューすることを前提にしている。
- CSVは表形式のフォーマット。各行が同じ形を持ち、消費者がスプレッドシート、データベースのCOPYコマンド、あるいはpandasのread_csvを実行する人であることを前提にしている。
JSON: APIとJSのデフォルト
JSON、JavaScript Object Notationは、2000年代初頭にJavaScriptから抽出され、RFC 8259として標準化されました。プリミティブ型は6つ: object、array、string、number、boolean、null。語彙はそれだけです。日付なし、コメントなし、末尾のカンマなし、参照なし。このミニマリズムが要点で、どんな言語でも数百行でJSONをパースできます。これが地球上のすべてのHTTP APIが最終的に落ち着く理由です。
ブラウザはJSON.parseでJSONをネイティブにパースし、すべてのバックエンド標準ライブラリにJSONモジュールがあり、テキスト表現を超える必要が出てきたときにはMessagePackやCBORのようなバイナリフレンドリーなバリアントもあります。リクエスト/レスポンスのペイロード、ログの転送、JS状態の永続化、ドキュメントデータベースには、JSONがほぼ常に正しいデフォルトです。
YAML: 設定のスイートスポット
YAMLは元々Yet Another Markup Languageと呼ばれ、後に再帰的にYAML Ain't Markup Languageに改名されました。バージョン1.2ではJSONの厳密なスーパーセットです。JSONで合法なものはYAMLでも合法ですが、YAMLにはコメント、複数行文字列、再利用のためのアンカーとエイリアス、明示的な型タグ、そして最も重要なこととしてインデントベースの文法が加わり、句読点ノイズの大部分が剥がれます。
その読みやすさが、YAMLが設定を支配する理由です。Kubernetesマニフェスト、Helmチャート、Ansibleプレイブック、GitHub Actions、GitLab CI、Docker Compose、OpenAPI仕様、dbtプロジェクト、そしてほとんどの最新CLIはYAMLを読みます。人間がエディタでファイルを編集し、プルリクエストでレビューする場合、YAMLが勝ちます。
CSV: 普遍的なスプレッドシート握手
CSV、comma-separated valuesはWebより古く、RFC 4180で緩く記述されています。極めてシンプルです: 1行目は通常ヘッダー、以降の各行はレコード、フィールドは区切り文字(多くはカンマですが、タブ、セミコロン、パイプも一般的)で区切られます。区切り文字、改行、ダブルクォートを含む文字列はダブルクォートで囲み、内部のダブルクォートは2重にしてエスケープします。
CSVは地球上のすべてのスプレッドシート、すべてのBIツール、すべてのデータベースのバルクローダー、Pythonノートブックを開いたすべてのアナリストが、儀式なしで理解するフォーマットです。ネストデータには酷いフォーマットで、フラットなテーブルには素晴らしいフォーマットです。消費者がExcelを開いた人間なら、CSVがほぼ常に正解です。
同じデータ、3つのフォーマット
違いを具体例で固定しましょう。3人のユーザーのリストを想像してください。各人にid、name、email、role、tagsのリストがあります。JSON版は次のとおりです。
[
{
"id": 1,
"name": "Ada Lovelace",
"email": "ada@example.com",
"role": "admin",
"tags": ["founder", "math"]
},
{
"id": 2,
"name": "Linus Torvalds",
"email": "linus@example.com",
"role": "maintainer",
"tags": ["kernel", "git"]
},
{
"id": 3,
"name": "Grace Hopper",
"email": "grace@example.com",
"role": "admin",
"tags": ["compiler", "navy"]
}
]同じペイロードをYAMLで
句読点が落ちていく様子に注目してください。構造はインデントだけで伝えられ、tagsのリストはインライン(フロースタイル、JSONと同じ)でもブロックでも書けます。コメントは合法で、よく役立ちます。
# ステージング環境のシードユーザー
- id: 1
name: Ada Lovelace
email: ada@example.com
role: admin
tags:
- founder
- math
- id: 2
name: Linus Torvalds
email: linus@example.com
role: maintainer
tags: [kernel, git] # 短いリストにはフロースタイルでもOK
- id: 3
name: Grace Hopper
email: grace@example.com
role: admin
tags:
- compiler
- navyそしてCSVで
CSVはネストされたtagsの配列をネイティブに表現できないので、フラット化する必要があります。よくある慣例は、リストをパイプやセミコロンのような副次的な区切り文字で結合し、その選択をどこかに記録することです。ヘッダー行がフィールド名を置き換え、各レコードは独自の行に置かれます。
id,name,email,role,tags
1,Ada Lovelace,ada@example.com,admin,founder|math
2,Linus Torvalds,linus@example.com,maintainer,kernel|git
3,Grace Hopper,grace@example.com,admin,compiler|navy3つのフォーマット、3つのサイズ
ファイルサイズは人々が認めるよりも重要です。ロギングパイプライン、ブラウザバンドル、ストレージ料金はすべてそれを気にします。上記の例の大まかなバイト数は: JSONはきれいに整形して約410バイト、最小化で290; YAMLは約320バイト; CSVは約200バイトです。CSVはフィールド名をすべての行に繰り返さず1回で済ますため、フラットデータでは堂々と勝ちます。
ネストし始めると話は逆転します。JSONとYAMLはレコードあたりほぼ一定ですが、CSVは自分で考案した慣例でフラット化するか、複数のシートに展開せざるを得ません。20のフィールドを持つ深くネストされた1人のユーザーなら、JSONとYAMLは構築可能などのCSVよりも小さく、明確になります。
実務でそれぞれが勝つ場面
本物のチームが使うパターンマッチング:
- JSONはHTTP API、WebSocketペイロード、ブラウザのlocalStorage、ログ行(特にJSON Lines)、MongoDBなどのドキュメントDB、サービス間契約に。
- YAMLはKubernetes、Helm、Argo、Terraform Cloudワークスペース、GitHubやGitLabのCIパイプライン、OpenAPIとAsyncAPIの仕様、人間が編集するアプリ設定、可読性がパース速度に勝るInfrastructure-as-Codeに。
- CSVはアナリティクスのエクスポート、CRMインポート、ETLステージングテーブル、機械学習データセット、財務レポート、ExcelやGoogleシートに送られるあらゆるものに。
- データがバイナリ、超高スループット、サービス間で強く型付けされている場合は、3つともなしに。Protobuf、Avro、Parquetが通常正解です。
JSONの噛みつく落とし穴
JSONのミニマリズムは特長ですが、いくつかの罠を生みます。仕様はコメントを禁じているため、JSONで書かれた設定ファイルは自分自身を説明できません。配列やオブジェクトの最後の要素の後ろの末尾カンマは、最新言語が受け入れていても違法です。数値はデフォルトで64ビット浮動小数点なので、2の53を超える整数は静かに精度を失います。多くのAPIが大きなIDを文字列としてシリアライズするのはこのためです。
JSONはネイティブの日付型も持ちません。ISO 8601文字列が事実上の慣例ですが、あなたと消費者で合意する必要があります。同じオブジェクト内の重複キーは文法上は許容されていますが、パーサー間で未定義動作を生むので頼ってはいけません。
YAMLのもっと強く噛みつく落とし穴
YAMLの柔軟性は弱点でもあります。インデントが意味を持つので、タブと空白を混ぜたり先頭の空白を2文字失ったりするだけで、ファイルの意味が静かに変わります。悪名高いノルウェー問題はYAML 1.1パーサーで今も発生します。引用符なしのトークンNOはbooleanのfalseとしてパースされ、国コードリストを何度も壊してきました。YAML 1.2はこれを修正しましたが、多くのツールは依然1.1セマンティクスを出荷しています。
数値、日付、booleanのように見える文字列はクォートしないと型強制されます。アンカーとエイリアス(&fooと*foo)は強力ですが、信頼できないYAMLを受け入れるとbillion-laughs型のサービス拒否を招きます。ユーザー提供のYAMLは必ずsafeローダーでパースしてください。
CSVの静かに噛みつく落とし穴
CSVは正しく見えながらこっそり壊れている可能性が最も高いフォーマットです。区切り文字に標準はなく、ヨーロッパのロケールはカンマが小数点なのでセミコロンで書き出します。インポーターはそれを検出する必要があります。引用符内の改行は合法ですが、素朴なライン分割を躓かせます。Excelは電話番号や長いIDをCSVを開いたときに科学記法に喜んで再フォーマットし、人間が見る前にデータを壊します。
エンコーディングはもう一つの地雷です。CSVにはエンコーディング宣言がないので、macOSできれいに開くファイルがWindowsでは文字化けすることがあります(UTF-8 vs Windows-1252)。迷ったらUTF-8 BOMを書き、区切り文字を文書化し、すべての文字列フィールドをクォートしてください。
それらの間で安全に変換する
実際のシステムの多くは、これらのフォーマットの複数に住んでいます。ベンダーからCSVを取り込み、APIのためにJSONに変換し、結果を処理するワーカーを設定するためにYAMLを出力します。それらの変換を手作業でやるとバグが生まれるため、Multilitiesは専用の変換ツールを提供しています。
JSONとYAMLの間を切り替えるなら、/tools/yaml-jsonコンバーターが両方向を扱い、可能な限りコメントを保持します。表形式データなら、/tools/csv-jsonがCSVエクスポートをフィクスチャファイルやPostmanリクエストにそのまま貼り付けられるJSON配列に変え、財務にスプレッドシートを渡す必要があるときには逆方向にも変換します。そして人が書いたように読めるJSONブロブが欲しいだけなら、/tools/json-formatterがキーをソートし、インデントを直し、構造を一度に検証します。
決定チェックリスト
確信が持てないときは、上から順にこのリストをたどり、最初のYesで止まってください。
- 消費者がスプレッドシートかSQLバルクローダーで、データはフラットか? CSVを使う。
- 人間がコードエディタでこのファイルを編集し、プルリクエストでレビューするか? YAMLを使う。
- 消費者がプログラムで、特にネットワーク越しで、最小限の儀式と最大限のツールが欲しいか? JSONを使う。
- 固定スキーマで高スループットに数百万レコードをシリアライズするか? 3つを飛ばしてProtobuf、Avro、Parquetへ。
まとめ
3つのフォーマットは競合するというより、それぞれの専門家です。JSONは普遍的な交換フォーマット、YAMLは人間に優しい設定言語、そしてCSVは開発者でない人にも普遍的に理解されているため死なないスプレッドシート握手です。それぞれがどんな仕事のために設計されたか、そして落とし穴を知っていることが、クリーンなデータパイプラインを出荷するチームと、毎週金曜午後にエスケープのバグと戦うチームを分けます。
コンバーターのツールをブックマークし、CSVがどの区切り文字とエンコーディングを使うか書き留め、迷ったらYAMLの文字列をクォートし、JavaScriptを通る64ビットIDが無傷で帰ることを期待しないでください。それさえやれば、選んだフォーマットはほとんど背景に消え、まさにそれが良いデータフォーマットがすべきことです。