予測可能性はgraph形状と属性値の二側面を持つ
コードから読み取りたいものは二つある。graph形状(どんなリソースがいくつ、どう繋がって作られるか)と、各ノードの属性値(そのリソースが具体的にどう設定されるか)である。三つの記述自由度はどちらの側にも適用される。
属性値の予測可能性は、運用上「このリソースは具体的にどう設定されているか」をコードから知りたい場面 — インシデント対応 / コンプライアンス監査 / セキュリティレビュー — でgraph形状と並ぶ重要性を持つ。属性値計算の抽象化自由度には明確な差がある: Terraform(組込み関数のみ) < Bicep(funcあり) < Carina(関数合成 + closure) < CDK / Pulumi(高階関数 + クラス継承)。graph形状側では同列に「言語が決める」と評価される3ツール(Terraform / Bicep / Carina)でも、属性値側では差が出る。
for構文でも、適用位置がengineの見る同一性を変えるかどうかで、効き方が二つに分かれる。三自由度のうち「複数量の制御」だけは、同じ構文でも適用位置でどちらに効くかが分かれる。区別の基準は「engineが別ノード/別identityとして扱うか」:
- graph形状側に効く:
for_each = var.subnet_cidrsのようにresourceブロックやmodule呼び出しで使われると、要素ごとに別resourceノード(別identity)が生成される。要素数の動的化はそのままノード数の動的化 - 属性値側に閉じる:
tags = { for k in keys: k => format(...) }のように属性内のコレクション生成で使われると、ノード数もidentityも変わらず属性値の中身だけが動く
両者は同じfor構文を使うが、結果予測性への効き方が異なる。graph形状側のfor_eachはplanで「resourceがN個増減する」として現れ、属性値側のforは「あるresourceの属性Xが複雑な値になる」として現れる。AI修正やレビュー時の認知負荷も別物である。