notes mizzy.org

契約を別ファイルに切り出すと必ずずれる

確認済み 出典: peitho/docs/PEITHO_KICKOFF.md §3, §17 / peitho/CLAUDE.md 三本柱② 作成/ 更新

peithoのレイアウトはHTMLテンプレートだが、テンプレートそのものがスキーマを兼ねている。契約を別ファイルに書き出すことを明示的に禁じている — 「二重管理は必ずずれる」からである。

<section class="slide">
  <h1><slot name="title" accepts="inline" arity="1"></slot></h1>
  <div class="body">
    <slot name="body" accepts="blocks" arity="0..*"></slot>
  </div>
</section>

<slot> の属性から契約(名前 / 受け付ける型 / 個数)を抽出する。スキーマファイルは存在しない。契約が意味の場所に物理的に同居しているので、片方だけ直すことができない。

「同居」で守れない境界には別の手を打つ

同じ設計判断が、言語をまたぐ境界でも繰り返し出てくる。peithoはビルドがRust、プレゼン実行時がTypeScriptで、両者はmanifestという契約を共有する。ここでは物理的な同居ができない。

採った手は片方を正とし、もう片方を生成することである。ドメイン型とmanifestスキーマはRust側の peitho-core が唯一の源で、TS型は ts-rs / schemars 経由で生成される。TS側は契約を手書きしない。Rust側が変われば生成物がずれ、CIの git diff --exit-code bindings/ が赤くなる。

① 規約で守る 本体 契約ファイル 人が同期 ずれても誰も気付かない ② 同居させる — peithoのレイアウト 本体 = 契約 <slot accepts arity> 写しが存在しないので、ずれようがない ③ 生成する — 言語をまたぐ境界 Rust(正) TS(生成物) ts-rs ずれるとCIが赤くなる
①だけが「人間が覚えていること」に依存している。②と③は、狙いは同じで手段が違う。

同居も生成も、狙いは一つである — 契約の写しを人間が手で同期する地点を無くすこと。同居できるなら同居し、できないなら生成する。どちらも取れないなら、それは「規約で守る」ということで、typestateで壊れた状態を書けなくするの言う「呼び出し側が覚えていること」に依存した状態に戻っている。

表現力の上限を引き受けている

テンプレートがスキーマを兼ねるということは、HTMLの <slot> 要素で書けることが契約の表現力の上限になるということでもある。契約を別言語で書けば、もっと複雑な条件(「titleがある場合に限りsubtitleを許す」等)を表現できたはずだ。

peithoはその上限を受け入れている。契約の語彙が貧しいことより、契約が本体からずれることの方が高くつく、という賭けである。これはschemaの型語彙が上限を決めるのと同じ構図を、逆向きの選択として持っている — あちらはschemaの型語彙が上限を決めることを問題として指摘し、こちらは上限が低いことを承知で同居を選んでいる。

#設計原則 #契約 #peitho