構成データ出力DSLから貰えるのは評価段階だけである
構成データ出力DSL(Jsonnet / CUE / Dhall / Nickel / KCL / Pkl)をIaCの front end に使えないか、という問いがある。「IaCはグラフだから使えない」と言い切るのは言い過ぎで、実際 Jsonnet や CUE が Terraform JSON や k8s manifest を吐く構成は広く動いている。resource graph は構造データとして表現できる。
正確には、貰えるのは評価段階だけである。そして評価段階はIaCで難しいところではない。
出力で終わる処理系と、出力から始まる処理系
構成データ出力DSLの契約は「評価して値ツリーを出す」で終わる。型検査があっても、検査するのは出てくるドキュメントであり、出した後は型を捨てる。処理系の仕事はそこで完結する。
IaCの処理系は、その出力から始まる仕事の方が本体である。
| 段階 | 構成データ出力DSL | IaC処理系 |
|---|---|---|
| 評価 | ある | ある |
| 世界の取得(refresh) | 無い | 要る |
| 世界との突き合わせ(差分計算) | 無い | 要る |
| identity の同定 | 無い | 要る |
| まだ存在しない値の扱い | 無い | 要る |
| 効果の実行と記録(state) | 無い | 要る |
これは構成データ出力DSLの欠陥ではない。値ツリーを出すことが仕事なのだから、その先が無いのは当然である。構成データ出力DSLとgraph出力DSLはレイヤが違うが「state管理 / 差分計算 / CRUD実行はDSLのレイヤではなくツールのレイヤの話であり、DSL同士を比べるときはこの線を越えない」と書いて引いた線の、向こう側がまるごとIaC処理系の担当になる。
ここでは意図的にその線を越えている。 DSL同士を比較するときは越えるべきでないが、「既存DSLを front end に採用できるか」を問うときは、越えた先の面積こそが判断材料だからである。線の向こう側が自前になるなら、front endの流用で浮くコストはその分だけ小さい。
消えるのはエッジの検査である
値ツリーとして出せることと、出した後も検査が効くことは別である。IaCで効かせたい性質はエッジにある — subnet.vpc_id の参照先が実在し、型が合っており、apply時には値を持つ、という性質である。
構成データ出力DSLの中では、このエッジは書けてもエッジとして残らない。JSONに落ちた時点で参照は文字列か、消費側ツール独自の補間構文を埋めた文字列になる。DSLの型システムはドキュメントを検査し終えて退場しており、エッジの正しさを見るのは消費側の仕事として残る。型名の文字列比較で代入可能性を決めるのは構造を捨てているが言っているのと同じ損失が、言語境界をまたぐ地点で起きる。
これは identity についても効く。構成データ出力DSLとgraph出力DSLはレイヤが違うはノードとエッジまでを扱ってidentityに触れていないが、identityは「何を同一資源と見なすか」の規則であり、stateとは独立軸であるが言う「エンジンが同じリソースとみなすもの」は、値ツリーには現れない。同じJSONを二度出しても、それが同じリソースの二度目なのか別物なのかは、ドキュメントの側からは決まらない。
Unknownを表現する語彙が無い
もう一つの欠落は既に別ノートが押さえている。全域性の価値は「何をゲートするか」で決まるが「Pklには守るべきapply段階がなく、したがって段階を跨ぐ値(applyまで決まらない値)の問題自体を持たない」と書いている通りで、これはPklに限らず構成データ出力DSL全般に及ぶ。値ツリーは評価が終われば完成しているものだから、Unknownは二段階の間に開いた窓であるのUnknown — まだ無いが後で値を持ち、型は分かっている — を置く場所が無い。
つまりこれは評価器に足せる機能ではなく、IaC言語は二段階の言語であることの帰結である。
コンパイラの蓄積は使えるが、既存処理系は流用できない
類比が切れるのはターゲットが生きている場所であるは「三点の外側ではコンパイラの蓄積がほぼそのまま使える」と書いている。本ノートはそれと矛盾しない。理論の蓄積が使えることと、特定言語の処理系がそのまま載ることは別だからである。
字句解析・評価・型検査の作り方はコンパイラ工学から借りられる。借りられないのは、refresh・差分・identity・stateという、評価の後ろに続く段の実装である。既存DSLの処理系が提供しているのは前者の成果物であって、後者は最初から範囲外にある。
帰結
構成データ出力DSLを front end に採用しても、手に入るのは「評価してツリーを出す」までである。identity・差分・state・Unknownはどのみち自前で持つことになり、しかも front end の型情報は境界で失われているので、エッジの検査をもう一度やり直すことになる。
これは既存言語を採用してもフル機能は使わせられないと対になる論点である。向こうは言語表面の話(採っても使わせられない)、こちらは処理系の話(採っても難しい部分は貰えない)。汎用言語埋め込みと構成データ出力DSLという別々の選択肢に対して、それぞれ別の理由で「既存のものを流用する」が期待ほど効かない。
根拠の確度
構成データ出力DSLとgraph出力DSLのレイヤ差は構成データ出力DSLとgraph出力DSLはレイヤが違うで確認済み。apply段階を持たないことの含意は全域性の価値は「何をゲートするか」で決まるにあるが、そちらはPklについてAI由来の未確認事実を含む。
本ノートが足しているのは「front endに採用したとき何が貰えて何が残るか」という読みで、解釈である。未解決の問いに挙がっていた「Pklの構成データ計算 vs IaCのresource graph」への一つの答えでもある。
実在の構成(Jsonnet + Terraform JSON、CUE + k8s)でエッジの検査がどこまで失われ、どこで補われているかは未確認。表の「無い」は、その言語の仕事の範囲外という意味であって、周辺ツールを含めた運用で代替物が無いという主張ではない。