オブジェクトグラフの視覚化
Guiceの"Grapher"
洗練されたアプリケーションを、Guiceの豊富なイントロスペクションAPIがオブジェクトグラフで詳細に記述することができます。 グラファー拡張機能はグラフを簡単に理解できるように視覚化します。 複雑なアプリケーションの複数のクラスのバインディングと依存関係を統合された図で表示できます。"
Using grapher to visualize Guice applications
以上はGoogle GuiceのGrapherというオブジェクトの依存関係を視覚化するツールの説明です。
これはModule
で設定したオブジェクトの依存関係を以下のようにdotlangという、"グラフを表現するためのデータ記述言語"にに変換することで実現しています。
digraph injector {
graph [rankdir=TB];
k_dd456f9 [shape=box, label=<<table cellspacing="0" cellpadding="5" cellborder="1" border="0"><tr><td
align="left" port="header" bgcolor="#000000"><font color="#ffffff">EnergySourceProvider<br
align="left"/></font></td></tr><tr><td align="left" port="m_f4b5f9f7"><init></td></tr></table>>,
style=invis, margin=0.02,0]
k_997fdab -> k_1c5031a6 [arrowtail=none, style=dashed, arrowhead=onormal]
k_119e4fd8 -> k_17b87c3a [arrowtail=none, style=dashed, arrowhead=onormal]
k_115c9d69 -> i_115c9d69 [arrowtail=none, style=dashed, arrowhead=onormalonormal]
i_115c9d69:header:e -> k_9acc501 [arrowtail=none, style=solid, arrowhead=normal]
k_9acc501 -> k_dd456f9 [arrowtail=none, style=dashed, arrowhead=onormalonormal]
}
Ray.ObjectGrapher
Ray.Diでこの機能を実現するRay.ObjectGrapher
を開発中です。
例えば以下のモジュールがあるとします。
class FakeModule extends AbstractModule
{
protected function configure()
{
$this->bind(LoggerInterface::class)->to(DatabaseLogger::class);
$this->bind(PdoInterface::class)->toProvider(PdoProvider::class);
$this->bind()->annotatedWith('dsn')->toInstance('');
$this->bind()->annotatedWith('id')->toInstance('');
$this->bind()->annotatedWith('pass')->toInstance('');
$this->bind(FooInterface::class)->to(Foo::class);
}
}
ObjectGrapher
クラスをモジュールを引数にして実行するとdot
ファイルができます。
$dot = (new ObjectGrapher)(new FakeModule);
file_put_contents(__DIR__ . '/test.dot', $dot);
dotコマンドでpng
出力します。
dot -T png fake.dot -o fake.png
オブジェクトグラフが描画され、オブジェクトの構造やオブジェクトを繋ぐバインディングが理解しやすくなります。
線やノードの形や色には意味があります。
線
- 実線は型を表しています。
- 点線は型からクラスへのバインディングを表しています。
- 2つの矢印は依存が
プロバイダー
にバインドされてる事を表してます。
ノード
- 黒はクラスです。
- 灰色はインスタンス(実値)です。
BEAR.Resource
次はBEAR.Sundayのコンポーネントを描画してみましょう。まずはBEAR.Resourceのモジュールで宣言されたモジュールです。BEAR.SundayのコンポーネントはSRP原則を守り、複数のオブジェクトに分割されグラフを構成しています。
$dot = (new ObjectGrapher)(new ResourceModule);
このスクリプトで出力されたdot
ファイルをPNGに変換しました。
全体としては複雑ですが、部分を見るとオブジェクト同士の関係は単純です。
よく観察してみてください。Annotations\Reader
が5つのクラスから依存されてる事がわかります。
この図なしにこの依存を理解するのは簡単ではありません。
BEAR.Package
次にBEAR.Sundayで一番大きなオブジェクトグラフ$app
を服もBEAR.PackageのPackageModule
を描画しました。
複雑で大きなグラフですが、クリーンに分割できていると思います。
終わりに
このグラフ描画は、オートワイアリングが必須である GuiceやRay.Diだからこそできるものです。
グラフを描画する事でオブジェクトの構造を理解しやすいようにするだけではなく、誤ったバインディングや不要なバインディングを発見する事もできます。機能が適切な粒度を持って分割されてるか(SRP)のリファクターをする時にも役立つでしょう。
今までも print_oでオブジェクト間の繋がりを表す事ができましたが、このグラファーでは繋がりだけでなく、インターフェイスやプロバイダー、インスタンスなど、どのように繋がれたのかも確認する事ができます。
もうすぐ完成です。