JSON Diffにおけるキーの並べ替え
JSON diffツールがオブジェクト内のキーの並べ替えをどのように処理するかを理解します。JSONでキーの順序が通常重要でない理由と、偽陽性が生じる場合について解説します。
Structural Diffs
詳細な説明
JSON仕様(RFC 8259)は、オブジェクトはキーと値のペアの順序なしコレクションであると述べています。つまり {"a":1,"b":2} と {"b":2,"a":1} は意味的に同一です。しかし実際には、シリアライザー、言語、バージョンによってキーの順序は異なることがあり、diffツールがそれをどう扱うべきかという疑問が生じます。
意味的比較 vs テキスト比較:
テキストdiff(JSONを生の文字列として比較)は、文字シーケンスが異なるため、並べ替えられたキーを変更として報告します。意味的diff(両方のドキュメントをまずデータ構造にパースして比較)は、並べ替えられたキーが意味のある差分を生じないことを正しく識別します。
// ドキュメントA
{
"name": "Widget",
"price": 29.99,
"category": "tools",
"inStock": true
}
// ドキュメントB
{
"category": "tools",
"inStock": true,
"name": "Widget",
"price": 29.99
}
意味的JSON diffは、すべてのキーと値が同一であるため差分ゼロを報告します。行ベースのテキストdiffでは、すべての行が変更として報告されます。
キーの順序が変わる理由:
- 言語の違い: Python辞書(3.7+)は挿入順序を保持します。Goのmapはランダムな順序で反復します。Javaの
HashMapは順序が保証されません。異なるサービスがJSONをシリアライズすると、キーの順序が異なる場合があります。 - シリアライザーの設定: 一部のJSONライブラリは「キーをソート」するオプションを提供します。ドキュメントの一方がソートされたキーでシリアライズされ、もう一方がそうでない場合、すべてのキーが移動したように見えます。
- データベースの往復: JSONをデータベースに保存して取得すると、ストレージエンジンによってキーの順序が変わる場合があります。
ベストプラクティス:
- JSON比較にはテキストdiffではなく、必ず意味的(パース済み)diffツールを使用してください。
- テキストベースの比較を使用する必要がある場合(例:git内)、コミット前にキーをソートしてください。
- diffツールがキーの順序を無視するオプションを提供している場合は、それを設定してください。
ユースケース
ソフトウェアアップデート間でシリアライザーがキーの順序を変更しても、JSON変換パイプラインが意味的に同一の出力を生成することを検証する。