モジュールは速く副作用の無いこと
コンフィギュレーションのための外部XMLではなく、Guiceでは通常のJavaコードを使ってモジュールを記述する。 Javaならわかりやすく、IDEで操作可能で、リファクタリングしてもおかしくならない。
しかし、Java言語のフルパワーを生かすにはコストがかかる。モジュール内で「やりすぎ」がたやすくできてしまう。 モジュール内でHTTPサーバを開始しデータベースに接続するというような誘惑にかられる。 こんなことをしないように! 重量級のモジュールでは問題が発生しかねない。
- モジュールがスタートアップするが、シャットダウンしない。モジュール内でデータベース接続を開始するとそれをクローズする方法がない。
- モジュールをテストしなければならなくなる。モジュール内でデータベース接続をオープンすると、それをテストするのは難しい。
- モジュールはオーバライド可能である。Guiceモジュールはオーバライドをサポートしており、製品向けサービスを軽いテスト用のものに代替することが可能であるが、製品サービスをモジュール実行の一部として起動してしまうと、そのようなオーバライドが意味をなさなくなる。
モジュール自体の中でそのような仕事をさせるのではなく、特定の抽象の中でそのような仕事ができるようなインターフェースを定義すべきである。 例えばこのように。
public interface Service { /** * サービスをスタートする。このメソッドはサービスが完全に開始するまでブロックする。 */ void start() throws Exception; /** * サービスを停止する。完全にシャットダウンするまでブロックする。 */ void stop(); }
インジェクタを作成した後は、そのサービスを開始することでアプリのブートストラップを終了する。 アプリをストップさせるときは、リソースを完全に解放するためのシャットダウンフックも提供する。
public static void main(String[] args) throws Exception { Injector injector = Guice.createInjector( new DatabaseModule(), new WebserverModule(), ... ); Service databaseConnectionPool = injector.getInstance( Key.get(Service.class, DatabaseService.class)); databaseConnectionPool.start(); addShutdownHook(databaseConnectionPool); Service webserver = injector.getInstance( Key.get(Service.class, WebserverService.class)); webserver.start(); addShutdownHook(webserver); }