DIフレームワークはどのような複雑さを追加しますか?


8

非常に最近の質問に対する現在最も支持されている回答は、

DIコンテナーは「エンタープライズソフトウェア」パターンであり、オブジェクトグラフが非常に大きく複雑な場合に使用されます。アプリケーションの95%はそれを必要としないと思います。

これは私が強く反対することです。多分私は間違った用語を持っているかもしれませんが、私にとってDIフレームワークは単に「オブジェクトを一緒に配線する何か」を意味します。何か不足していますか?

非常に小さなプロジェクト(10クラスなど)でも、それらを簡略化するためにGuiceを使用しています。確かに、400 kBのJARファイルですが、これは私が気にすることではありません。小規模なプロジェクトの場合、設定はほとんど必要なく、唯一の「オーバーヘッド」は注釈の追加です。@Inject

それで、私は本当に不思議に思います、DIフレームワークはどんな追加された複雑さを引き起こしますか?

回答への対応を更新

82クラスのプロジェクトでは、

  • 32 @Inject注釈
  • 15 @Singletonと1の@ProvidedBy注釈
  • 4プロバイダー(これらはすべて私の工場であるため、DIなしでも必要です)
  • 1つの行を含むモジュール
  • 0行XML !!!

それで全部です。確かに、それは小さなプロジェクトですが、まさにこれが私のポイントでした。追加の作業は、ではなく数でした。

不変の「使いやすい」オブジェクトを取得するために、コンストラクター注入のみを使用しています。新しい依存関係が出現するたびに、最終フィールドを追加し、LombokのRequiredArgsConstructorが宣言を処理するようにし、Guiceがそれを適切に呼び出すようにします。


Guiceはプロパティインジェクションを行っていますか?
Reactgular 2014年

@MathewFoscarini私はそう思う-私は他の用語を知っており、これはメソッド注入(の特別なケース)でなければならない。
maaartinus

1
Guiceにとても感謝しています。私の開発の多くを簡素化し、よりテストしやすく、堅牢にしました。DIなしで長い間行ったなんて信じられません。ケーキは本物です。
コーディネーター

回答:


6

私の知る限り、DIフレームワークを使用する際には、いくつかの妥協点があります。

私にとって最も心配なのは、通常、アプリケーションコードがメインのプログラミング言語(Javaなど)とXML / JSON構成コード(コード)に分散していることです。つまり、アプリケーションに問題がある場合は、2つの場所を調べる必要があります。多くの場合、構成コードはメインアプリケーションコードに簡単に関連付けることができません。

もちろん、この構成はコンパイラ(および多くの場合IDE)がチェックできる範囲の外側にもあります。つまり、配線を処理するメインクラスを作成する場合よりも、この構成を間違える方がはるかに簡単です。事実上、これは、配線の問題がコンパイル時の問題から実行時の問題に移行することを意味します。

アプリケーションを分割するだけでなく、DIフレームワークを使用すると@Inject、従来のDI手法(Java / C ++でのCTORインターフェースインジェクション、C ++でのテンプレートインジェクション)の代わりに、コード内でを使用することもよくあります。これの欠点は、アプリケーションでDIフレームワークを使用する必要があることです。別の方法は、DIフレームワークを想定せずにアプリケーションを設計し、DIフレームワークがクラ​​スの従来のCTOR /セッターインジェクションを再利用できるようにすることです。

従来のインジェクションメカニズムの欠点は、複雑で適切にカプセル化されたクラスが、CTOR時に他の比較的複雑なインジェクションの数を要求する場合です。これは通常、を組み込むことBuilderで解決しますが、これは面倒な場合があります。

編集

以下の若者Guiceは、個別のXML / JSON構成を必要としないことを述べました。私の答えは、私自身のSpringの使い方に本当に当てはまります。


2
Guiceの良い点は、Javaで完全に構成できることです(アドオンを入手しない限り、XMLはありません)。小さなプロジェクト(私がマスキングしているもの)の場合、実際には「自動配線」で十分です。質問を更新しました。多分すべての恐怖は悪いことから来ていますか(またはあまりにもエンタープライズプライスなDIフレームワーク)?
maaartinus 14年

1
@Dennis:Guiceはまったく邪魔になりません。Guiceコンテナは、オブジェクトインスタンスを取得するための代替方法にすぎません。必要に応じて、コンストラクタを呼び出すこともできます。これは、依存関係のモックを使用した単体テストに便利です。
kevin cline 2014年

1
特にGuiceと話すことはできませんが、シングルトンやファクトリーなどの長いライフサイクルを持つものにそれらを使用するだけで、多くのDIスタックは非常に自動化されます。コンストラクターインジェクションを備えたこれらのタイプのオブジェクトを使用すると、静的なものやハードな依存関係から簡単に離れることができます。小さなプロジェクトの場合でも、このような場合に役立ちます。DIフレームワークのより単純な機能とコンストラクターインジェクションを使用していて、多くの複雑さを追加している場合は、新しいDIフレームワークを見つけてください。
danwyand 14年

1
@maaartinus-あなたはそれについて正しいかもしれません。私は正直に言うとGuiceに詳しくないので、私の答えは主にSpringに当てはまると思います。
デニス

4

IoCコンテナーを使用することの主な欠点は、それが舞台裏で行うすべての魔法です。(これも、別の一般的な魔法のツールであるORMの問題です。)IoCの問題のデバッグは、依存関係がいつどのように満たされているかを確認することが困難になるため、楽しくありません。デバッガーで依存関係の解決をステップ実行することはできません。

コンテナーでは、「クラスAに1つのバージョンの依存関係があり、クラスBに別のバージョンがある」、または抽象化が再利用される同様のシナリオを構成するのが面倒です。同じことを意味する場合でも、すべてのクラスに独自のインターフェースがある状況になる可能性があります。これにより、インターフェースを再利用するという抽象化の力からブロックされます。

私の意見では、IoCから得られる本当に大きな勝利は、自動ライフスタイル管理です。コンポーネントをシングルトン、リクエストごとのシングルトン、一時的なインスタンスなどとして宣言できます。コンテナがすべてを処理します。-式を使用してこれを設定することはかなり困難newです。一方、ライフスタイルの不一致によってリソースリークが発生するのは依然として簡単です。

一部のプロジェクトは、IoCを使用して、システム内のすべてを構築しますnew。ビジネスデータを表すクラスでさえ、キーワードはありません。カプセル化が不十分なクラスやインターフェースが多すぎることをお勧めするため、これは一般に間違いだと思います。コードがIoCに依存するようになります。また、過剰テストと併存するようです。

個人的に、私は一般的にコンテナなしで行くことを好みます。代わりnewに、コンポジションルートにカプセル化された-式を使用してオブジェクトを作成します。特定のクラスの具体的な依存関係を確認するのは簡単です。コンストラクタを変更すると、コンパイル時エラーが発生します。どちらもメンテナンスに大きな影響があります。また、異なるコンポーネントを使用して個別のインスタンスを構成するのも簡単です。

IoCコンテナーを使用する場合の私のアドバイスは、システムへのエントリーポイントで依存関係を満たし、実際の依存関係(リポジトリーなど)にのみ使用することです。また、依存関係注入を引き続き使用でき、コンテナーを使用せずに構成を1つのファイルに保存することもできます。


1
「依存関係注入を引き続き使用でき、コンテナーを使用せずに構成を1つのファイルに保存することもできます。」++。DIとDIコンテナーフレームワークは同じものではないことを忘れている人が多すぎると思います。
RubberDuck 2015

1

一部の開発者は、コードで使用するフレームワークは後日潜在的な問題になると主張します。通常、コードを正しく操作するには特定の方法でコードを記述する必要があるため、後日問題が発生する可能性があるためです。これらの方法は他の設計要件と矛盾することがわかりました。この懸念の例は、ボブマーティンがここに示しています。私は個人的には同意しませんが、彼の主張は理解できます。


2
したがって、このフレームワークをより複雑なプロジェクトで使用することで得られる利点は、リスクに見合う価値があるのでしょうか。
JeffO 2014年

1

要約すると、唯一の複雑さは、不適切な構成メソッドの使用(そう、XMLはタイプセーフではない)によるものであり、フレームワークがはるかに多くの作業(Springがオブジェクトライフサイクルを管理し、DIをはるかに超える)によるものであるようです。

単純なプロジェクトの場合、DIを正しく実行すると非常に便利です。

  • 最小限の労力でサービスを小さな不変クラスとして書くことができます
  • テスト可能な状態を保ちながら、適切な範囲での単一性を保証します
  • 構成はほとんど必要ありません(20 DIクラスごとに約1行)

また、すべて手動で行うことができるため、害はありません。それは単にインスタンスを作成し、さらにインスタンスを作成するためにそれらをコンストラクターに渡すことなどです。退屈で長く、シンプルです。

GuiceとLombokを使用した典型的なサービスは次のようになります

@Singleton
@RequiredArgsConstructor(onConstructor=@__(@Inject))
public class TotalCostsComputer {
    public CostsResult getCosts(Goods goods, Shippment shippment) {
        return taxComputer.applyTax(composeResult(
                    goodsCostComputer.getCosts(goods),
                    shippmentCostComputer.getCosts(shippment));
    }
    ...

    private final GoodsCostComputer goodsCostComputer;
    private final ShippmentCostComputer shippmentCostComputer;
    private final TaxComputer taxComputer;
}

ここで、依存関係を追加することは、新しいプライベート最終フィールドを追加することを意味します。nullにすることはできません(Guiceは@NonNullがなくてもこれを保証します)。

テストとは、独自のインスタンスを作成するか、インスタンスから取得することを意味しますInjector(一部のスタブを返すように構成されている可能性があります)。どちらも非常に単純です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.