「なぜDI(依存性注入)が必要なのか？」についてGoogleが解説しているページを翻訳した　

 
 イマイチ理解しきれていなかったDIに関して調べていところ、[Google Guice](https://github.com/google/guice/wiki/Motivation)の解説がすごく分かりやすかったので、和訳してみました。
 （ところどころ意訳気味です。明らかに解釈の誤った訳がありましたら、ご指摘ください）
 
 ちなみにGoogle Guiceというのは、Googleが開発したDIライブラリです。この例ではJavaが使用されていますが、Scalaでも使用可能です。最近Play Frameworkでも採用されたので話題になっているようです。
 
##用語の定義

本文を読む前に目を通すことで、内容をスムーズに理解できます。
  
|用語|意味|本文中の例|
|:-:|:-:|:-:|
|サービス|何らかの機能を提供するクラス。 **依存される側** |CreditCardProcessor、TransactionLog|
|クライアント|サービスを利用するクラス。 **依存する側** | RealBillingService |
|依存性解決|サービスとクライアントの依存関係をコード上で明記すること|new演算子、Factoryクラス、DI|
|モック|単体テストにおいて、実際のサービスの代わりに用意する偽のクラス。本物のサービスと同じインターフェースを実装する|InMemoryTransactionLog、FakeCreditCardProcessor|

 
##本文

### DIを行う動機
 
 関係する全てのオブジェクトをひとまとめにするのは、アプリ開発の中でも退屈な作業です。サービス、データ、そしてクライアントを結合する方法には色々あります。それらの方法を比較するために、ピザのネット注文の代金を請求するコードを書いてみましょう。

```Java:
 public interface BillingService {

  /**
   * クレジットカードに注文代の課金を試みる。
   * 成功しても失敗しても、トランザクションは記録される。
   * @ return トランザクションの領収書（Reciptオブジェクト）を返す。課金が成功した場合、Reciptオブジェクトは正常な値を持つ。失敗した場合、Reciptオブジェクトは課金が失敗した理由を保持する。 
   */
  Receipt chargeOrder(PizzaOrder order, CreditCard creditCard);
}
```

　実装に際しては、単体テストを書くことにしましょう。テストでは、本物のクレジットカードに課金してしまわないよう、偽のカード課金を表す```FakeCreditCardProcessor```クラスを使う必要があります。

### コンストラクタを直接呼び出す

　以下のコードは、カード課金を行うクラス（```CreditCardProcessor```クラス）と、トランザクションを記録するクラス（```TransactionLog```クラス）を、愚直にnew演算子でインスタンス化した場合です。

```Java:
public class RealBillingService implements BillingService {
  public Receipt chargeOrder(PizzaOrder order, CreditCard creditCard) {
    CreditCardProcessor processor = new PaypalCreditCardProcessor();
    TransactionLog transactionLog = new DatabaseTransactionLog();

    try {
      ChargeResult result = processor.charge(creditCard, order.getAmount());
      transactionLog.logChargeResult(result);

      return result.wasSuccessful()
          ? Receipt.forSuccessfulCharge(order.getAmount())
          : Receipt.forDeclinedCharge(result.getDeclineMessage());
     } catch (UnreachableException e) {
      transactionLog.logConnectException(e);
      return Receipt.forSystemFailure(e.getMessage());
    }
  }
}
```

　このコードはモジュール性とテスト性に問題があります。本物のクレジット課金を行うクラス（```CreditCardProcessor```クラス）にコンパイル時点で直接依存しているため、テストをするとカードに課金されてしまいます！ また、課金が失敗した時やクレジットサービスが停止している時の挙動をテストするのにも骨が折れます。
　　
###Factoryクラス

Factoryクラスは、クライアントとサービスの実装とを分離します。単純なFactoryクラスでは、インターフェースを実装したモックをgetterやsetterで操作できます。

```Java:
public class CreditCardProcessorFactory {

  private static CreditCardProcessor instance;

  public static void setInstance(CreditCardProcessor processor) {
    instance = processor;
  }

  public static CreditCardProcessor getInstance() {
    if (instance == null) {
      return new SquareCreditCardProcessor();
    }

    return instance;
  }
}
```

クライアント側で行うことは、new呼び出しをFactoryメソッドに変更するだけです。

```Java:
public class RealBillingService implements BillingService {
  public Receipt chargeOrder(PizzaOrder order, CreditCard creditCard) {
    CreditCardProcessor processor = CreditCardProcessorFactory.getInstance();
    TransactionLog transactionLog = TransactionLogFactory.getInstance();

    try {
      ChargeResult result = processor.charge(creditCard, order.getAmount());
      transactionLog.logChargeResult(result);

      return result.wasSuccessful()
          ? Receipt.forSuccessfulCharge(order.getAmount())
          : Receipt.forDeclinedCharge(result.getDeclineMessage());
     } catch (UnreachableException e) {
      transactionLog.logConnectException(e);
      return Receipt.forSystemFailure(e.getMessage());
    }
  }
}
```

 Factoryを使うと、標準的な単体テストを書くことができます。

```Java:
public class RealBillingServiceTest extends TestCase {

  private final PizzaOrder order = new PizzaOrder(100);
  private final CreditCard creditCard = new CreditCard("1234", 11, 2010);

  private final InMemoryTransactionLog transactionLog = new InMemoryTransactionLog();
  private final FakeCreditCardProcessor processor = new FakeCreditCardProcessor();

  @Override public void setUp() {
    TransactionLogFactory.setInstance(transactionLog);
    CreditCardProcessorFactory.setInstance(processor);
  }

  @Override public void tearDown() {
    TransactionLogFactory.setInstance(null);
    CreditCardProcessorFactory.setInstance(null);
  }

  public void testSuccessfulCharge() {
    RealBillingService billingService = new RealBillingService();
    Receipt receipt = billingService.chargeOrder(order, creditCard);

    assertTrue(receipt.hasSuccessfulCharge());
    assertEquals(100, receipt.getAmountOfCharge());
    assertEquals(creditCard, processor.getCardOfOnlyCharge());
    assertEquals(100, processor.getAmountOfOnlyCharge());
    assertTrue(transactionLog.wasSuccessLogged());
  }
}
```

　このコードもスマートではありません。グローバル変数がモック実装を保持しているため、モックの用意と破棄には細心の注意を要します。tearDownメソッドが失敗すると、グローバル変数はテスト用のインスタンスを参照し続けます。こうなると別のテストに影響が出かねませんし、複数のテストを並行して進めることもできません。

　しかし最大の問題は、依存性がコードの中に隠れてしまっていることです。もし、クレジットカードのなりすましを追跡するクラスを作成し、```RealBillingService```がそのクラスにも依存するようになったとしましょう。テストが失敗した時、依存しているどのクラスに問題があったのかを知るには、テストをもう一回実行しなければなりません。もしFactoryを初期化するのを忘れても、テストを実行するまで気づけません。アプリが肥大化するにつれ、依存性の面倒を見ているFactoryは、生産性を落とす原因になっていきます。
　
　品質問題は、品質保証部や受け入れテストで補足されるでしょう。それで十分かもしれませんが、もっとうまくやることができます。

###依存性注入(DI)

　Factoryのように、DIもデザインパターンです。その基本的な考え方は、 **振るまいと依存性解決を分離する** ことです。この例で言うと、```RealBillingService```は、```TransactionLog```と```CreditCardProcessor```を見つけてくる責任を負いません。その代わり、それらはコンストラクタの引数として渡されます。

```Java:
public class RealBillingService implements BillingService {
  private final CreditCardProcessor processor;
  private final TransactionLog transactionLog;

  public RealBillingService(CreditCardProcessor processor, 
      TransactionLog transactionLog) {
    this.processor = processor;
    this.transactionLog = transactionLog;
  }

  public Receipt chargeOrder(PizzaOrder order, CreditCard creditCard) {
    try {
      ChargeResult result = processor.charge(creditCard, order.getAmount());
      transactionLog.logChargeResult(result);

      return result.wasSuccessful()
          ? Receipt.forSuccessfulCharge(order.getAmount())
          : Receipt.forDeclinedCharge(result.getDeclineMessage());
     } catch (UnreachableException e) {
      transactionLog.logConnectException(e);
      return Receipt.forSystemFailure(e.getMessage());
    }
  }
}
```

もはやFactoryは必要ありません。その上、決まり文句と化した```setUp```と```tearDown```を取り除いたおかげでテストケースが簡潔になりました。

```Java:
public class RealBillingServiceTest extends TestCase {

  private final PizzaOrder order = new PizzaOrder(100);
  private final CreditCard creditCard = new CreditCard("1234", 11, 2010);

  private final InMemoryTransactionLog transactionLog = new InMemoryTransactionLog();
  private final FakeCreditCardProcessor processor = new FakeCreditCardProcessor();

  public void testSuccessfulCharge() {
    RealBillingService billingService
        = new RealBillingService(processor, transactionLog);
    Receipt receipt = billingService.chargeOrder(order, creditCard);

    assertTrue(receipt.hasSuccessfulCharge());
    assertEquals(100, receipt.getAmountOfCharge());
    assertEquals(creditCard, processor.getCardOfOnlyCharge());
    assertEquals(100, processor.getAmountOfOnlyCharge());
    assertTrue(transactionLog.wasSuccessLogged());
  }
}
```

　こうなれば、いつ依存性を追加しようと削除しようと、どのテストを修正したら良いのかコンパイラが教えてくれます。依存性は、APIのシグネチャとして外出しされたのです。

　ただ残念ながら、```BillingService```のクライアントは、依存性を自分で見つけなければなりません。```BillingService```に依存しているクラスは、コンストラクタで```BillingService```を受け取ることができます。再度DIパターンを適用すれば、大方問題は解決するかもしれません。しかし最上位のクラスにとっては、フレームワークがあったほうが便利でしょう。さもないと、サービスを使用するのに再帰的に依存関係を構築するはめになります。

```Java:
  public static void main(String[] args) {
    CreditCardProcessor processor = new PaypalCreditCardProcessor();
    TransactionLog transactionLog = new DatabaseTransactionLog();
    BillingService billingService
        = new RealBillingService(processor, transactionLog);
    ...
  }
```

###Guiceによる依存性注入

　DIパターンによってコードのモジュール性とテスト性を上げられますが、Guiceを使えば同じことをもっと簡単に書くことができます。Guiceをカード請求の例に使用するには、まずインターフェースと実装の関係をGuiceに伝える必要があります。この設定は、```Module```インターフェースを実装したJavaクラス（Guice Moduleクラス）で行われます。

```Java:
public class BillingModule extends AbstractModule {
  @Override 
  protected void configure() {
    bind(TransactionLog.class).to(DatabaseTransactionLog.class);
    bind(CreditCardProcessor.class).to(PaypalCreditCardProcessor.class);
    bind(BillingService.class).to(RealBillingService.class);
  }
}
```

　この設定を使用するには、```@Inject```アノテーションを```RealBillingService```のコンストラクタに付与します。するとGuiceはアノテーションのついたコンストラクタを調べ、引数の値を見つけてきてくれます。

```Java:
public class RealBillingService implements BillingService {
  private final CreditCardProcessor processor;
  private final TransactionLog transactionLog;

  @Inject
  public RealBillingService(CreditCardProcessor processor,
      TransactionLog transactionLog) {
    this.processor = processor;
    this.transactionLog = transactionLog;
  }

  public Receipt chargeOrder(PizzaOrder order, CreditCard creditCard) {
    try {
      ChargeResult result = processor.charge(creditCard, order.getAmount());
      transactionLog.logChargeResult(result);

      return result.wasSuccessful()
          ? Receipt.forSuccessfulCharge(order.getAmount())
          : Receipt.forDeclinedCharge(result.getDeclineMessage());
     } catch (UnreachableException e) {
      transactionLog.logConnectException(e);
      return Receipt.forSystemFailure(e.getMessage());
    }
  }
}
```

　こうして、全部のクラスをひとまとめにすることができました。```Injector```は結合したクラスのインスタンスを取得するのに使います。

```Java:
  public static void main(String[] args) {
    Injector injector = Guice.createInjector(new BillingModule());
    BillingService billingService = injector.getInstance(BillingService.class);
    ...
  }

```

[Getting Started](https://github.com/google/guice/wiki/GettingStarted)に、どのようにこのコードが動くのかの説明があります。