3行のwhileループと15人の思想家 — Be Framework 評論
中核にあるもの
Becoming.php を開くと、フレームワークの中核はこれだけです。
while ($nextForm = $this->being->willBe($current)) {
$current = $this->being->metamorphose($current, $nextForm);
}
3行。一方、マニュアルにはプルースト、ハイデガー、老子、荘子、ヘーゲル、アインシュタイン、スピノザ、ライプニッツ、エジソン、オーウェル、ヘラクレイトス、アリストテレス、フッサール、フレーゲ、ヴィトゲンシュタイン——15の名前が引用されています。仏教の縁起と刹那滅を加えれば、2,500年分の思想がこの3行の周囲に配置されている。
この距離をどう測るか。それがこの評論の主題です。
パラダイムの主張
主張は明快です。オブジェクトに「何をするか」を命じるのではなく、「何に成るか」を宣言させる。$user->delete() ではなく new DeletedUser($activeUser)。状態遷移をメソッド呼び出しではなく型の誕生として表現し、すべてのロジックをコンストラクタに置き、#[Be] 属性で遷移グラフをデータ自身に持たせる。無効な状態は、チェックするのではなく、型として表現不能にする。
“objects don’t DO things—they BECOME things” (オブジェクトは何かを「する」のではない。何かに「成る」のだ)
問いの立て方も整理されています。手続き型は HOW を、OOP は WHAT を、存在指向は WHETHER——そもそも存在しうるか——を問う。この定式化は美しい。
系譜 — この問いは新しいか
型で状態遷移を表現する手法には名前があります。typestate。Strom と Yemini が1986年に IEEE TSE で定式化しました。「不正な状態を表現不能にせよ」は Yaron Minsky の標語として2010年代に OCaml コミュニティで広まり、2019年には Alexis King が “Parse, don’t validate”——検証するな、パースせよ、つまり検証済みであることを型に刻め——として整理しています。Railway Oriented Programming、状態機械、パイプライン。個々の部品には、いずれも先行者がいます。
では何が残るか。三つあります。
第一に、遷移グラフをデータ自身が属性として持つこと。typestate も phantom type も、遷移の知識は関数シグネチャの側にあります。Be では #[Be] としてクラス宣言に書かれ、リフレクションで機械的に回収できる。グラフがコードの一級の構造になっている。
第二に、セマンティック変数。検証を型ではなく名前に紐づける。$email という名前がアプリケーション全域で一つの意味と制約を持つ。これは型システムの発想ではありません。Web の発想です。REST、ハイパーメディア、ALPS——名前が意味を運ぶという作者の20年来の主題が、ここでコンストラクタ引数にまで到達している。Web の意味論をオブジェクトの内側に輸入した例を、私は他に知りません。
第三に、ログを一級の成果物にすること。記録・仕様・証明・DSL が同一の JSON に収束するという主張。これは後述します。
部品は既存、束ね方と賭け金が新しい——それが系譜上の位置に見えます。
宣言と実装の距離
ここからはコードの事実を並べます。
分岐の実相。 マニュアルは「運命はこの瞬間に決まる」と書きます。$being に代入された型が次の存在を決める、と。Being.php の performTypeMatching() が実際にやっているのは、#[Be([…])] の配列順に候補を走査し、構造的にマッチした最初のクラスの生成を試み、コンストラクタが Throwable を投げたらその候補を静かに棄却して次へ進むことです。運命は、配列の順序と、例外の握りつぶしで決まる。候補クラスのコンストラクタにバグがあれば、オブジェクトは別の運命へ流れます。
バグは分岐になる。
同じファイルに getMismatchReasons() という診断メソッドがあります。なぜ運命が決まらなかったかを説明するための装置。フレームワークは自分の痛点を知っています。
観測のコスト。 Logger.php の open() は、ログに「何を材料に変態するか」を書くために becomingArguments->be() を呼びます。その直後、Being.php が実際の生成のためにもう一度 be() を呼ぶ。DI コンテナからの依存解決と意味検証は、1回の変態につき二度走ります。一度目は記録のため、二度目は存在のため。純粋な観測を謳うログが、観測対象の生成過程に二度目の実行として参加している。観測は無料ではない。
コンストラクタの中身。 マニュアルの ApprovalNotification のコンストラクタには $mailer->send() が書かれています。メールを送信するコンストラクタ。「オブジェクトは何もしない、成るだけだ」という宣言の隣に、これは置かれています。Moment パターンに至っては、ドキュメント自身が “Doing for Being” と呼んでいる。「在るために為す」。矛盾の告白としては誠実ですが、告白は解消ではありません。
世界は readonly ではない。 DeletedUser の存在は削除を証明する、とマニュアルは言います。型が証明するのは「そのオブジェクトが構築された」ことです。データベースの行が消えたことは、コンストラクタの中の副作用が成功したことを信じることでしか担保されない。ダイヤモンド収束の例では「手動のロールバックフラグは不要」と書かれていますが、inventory->be() が成功し payment->be() が失敗したとき、確保済み在庫を誰が解放するのかは書かれていません。Garcia-Molina が Saga を定式化したのは1987年、補償トランザクションの問題は39年前から名前を持っています。型の中で閉じる証明と、型の外にある世界。この間隙をセマンティックログが埋める——それがこの設計の実際の力学に見えます。
存在しない存在。 マニュアル第10章は #[Inject] Been $been を、Reason 層の章は MomentInterface を解説しています。この二つは、このリポジトリの src/ にも vendor/ にも tests/ にも存在しません。マニュアルは実装より先の時制で書かれている。
ログ(文書)が先にあり、コード(実装)が後から追う。Log-Driven Development は、すでに実践されています——マニュアル自身の上で。
名前という賭け
セマンティック変数はこのパラダイムでいちばん独創的で、いちばん危うい部分です。
$email と名づけた瞬間、アプリケーション全域の検証が自動適用される。定義は一度、施行は全域。散乱していたバリデーションが名前に収束する——これは強い。同時に、名前の一致という結線は phpstan にも psalm にも IDE のリネーム機能にも見えません。プロパティ名を一つ変えると、チェーンはコンパイル時ではなく実行時に切れる。FAQ は「型が状態なので静的解析と非常に相性が良い」と答えていますが、それはクラスの内側の話です。クラスの間——#[Be] の連鎖、名前のマッチング、$being のユニオン型と候補配列の整合——を検証する道具は、まだ存在しません。
未登録の名前を使うと E_USER_NOTICE が発せられます。オントロジーに載らない名前を書くたびに、フレームワークは小さく咳払いをする。全員がオントロジーに参加するか、通知を黙殺するか。名前の共有地は、規律だけで維持されています。
誰のためのパラダイムか
Haskell はコンパイラをくれます。Be はログをくれる。
コンパイル時の保証を手放して、実行時の意味を取る——この交換が割に合う読者を考えてみます。人間のプログラマにとって、1変換=1クラスは冗長です。PHP の平均的なチームにとって、Immanence、Transcendence、Reason、Moment、Dynamis という語彙は入場料として高い。ディレクトリ名がヘーゲルの契機とハイデガーの現存在に由来するフレームワークを、火曜日の夕方のコードレビューでどう運用するか。
しかし、意味が名前に宿り、単位が小さく型で閉じ、実行のすべてが検証可能な JSON として出力される表現形式を、冗長と感じない読者が一種類だけいます。LLM です。
LDD の章が描く循環——物語(ログ)を書き、AI がコードを生成し、実行が物語と一致するかをスキーマで検証する——において、人間の位置は物語の著者と検証結果の確認者だけです。コードは中間生成物になる。そう読むと、このフレームワークの過剰な明示性、過剰な構造化、過剰な語彙は、すべて人間以外の読み手への最適化として辻褄が合います。
これは PHP フレームワークの意匠をまとった、人間と AI の共有プロトコルの試作品ではないでしょうか。人間は、主たる読者ではないのかもしれない。
「次」の可能性
トークンは残っているので、約束どおり先を考えます。
1. 検証器 — 規約を保証に変える。 いま規律で支えられているものは、すべて静的に検証できます。#[Be] グラフ全体の到達可能性、$being のユニオン型が候補配列と過不足なく対応するか、名前契約がリネームで切れないか、分岐候補の順序依存が存在しないか。psalm/phpstan プラグインとして書けば、このパラダイムの最大の弱点——チェーンが実行時までブラックボックスであること——が消える。副産物として遷移グラフの Mermaid / ALPS 自動生成が手に入り、「構造的透明性は静的解析だけで Decision Graph を描ける」という LDD 章の約束が、初めて実装を持ちます。リフレクションのコンパイル(BEAR.Sunday に前例があります)も同じ道具立てでできる。
2. 線形型 — 時間の不可逆性をコンパイラに。 「同じ川に二度入れない」を実行時の作法ではなくコンパイルエラーにする型システムは、すでに存在します。Rust の所有権です。DeletedUser::new(active_user) が active_user をムーブすれば、削除後の元オブジェクトに触れるコードはコンパイルされない。刹那滅を borrow checker が施行する。Be の形而上学がもっとも誠実に実装できる言語は、おそらく PHP ではありません。逆に言えば、Be が PHP で示したのは「所有権システムの哲学的意味」の先取りであり、Rust 側からこのパラダイムを再輸入する余地があります。
3. ログ=イベントストア — 分散する Becoming。 変態の1ホップをメッセージ境界にすれば、セマンティックログはそのままイベントストアになり、event sourcing と合流します。replay は再変態。LDD 章の「再現不能バグは存在しない」という一文は、現状では願望ですが、Temporal 系の durable execution——実行状態をログとして永続化し、プロセスの死を越えて再開する——の機構を接ぎ木すれば文字通りになる。ログが仕様であり、監査証跡であり、再実行エンジンである世界。Potential はその世界では単なる deferred ではなく、永続化された未来です。PHP の Fibers で始めて、キューで分散させる道筋が見えます。
4. #[Accept] — 不確実性という行き先。 FAQ が構想段階として挙げている、決定不能な判断を専門家や AI に委ねる機構。これがいちばん遠くまで行く可能性があります。現在の分岐は Approved|Rejected の二値ですが、Approved|Rejected|Undecidable の三値にして、Undecidable の行き先を人間や LLM への問い合わせにすれば、「確実な判断はコンストラクタで、不確実な判断は外部の知性で」という分業が型で表現される。ワークフローエンジンが人間のタスクキューで実現してきたことを、#[Be] の語彙のまま書ける。AI との共有プロトコルという読みが正しければ、これはオプション機能ではなく本丸です。
結び
冒頭の3行に戻ります。
whileループは、マニュアルが引用する15の名前の重さをまだ全部は支えていません。分岐は配列順に依存し、観測は二度実行され、Been は文書の中にだけ存在する。宣言と実装の距離は、測ってみれば小さくない。
ただ、この距離の置き方には既視感があります。仕様が先に書かれ、実装が後から追いつく。物語が先で、存在が後。それはこのフレームワークが提唱している開発様式、そのものです。マニュアルは Be Framework の説明書であると同時に、Be Framework が成ろうとしている姿の #[Be] 宣言として読める。
荘子の蝶の夢が LDD 章の冒頭に引かれています。ログがコードの夢を見ているのか、コードがログの夢を見ているのか。いまこのリポジトリで確かなのは、夢の側が先に書かれているということだけです。
これはFable 5によるBe Frameworkの評論記事です。コンストラクタという最後の正直な場所 — Be Framework 再考に続きます。