YAMLの落とし穴: ノルウェー問題とその他の静かな罠

YAMLの便利さは暗黙的な型推論から来ており、そこがまさに問題の起きる場所です。国コードがfalseになり、バージョン番号が桁を失い、時刻が整数になります。こうした罠とその回避方法を整理します。

YAMLは書きやすい形式です。波括弧も引用符もなく、インデントと値だけで 表現します。その便利さは一つの機能から来ています。引用符のない値の型を YAMLが推測してくれる点です。多くの場合、その推測は正しいです。しかし それ以外の場合には、データを静かに別のものへ変えてしまい、静かである ために本番環境で初めて気づくことになります。有名な例はブール値になって しまう国コードですが、これは知っておくべきより広いパターンの一例にすぎ ません。

暗黙的な型推論が根本原因です

YAMLは引用符のないスカラーに出会うと、それを解釈しようとします。123は 整数になり、trueはブール値になり、nullはnullになる、といった具合 です。型を要求していないのに、YAMLはテキストの形から型を推論します。 おかげでcount: 3を引用符なしで書けますが、同時に以下のすべての罠を 引き起こす原因でもあります。すべての罠に対する対処法は同じで、値に引用符 を付けることです。ただしいつ引用符を使うべきかを知っておく必要があり ます。

ノルウェー問題

代表的な例は国コードのリストです。

countries:
  - NO   # Norway
  - SE   # Sweden
  - FR   # France

YAML 1.1仕様では、NOブール値のfalseです。YESONOFFTRUEとその大文字小文字のバリエーションも同様です。そのためノルウェーは 静かにfalseになり、パーサーはアプリケーションが文字列を期待している ところにブール値を渡します。同じ論理で、化学物質リストのNO(一酸化窒素) やユーザーのイニシャルもブール値になります。引用符を付けること、つまり "NO"が対処法です。

YAML 1.2はブール値をtrue/falseだけに絞りましたが、多くのパーサーは いまだに1.1の動作をデフォルトにしています。そのため安全だと決めつけ られません。2文字の大文字の文字列は引用符が必要なものとして扱ってくだ さい。

バージョン番号と60進法の罠

数値推論から生じるものがもう2つあります。

  • **version: 1.20**は浮動小数点の1.2としてパースされます。末尾の0が 消え、両者を区別したいときに1.20 == 1.2が真になります。バージョン 文字列は常に引用符を付けるべきです。version: "1.20"と書きます。
  • **time: 22:30**はYAML 1.1で60進法(sexagesimal)の整数として読まれる ことがあります。22*60 + 30 = 1350になります。時計の時刻として意図した フィールドが意味のない整数になります。引用符を付けてください。

先頭のゼロと8進数の落とし穴

id: 0755のような値は**8進数(octal)**として解釈され、10進数で493に なることがあります。電話番号、郵便番号、ゼロ埋めのIDはすべて先頭のゼロを 失うか、別の解釈をされます。CSVと同様に、先頭のゼロが意味を持つ値は必ず 引用符を付けた文字列でなければなりません。

その他の鋭い角

  • タブはインデントに使えません。 YAMLは空白を要求しており、紛れ込んだ タブはパースエラーになります。タブを挿入するエディタは分かりにくい失敗を 引き起こします。
  • インデントが構造そのものです。 揃っていないキーは静かに誤った親の 子になったり、意図しない兄弟になったりします。有効なYAMLですが、誤った データです。
  • アンカーとマージキー(&*<<)は強力ですが、ドキュメントを 読みにくくし、パーサーによって動作が異なります。控えめに使ってください。

大半を防ぐルール

迷ったときは、別の型と間違われ得る文字列に引用符を付けてください。 意図せずブール値になる値(NOYESON)、バージョン番号、時刻、 ゼロ埋めの数値が対象です。必要のない値に引用符を付けても失うものはなく、 上記のすべての罠を避けられます。大半が文字列と識別子からなる設定では、 手で調整した数値ファイルよりも引用符の規律が重要になります。

こうした問題をリリース前に捕まえるには、YAMLバリデーターが ブラウザでドキュメントをパースし、構造とエラーを表示します。そのためNOが 文字列として通ったのかブール値として通ったのかを確認できます。YAMLが あなたのケースに適した形式かどうかをまだ検討中なら、 JSONとYAMLの比較で、それぞれの危険な点を それぞれが適する場面と照らし合わせて扱います。