Advent Day 9: Compile and Runtime
決定論
もしもある瞬間における全ての物質の力学的状態と力を知ることができ、かつもしもそれらのデータを解析できるだけの能力の知性が存在するとすれば、この知性にとっては、不確実なことは何もなくなり、その目には未来も(過去同様に)全て見えているであろう。
— 『確率の解析的理論』1812年
「ラプラスの悪魔」です。
ラプラスの悪魔のような、こんなデバックツールできないでしょうか?
もしもある瞬間における全てのオブジェクトの状態と機能を知ることができ、かつもしもそれらのデータを解析できるだけの優れたアナライザーがあるとすれば、このアナライザーにとっては、不確実なことは何もなくなり、その目には全ての潜在的なバグが全て見えるであろう。
…夢でしょうか^^; しかしデバックに苦しむのは「状態の不確実性」からという事は多くないでしょうか?例外でいえばLogicExceptionの原因追及は、RunteimExceptionの例外の原因追及よりずっと簡単です。オブジェクトが”モード”やHTTPが状態(セッション)をもつと問題解決はずっと複雑になります。状態=不確実性=evil !
この記事ではオブジェクトの不確実性を低減する技術としてのDIを見て見ます。
再び生成と利用分離原則
DIでは生成と利用を分離しますが、分離するのはコードだけではありません。その時間(タイミング)も分離されます。「生成」が終わってから「利用」になるためです。BEAR.Sundayではオブジェクトの生成時に依存の注入だけでなく、アスペクトの織り込みも行われます。これがオブジェクトをつくるコンパイル。その時間がコンパイルタイムです。
生成・使用分離の原則 DI 関心の分離で[具象コード]と[抽象コード]の分離を示したようにするとこういう風になります。
生成と使用のタイミングが分離されていないパターン
< -– boot終了 -–>
< -– runtime開始 -–>
[生成]
[使用]
[生成]
[使用]
[使用]
[生成]
[使用]
生成と使用のタイミングが分離されているパターン(DI)
[生成]
[生成]
[生成]
< -– boot終了 -–>
< -– runtime開始 -–>
[使用]
[使用]
[使用]
[使用]
オブジェクトグラフの決定
DI以外のパターン、例えばfactory()メソッドとの比較は分かりやすいでしょう。コードの途中で現れたnew演算子やfactory()メソッドは“on demand”でオブジェクトの取得を行います。
対してService Locaterを使ったパターンではどうでしょうか。オブジェクトやあるいはオブジェクトの生成方法はboot時に各コンテナに格納されるので生成と使用のタイミングの分離はDIと同じです。
しかしオブジェクト間の関係性=オブジェクトグラフの決定のタイミングが違います。SLではオブジェクトをコンテナから取り出しプロパティに格納あるいは直接利用します。その時点でdependentとdependencyの関係性が決定されます。つまりメソッド内の実装でその関係性が決定されます。
対してDIではメソッドシグネチャーとその束縛の集合がオブジェクトグラフを決定します。リクエストを受けたboot時にどのオブジェクトグラフが生成されるかが最大限、決定されています。
その応用
BEAR.Sundayではその特性を利用してオブジェクト生成の再利用を行っています。莫大なオブジェクトグラフコンストラクションコストは再利用され運用ではほぼ0になります。10万を超えるファンクションコールは1/100の1000程度になります。これは抽象化レイヤーが最少のFWとほぼ同等です。
この設計パターンはパフォーマンスの寄与と、より少ないコード実行を可能にしています。