データフォーマットの仕様を考える
必要な仕様が定義されているか?
データがどのように格納されるべきか、最低限定めておかなければいけない仕様を定める
意外といろいろ細かいことを定義しなければいけない
JSON Schemaを利用する場合、一度JSON Schemaの仕様を眺めてみて、何が設定できるかを把握しておくと良い ✅️ 文字エンコード
✅️ データの型
✅️ 数値の最大値・最小値
✅️ 値の必須・非必須
非必須の場合、初期値あるいは挙動
仕様の解釈違いが発生しにくいか?
シリアライズされたデータを見た際に、仕様を参照しなくともひと目でそのデータが何を表すかが頭に入ってくるとベスト
仕様の解釈違いを誘発するインタフェースは極力避けるべきである
✅️ 値の意図を説明する
✅️ リファレンス実装を提供する
✅️ データの例を提供する
および、それを読み込んだ際の想定挙動を説明する
✅️ 実装に期待する挙動を仕様内で言及しておく
💡 他フォーマットの仕様や挙動を参考にする
💡 フィールド名で値の意味を明示する
例: localCoord と、データがローカル座標系かワールド座標系かをフィールド名で明示する 例: srgbColor と、データの色空間がsRGBであるとフィールド名で明示する ❌️ 1つの構造体内に、同じ名前・似た名前を持つフィールドが複数存在する
どの環境でも同様に読めるデータか?
他のエンド・プラットフォーム等に持っていったときに問題なく読めるか?
✅️ 実装例を擬似コードで提供する
❌️ 絶対パスが含まれる
❌️ 単一のプラットフォームの機能に依存した仕様
不正なデータを生み出しづらい構造か?
不正なデータを誤って生み出さないような工夫をする。あるいは、不正なデータがあったとしても、デシリアライズする際に頑張れる余地を残しておく
✅️ 予期しない値が入っていた場合の挙動について、仕様で定義しておく
例: 数値のレンジを仕様で$ [0, 1] と定める場合、実装はそれ以外の値が来たときにsaturateすると規定しておく ✅️ 実装に対してファジングを行い、事前にどのような不正なデータが来る可能性があるかを予期しておく (必要に応じて)将来的な拡張・修正に強いか?
データフォーマットが将来的に変わる可能性がある場合、それを見越したスキーマにしておく
コミュニティによる拡張を推奨する場合、それができる余地を残しておく
あるいは、拡張を防ぎたい場合、それができる余地を潰しておく
💡 任意のデータを挿入できるフィールドを用意しておく
💡 値の制約をあえて設けないでおく
例えば、値が$ [0, 1] の範囲であると一度規定してしまうと、将来的にその制約を緩めた際、既存の実装はレンジ範囲外の値に対応できていない。値の制約は慎重に行うべき
後から制約を設ける分には、期待する挙動が変わらない限り、既存の実装も影響を受けない
💡 辞書のキーをenumで規定し、想定しない値が入らないようにしておく
コミュニティが勝手に慣習でデータを挿入してしまうのを防ぐ
(必要に応じて)データサイズが小さいか?
Intro等、データサイズが重要なケースの場合、データサイズが最優先事項となることがある 💡 バイナリフォーマット
💡 圧縮時に小さくなるよう、エントロピーが小さくなるような工夫がされている ❌ 実行時に必要のない文字列を含む
name ・ comment など
❌ 数値が文字列で格納され、かつ適切な精度に丸められていない
0.30000000000000004 や 0.3333333333333333 等は頻出
(必要に応じて)人間による可読性が高いか?
もし、シリアライズされたデータを人間が直接読み書きする機会がある想定ならば、それがやりやすいフォーマットになっているか確認すべき
💡 リレーションをユニークな名前参照にする
💡 設定項目のenumを、数値でなく意味のある文字列にしておく
❌ バイナリフォーマット
❌ リレーションがindex参照
❌ 長い配列において、絶対的なインデックスに意味がある
相対的な順序関係がある分には問題ない