Dependency Injection (DI) は、「依存性の注入」という言葉で最近話題になっています。「EJB は重過ぎて使えない」とか「軽量コンテナは疎結合だからすばらしい」といった声をよく聞くようになりました。
Dependency Injection (DI) はサービスコンポーネント間の関係を疎に保ったままアプリケーションを構築するというものです。「設定を利用から分離する」という原則が、DIの本質です。
いろんな書籍が出始めてきた中で、依存性注入の何がステキなのか、疎結合だと幸せだよねといったことは非常に良く分かるようになりました。それでも、自分の中で何かしらの引っ掛かりがあります。それをつらつら書き連ねてしまおうかと思っています。
参考
Inversion of Control コンテナと Dependency Injection パターン
感じたこと
DIコンテナの役割は、マーチン・ファウラーの言葉を借りるとこういうことです。
軽量コンテナは、異なるプロジェクトのコンポーネントをひとまとまりのアプリケーションとして組み立てることを支援する。このようなコンテナの根底には、コンポーネントの結び付け方についての共通したパターンがある。そのパターンのコンセプトは「Inversion of Control(制御の反転)」と、まことに包括的な名前で呼ばれている。《中略》 「設定を利用から分離する」原則こそが重要なのだ。
DIコンテナの役割は、「異なるプロジェクトのコンポーネントをひとまとまり」にするための糊として動くといっています。僕も非常にこの部分に同意します。異なるプロジェクトコンポーネントと言っているのが味噌です。でも、コンポーネントって何でしょうか?
ソフトウェアコンポーネントは、それぞれ特定の機能を持っているが、基本的に単体では使用できず、他のプログラムと組み合わせて機能を実現、ないし追加するために用いられる。また、オブジェクトの一種として、特定の機能を持つが単独では意味を持たないようなオブジェクト、と言うこともできる。
コンポーネントとは、「それだけでは機能しない、正しいインターフェースを持ったソフトウェアモジュール」であると言えます。DIコンテナは、「それだけでは機能しないソフトウェアモジュールを組み合わせて一つのアプリケーションにするもの」だと言うことができます。
DI のサンプルは、DIの本質をつかんでいないのではないか?
さて、DIの本質は、「コンポーネント同士を貼り付ける糊」だと言うことが一般的なようでした。しかし、DIコンテナのサンプルを見ると、ドメインモデル間の関係をDIしている例が見受けられます。これって変ですよね?
DIは異なるコンポーネント、つまりお互いに帰属関係のない概念を結合する場合に使うべきものです。ドメインモデルと言うものは、同一の概念レベルにあるものではないでしょうか?
帰属関係のない概念とは、例えば、データアクセスオブジェクトとデータソース、サーブレットコントローラとトランザクション、リソース管理とロギングの関係などです。これらはコンポーネントとしての機能を持っていますが、単体では動きません。こういうモノを組み合わせるためにDIコンテナを利用するべきではないかと考えます。
DIはいつ使うべきか?
DI自体はとてもすばらしい考えだと思います。コンポーネントの関係を疎結合にするというのは、保守を考えたとき、テストを考えたときにとても幸せになれます。ただ、ドメインモデル同士の関係に、DIを使うのはどうかと思います。ドメインモデルでは関係があるはずなのに、実装コードを見たら関係が見つからないと言うのでは、逆に保守が大変だと思います。
アプリケーションのコンフィギュレーションをリソース化する場合の基本は以下のようなものがあります。
- 横断的/共通的な概念
- データソース、データベースの名前、ユーザ名やパスワードなどは、設定ファイルとして切り出す。
- 外部との接点
- 既存システムとの連結部、ビジネスルール、サービスの開始部などは、インターフェースでやり取りし、カスタマイズできる部分を設定可能にする。
- 外部資源
- トランザクション、ログファイル、データソースなどはカスタマイズ可能です。あちこちに分散しそうな設定は外部化しておく。
アプリケーションのコンフィギュレーションをリソース化できる部分が、実はDependency Injection が使える重要ポイントなのではないかと考えています。コンポーネントは、コンテキストにもよりますが、それ自体が交換可能なものです。リソースもまた、交換可能なものです。それぞれが正しいインターフェースを提供することで、Dependency Injection が可能になるはずです。
「コンポーネント同士の結合部分、コンフィギュレーションとして切り出せる部分、プラグイン化可能な部分」こそ、Dependency Injectionを使うべきところで、それ以外のところでは、異なる概念でなければむやみに使わないほうがいいように思います。何でもかんでも疎結合にしようというのは、ちょっと考え物。
参考
- コンポーネントとは何かを調べるときに使いました。