レベルエンター山本大のブログ

面白いプログラミング教育を若い人たちに

Guice2.0 beta 紹介記事の翻訳(1)

Guice2.0のベータに関する記事があったので、またぼちぼち訳してみます。

Dependency injection with Guice

Testable code with less boilerplate
決まり文句の手間が少ないテストコード

http://www.ibm.com/developerworks/library/j-guice.html?ca=dgr-jw22Guice&S_tact=105AGX59&S_CMP=GRsitejw22

Level: 中級 Nicholas Lesiecki (ndlesiecki@apache.org), Software engineer, Google
2008/11/09



Guice is Google's open source dependency injection framework for Java〓 development. It enables better testing and modularity by taking away the pain of writing your own factories. Nicholas Lesiecki offers a tour of the most important Guice concepts that will leave you ready to Guice up your applications.

Guiceはグーグルが提供する、Java開発のためのオープンソースDIフレームワークです。
このフレームワークは、プログラマーを独自のファクトリーを作る手間から開放し、より良いテストとモジューラビリティーを可能にします。
この記事はGuiceを使うための準備として、最も重要なGuiceのコンセプトのツアーを提供します。


Guice is a dependency injection (DI) framework. I've suggested for years that developers use DI, because it improves maintainability, testability, and flexibility. By watching engineers react to Guice, I've learned that the best way to convince a programmer to adopt a new technology is to make it really easy. Guice makes DI really easy, and as a result, the practice has taken off at Google. I hope to continue in the same vein in this article by making it really easy for you to learn Guice.

Guicedependency injection (DI)フレームワークです。私はここ数年、開発者にDIを使うことを推奨してきました。なぜなら、DIを使うことでメンテナンス性、テスト容易性、柔軟性が好転するからです。新しい技術を採用するために、プログラマを説得する一番良い方法は、それを実際に簡単に使ってもらうことです。Guiceに対するエンジニアの反応を見ていると、GuiceはDIを本当に簡単なものにしてくれます。そして、結果としてその運営はGoogoleを離れました。私は、流れのまま続くことを希望しています。この記事でGuiceを学ぶこととても簡単にすることで、それを実現したいと思います。

Guice 2.0 beta


As I write this, the Guice team is working hard on Guice 2.0 and expects to release before the end of 2008. An early beta is posted on the Google Code download site (see Resources). This is good news, because the Guice team has added features that will make your Guice code easier to use and understand. The beta lacks some features that will make it into the final version, but it's stable and high quality. In fact, Google uses the beta version in production software. I advise you to do the same. I've written this article specifically for Guice 2.0, covering some new Guice features and glossing over features from 1.0 that have been deprecated. The Guice team has assured me that the features I cover won't change between the current beta and final release.

私がこの記事を書いているとき、GuiceチームはGuice2.0を2008年中にリリースするために一生懸命働いています。
早期Bata版が、Google Code ダウンロードサイト上にアップされました。(参照)
これは良いニュースです。なぜなら、Guiceチームは簡単に使えて学習も容易な新しい機能を作りこむからです。
Beta版で欠けているいくつかの機能は、最終バージョンでは組み込まれるでしょう。しかし、Beta版も安定していて高い品質です。
事実、Google自体がBetaバージョンをソフトウェア製品で使っています。私としては、同じようにあなたの製品でも使ってみてはとアドバイスしてあげたいぐらいです。
私は、この記事でGuice2.0の特徴を書きます。いくつかのGuice2.0の機能と、1.0で不評だった点をブラッシュアップした機能をカバーします。
Guiceチームは、私が書いた機能については、現在のベータ版から最終リリースの間まで変えないと私に確証してくれました。


If you already understand DI and know why you'd want a framework to help you with it, you can skip to the Basic injection with Guice section. Otherwise, read on to learn about DI's benefits.

もし、読者の方がDIについて既に知っているなら、なぜフレームワークがあなたの助けになるかは知っていることでしょうから、「Guiceの基本的なインジェクション」のセクションまで飛ばしてもかまいません。そうでなければ、DIの利益について学んでいきましょう。

DIを使う状況
The case for DI

I'll start with an example. Let's say I'm writing a superhero application, and I'm implementing a hero named Frog Man. Listing 1 contains the code, as well as my first test. (I hope I don't need to convince you of the value of writing unit tests.)

では、サンプルから始めることにしましょう。例として、スーパーヒーローアプリケーションを作っていきます。
Frog Manという名前のヒーローを実装していきます。"リスト1"にコードと最初のテストコードも一緒に記述します。
(単体テストの価値についての解説は、もう良いですよね?)


リスト1. ヒーロー と 彼に関するテスト

public class FrogMan {
  private FrogMobile vehicle = new FrogMobile();
  public FrogMan() {}
  // crime fighting logic goes here...
}

public class FrogManTest extends TestCase {
 public void testFrogManFightsCrime() {
    FrogMan hero = new FrogMan();
    hero.fightCrime();
    //make some assertions...
  }
}

All seems well until I try running the test, whereupon I get the exception in Listing 2:
リスト2で、テストを実行してExceptionを見てみると、すべてがよく理解できます。

リスト2. 面倒な依存性

java.lang.RuntimeException: Refinery startup failure.
  at HeavyWaterRefinery.<init>(HeavyWaterRefinery.java:6)
  at FrogMobile.<init>(FrogMobile.java:5)
  at FrogMan.<init>(FrogMan.java:8)
  at FrogManTest.testFrogManFightsCrime(FrogManTest.java:10)

It seems that the FrogMobile constructs a HeavyWaterRefinery and, well, let's just say there's no way I can construct one of those in my test. I can do so in production, sure, but no one will grant me a second refinery permit just for testing. In real life, you're not likely to refine deuterium oxide, but you are likely to depend on remote servers and beefy databases. The principle is the same: These dependencies are hard to start and slow to interact with, and they cause your tests to fail more often than they should.

FrogMobileが、HeavyWaterRefineryを生成していて、それで、私の作ったテストコードの仲ではそれらを生成する方法が無いのです。
プログラムの中でそうすることはできますが、テストにおいては別の手を使うことを許してくれません。
実生活では、重水を精製(HeavyWaterRefinery)するようなことはありませんが、しかし、リモートサーバーや肥満気味のデータベースに依存しているようなことはよくあります。
原則は同じです。依存性は、起動するのが難しいそして、相互に遅くなる、さらにたいていテストを失敗させるということです。

DI入門
Enter DI

To avoid this problem, you can create an interface (for example, Vehicle) and have your FrogMan class accept the Vehicle as a constructor argument, as in Listing 3:

この問題を回避するには、インターフェイスを作ります。(例えば、Vehicle(乗り物)というような)。そして、FrogManクラスのコンストラクタ引数にVehicleを受け取るようにします。
リスト3でそれを記載します。


リスト3. インターフェイスへの依存、そしてインジェクト

public class FrogMan {
  private Vehicle vehicle;

  public FrogMan(Vehicle vehicle) {
    this.vehicle = vehicle;
  }
  // crime fighting logic goes here...
}

This idiom is the essence of DI ― have your classes accept their dependencies through references to interfaces instead of constructing them (or using static references). Listing 4 shows how DI makes your test easier:

この書き方は、DIの核心部分です。つまり、クラスが、その依存性を生成する代わりにインターフェイスを介して参照しすることです。(または、静的参照を使います。)
リスト4は、DIがどのようにテストを簡単にするかを表しています。

Listing 4. テストで面倒な依存性の代わりにモックを使う方法

static class MockVehicle implements Vehicle {
  boolean didZoom;

  public String zoom() {
    this.didZoom = true;
    return "Mock Vehicle Zoomed.";
  }
}

public void testFrogManFightsCrime() {
  MockVehicle mockVehicle = new MockVehicle();

  FrogMan hero = new FrogMan(mockVehicle);
  hero.fightCrime();

  assertTrue(mockVehicle.didZoom);
  // other assertions
}

This test uses a hand-written mock object to replace the FrogMobile. Not only does DI free the test from the painful refinery startup cost, but it also keeps the test from knowing about FrogMobile. All it needs is the Vehicle interface. In addition to making tests easier, DI also helps your code's overall modularity and maintainability. Now, if you want to switch the FrogMobile for the FrogBarge, you can do so without modifying FrogMan. All FrogMan depends on is the interface.

このテストは、FrogMobileの代わりに手書きのモックオブジェクトを使っています。
DIはコストをかけて精製所を立ち上げるというテストの苦痛から解放してくれるだけではなく、テストがFrogMobileについて知っている状態をキープすることができます。これに必要なのは、Vehicleインターフェイスだけです。加えて、テストの作成を簡単にしてくれます。
DIはコードのモジュール性とメンテナンス性を、総合的に援助します。さて、もしもFrogBargeからFrogMobileに切り替えたいと思ったなら、FrogManクラスを変更することなく行なうことができます。FrogManが依存するのはインターフェイスだけです。

There's a catch, however. If you're like me the first time I read about DI, you're thinking: "Great, now all FrogMan's callers have to know about the FrogMobile (and the refinery, and the refinery's dependencies, and so on...)." But if that were true, DI would never have caught on. Instead of forcing callers to assume the burden, you can write factories to manage the creation of an object and its dependencies.

ここまでは理解できたと思います。しかしながら、私がDIに初めて触れたときにはこう考えました。
「とてもいいけど、FrogManを呼び出す側はFrogMobileについて知らないといけないんじゃない?(それに精製所や精製所の依存性についてなどなど、、)」
しかし、それが本当ならDIをまだ理解していないといえます。強制的に、呼び出し側の負担を装う代わりに、オブジェクトの生成や依存性を管理するファクトリーを書くようにすれば良いのです。

Factories are where frameworks come in. Factories require a lot of tedious, repetitive code. In the best case, they annoy the program author (and readers), and in the worst, they never get written because of the inconvenience. Guice and other DI frameworks serve as flexible "super factories" that you configure to build your objects. Configuring the framework is a lot easier than writing your own factories. As a result, programmers write more code in a DI style. More tests, better code, and happy programmers follow.

ファクトリーは、フレームワークで提供されています。ファクトリーは沢山の退屈な繰り返しのコードを必要とします。
その最も良い場合であっても、プログラム実装者や解読者を悩ませます。さらに最悪のケースでは、その面倒さから、ファクトリーをまったく記述しないことになります。GuiceやそのほかのDIフレームワークは、オブジェクトの生成を設定する柔軟な「スーパーファクトリー」を提供するものです。
フレームワークによる設定は、自分でファクトリーを書くよりも全然簡単です。結果として、プログラマーはDIスタイルでより多くのコードを書くことになります。より多くのテストをして、より良いコードを書いて、プログラマーが幸せになることにつながるのです。