Help us understand the problem. What is going on with this article?

Ray.Di オブジェクトグラフの視覚化

オブジェクトグラフの視覚化

Guiceの"Grapher"

洗練されたアプリケーションを、Guiceの豊富なイントロスペクションAPIがオブジェクトグラフで詳細に記述することができます。 グラファー拡張機能はグラフを簡単に理解できるように視覚化します。 複雑なアプリケーションの複数のクラスのバインディングと依存関係を統合された図で表示できます。"

Using grapher to visualize Guice applications

以上はGoogle GuiceのGrapherというオブジェクトの依存関係を視覚化するツールの説明です。

これはModuleで設定したオブジェクトの依存関係を以下のようにdotlangという、"グラフを表現するためのデータ記述言語"にに変換することで実現しています。

injector.dot
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">&lt;init&gt;</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を開発中です。

例えば以下のモジュールがあるとします。

FakeModule.php
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ファイルができます。

make_dot.php
$dot = (new ObjectGrapher)(new FakeModule);
file_put_contents(__DIR__ . '/test.dot', $dot);

dotコマンドでpng出力します。

dot -T png fake.dot -o fake.png

オブジェクトグラフが描画され、オブジェクトの構造やオブジェクトを繋ぐバインディングが理解しやすくなります。

image.png

線やノードの形や色には意味があります。

  1. 実線は型を表しています。
  2. 点線は型からクラスへのバインディングを表しています。
  3. 2つの矢印は依存がプロバイダーにバインドされてる事を表してます。

ノード

  1. 黒はクラスです。
  2. 灰色はインスタンス(実値)です。

BEAR.Resource

次はBEAR.Sundayのコンポーネントを描画してみましょう。まずはBEAR.Resourceのモジュールで宣言されたモジュールです。BEAR.SundayのコンポーネントはSRP原則を守り、複数のオブジェクトに分割されグラフを構成しています。

$dot = (new ObjectGrapher)(new ResourceModule);

このスクリプトで出力されたdotファイルをPNGに変換しました。

image.png

全体としては複雑ですが、部分を見るとオブジェクト同士の関係は単純です。
よく観察してみてください。Annotations\Readerが5つのクラスから依存されてる事がわかります。

この図なしにこの依存を理解するのは簡単ではありません。

image.png

BEAR.Package

次にBEAR.Sundayで一番大きなオブジェクトグラフ$appを服もBEAR.PackageのPackageModuleを描画しました。

image.png

複雑で大きなグラフですが、クリーンに分割できていると思います。

終わりに

このグラフ描画は、オートワイアリングが必須である GuiceやRay.Diだからこそできるものです。

グラフを描画する事でオブジェクトの構造を理解しやすいようにするだけではなく、誤ったバインディングや不要なバインディングを発見する事もできます。機能が適切な粒度を持って分割されてるか(SRP)のリファクターをする時にも役立つでしょう。

今までも print_oでオブジェクト間の繋がりを表す事ができましたが、このグラファーでは繋がりだけでなく、インターフェイスやプロバイダー、インスタンスなど、どのように繋がれたのかも確認する事ができます。

もうすぐ完成です。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした