UnitTesting以外の価値がある依存性注入


17

初期化するいくつかのオブジェクトの異なる実装を使用する必要がないコンストラクターを考えると、DIを使用することは依然として実用的ですか?結局のところ、まだ単体テストが必要な場合があります。

問題のクラスは、コンストラクター内の他のいくつかのクラスを初期化し、使用するクラスは非常に具体的です。別の実装を使用することはありません。インターフェイスにプログラムしようとするのを避けることは正当化されますか?



3
KISS-は常に最良のアプローチです。
Reactgular

5
私の意見では、この質問は提案された複製よりも具体的です。design-for-future-changes-or-solve-the-problem-at-hand、したがって、私はこれを閉じないことを
-k3b

1
テスト可能性は十分な理由ではありませんか?
ConditionRacer

実際に自分自身に答えるほど重複しているようには聞こえません。それが決して起こらない場合、そのための設計は将来の変更のための設計ではありません。建築の宇宙飛行士でさえ、悪い判断から決して起こらない変更のためにのみ設計します。
Steve314

回答:


13

それは、「決して、これまで」が正しいことをどの程度確信しているかによって異なります(アプリが使用される間)。

一般に:

  • テスト容易性のためだけに設計を変更しないでください。ユニットテストはあなたに役立つためのものであり、その逆ではありません。
  • 繰り返してはいけません。継承者を1つしか持たないインターフェースを作成することは役に立ちません。
  • クラスがテスト可能でない場合、実際のユースケースでも柔軟性/拡張性がない可能性があります。場合によってはそれで問題ありません-その柔軟性が必要になることはまずありませんが、シンプルさ/信頼性/維持性/パフォーマンス/その他はより重要です。
  • わからない場合は、インターフェイスにコーディングしてください。要件の変更。

12
「テスト容易性のためだけに設計を変更しないでください」の場合、ほぼ-1を与えました。テスト容易性を高めることは、デザインを変更する最大の理由の1つです。しかし、あなたの他のポイントは大丈夫です。
Doc Brown

5
@docBrown-(および他の)ここで私は多くの、そしておそらく大多数とは異なります。〜95%の時間、物事をテスト可能にすることは、それらを柔軟または拡張可能にします。ほとんどの場合、それをデザインに含める(またはデザインに追加する)必要があります。他の〜5%には、この種の柔軟性を妨げて他の何かを支持するという奇妙な要件があるか、専用のテストがなくても壊れた場合に非常にすばやく見つけることができる非常に重要/不変です。
テラスティン

4
確かかもしれませんが、上記の最初のステートメントは、「テスト可能性だけが問題である場合、不適切に設計されたコードをそのままにしておく」と誤解されやすい可能性があります。
Doc Brown

1
「継承者が1人しかいないインターフェイスを作成しても役に立たない」と言うのはなぜですか?インターフェイスはコントラクトとして機能します。
カプタン

2
@kaptan-具体的なオブジェクトはコントラクトと同様に機能するため。2つにすることは、コードを2回記述する必要があることを意味します(変更された場合はコードを2回変更します)。確かに、インターフェイスの大部分には複数の(テストではない)実装があります。ただし、必要なのは単純な封印オブジェクトだけであるというまれなケースでは、直接使用するだけです。
テラスティン

12

インターフェイスにプログラムしようとするのを避けることは正当化されますか?

インターフェイスに対するコーディングの利点は明らかですが、それを行わないことで何が正確に得られるかを自問する必要があります。

次の質問は、問題のクラスが実装を選択する責任があるかどうかです。その場合もそうでない場合もあるので、それに応じて行動する必要があります。

最終的に、間抜けな制約が突然発生する可能性が常にあります。同じコードを同時に実行したい場合があり、実装をインジェクトする可能性が同期に役立つ場合があります。または、アプリをプロファイリングした後、単純なインスタンス化とは異なる割り当て戦略が必要な場合があります。または、分野横断的な懸念が生じ、AOPサポートが手元にありません。知るか?

YAGNIは、コードを記述するとき、余分なものを追加しないことが重要であることを提案します。プログラマーが気付かないうちにコードに追加する傾向があるものの1つは、不必要な仮定です。「この方法は便利かもしれない」や「これは決して変わらない」など。どちらもデザインに混乱をもたらします。


2
ここでYAGNI DIの議論として引用しているのではなく、それに対してではありません。
Doc Brown

4
@DocBrown:ここではYAGNIを使用できることを考慮し、DIを使用しないことを正当化します。それは、YAGNIが何に対しても有用な手段であることに対する議論のようなものだと思います。
スティーブンエバーズ

1
余分な仮定のための+1は、数回の頭の中で私たちを直撃しているYAGNI、中に含まれている
Izkata

@SteveEvers:依存関係反転の原則を無視することを正当化するためにYAGNIを使用すると、YAGNIやDIP、またはプログラミングと推論のより基本的な原則さえ理解できなくなる可能性があります。必要な場合にのみDIPを無視する必要があります-YAGNIがその性質上単に適用できない状況。
back2dos

@ back2dos:「多分必要条件」と「誰が知っているか」のためにDIが有用であるという仮定。まさにYAGNIが戦うことを意図した一連の思考であり、代わりに追加のツールとインフラストラクチャの正当化としてそれを使用しています。
スティーブンエバーズ

7

さまざまなパラメーターに依存しますが、DIを使用したい理由がいくつかあります。

  • テストはそれ自体がかなりの理由です
  • オブジェクトに必要なクラスは他の場所で使用される可能性があります-それらを注入すると、リソースをプールすることができます(たとえば、問題のクラスがスレッドまたはデータベース接続である場合-各クラスで新規作成しないでください)接続)
  • それらの他のオブジェクトの初期化が失敗する可能性がある場合、おそらくスタックの上位のコードは、おそらくエラーを単に転送するクラスよりも問題を処理するのに優れているでしょう

要するに、その場合はおそらくDIなしで生きることができますが、DIを使用するとコードがきれいになる可能性があります。


3

あなたがプログラムまたは機能を設計するとき、思考プロセスの一部は、必要があるあなたがそれをテストしようとしている方法であること。依存性注入はテストツールの1つであり、混合の一部として考慮する必要があります。

依存性注入の追加の利点とクラスの代わりにインターフェイスを使用することは、アプリケーションを拡張する場合にも有益ですが、後で検索と置換を使用して非常に簡単かつ安全にソースコードに後付けすることもできます。-非常に大きなプロジェクトでも。


2
 > Dependency Injection worth it **outside** of UnitTesting?
 > Are we justified in avoiding trying to program to an interface?

この質問に対する多くの答えは、ユニットテストを行いたくない場合、YAGNIとして「..が必要な可能性がある」として議論することができます。

ユニットテストのほかに、インターフェイスにプログラムする必要がある理由を尋ねる場合

はいコントロールの反転が必要な場合は、UnitTesting 以外の価値があるDependency Injection です。たとえば、あるモジュールの実装に、そのレイヤーでアクセスできない他のモジュールが必要な場合。

例:モジュールがある場合gui=> businesslayer=> driver=> common

このシナリオでbusinesslayerは、使用できますdriverが使用driverできませんbusinesslayer

よりdriver高いレベルの機能が必要な場合は、この機能businesslayerを実装して、インターフェイスをcommonレイヤーに実装できます。 レイヤーdriver内のインターフェースのみを知る必要がありますcommon


1

はい、そうです。まず、単体テストツールを中心にコードを設計する理由として単体テストを忘れてください。人為的な制約に合わせてコード設計を曲げることは決して良い考えではありません。ツールでこれを行う必要がある場合は、より優れたツール(モックオブジェクトを作成するためのより多くのオプションを許可するMicrosoft Fakes / Molesなど)を入手してください。

たとえば、テストツールがプライベートメソッドで機能しないという理由だけで、クラスをパブリックメソッドのみに分割しますか?(私は、プライベートメソッドをテストする必要がないふりをするのが一般的な知恵であることを知っていますが、これはプライベートツールをテストする必要がないという真の反応ではなく、現在のツールでテストするのが難しいことへの反応だと思います)。、

全体として、それはあなたがどんな種類のTDDerであるか- ファウラーがそれらを説明する「モック主義者」であり、使用するツールに合わせてコードを変更する必要があるのに対し、「古典的な」テスターはより自然に統合されたテストを作成します(つまり、各メソッドではなくユニットとしてクラスをテストします)、特に具象クラスをモックできるツールを使用する場合は、インターフェースの必要性が少なくなります。


3
プライベートメソッドをテストするべきではないという一般的な知恵は、テストの難しさと関係があるとは思いません。プライベートメソッドにバグがあったが、それがオブジェクトの動作に影響を与えなかった場合、それは何にも影響しません。プライベートメソッドにオブジェクトの動作に影響するバグがある場合、オブジェクトのパブリックメソッドの少なくとも1つでテストが失敗または欠落しています。
マイケルショー

それは、動作または状態をテストするかどうかにかかっています。もちろん、プライベートメソッドは何らかの方法でテストする必要がありますが、もしあなたが古典的なTDDの人なら、クラス全体をテストすることでテストします。ほとんどの人が使用するテストツールは各メソッドのテストに焦点を当てています個別に...そして、私のポイントは、完全なテストを実行する機会を逃すため、後者は事実上適切にテストしていないということです。だから私はあなたに同意しますが、TDDが今日の一部の(ほとんどの?)
gbjbaanb

1

依存性注入はまたあなたのオブジェクトがあること、それが明確になりHASの依存関係を。

他の誰かが(コンストラクターを見ずに)オブジェクトを単純に使用すると、サービスや接続などをセットアップする必要があることに気付くでしょう。コンストラクターに渡す必要がないため、明らかではありませんでした。 。依存関係を渡すと、必要なものがより明確になります。

また、クラスがSRPに違反している可能性があるという事実を潜在的に隠しています。多くの依存関係(3つ以上)を渡す場合は、クラスの処理が多すぎる可能性があるため、リファクタリングする必要があります。ただし、コンストラクターで作成する場合、このコードの匂いは隠されます。


0

私はここの両方のキャンプに同意します、そして、問題は私の意見で議論のためにまだ開いています。YAGNIは、推測に合うようにコードを変更することはしないよう要求しています。ここでは、単体テストは問題ではありません。依存関係は決して変化しないと固く信じているからです。しかし、もし私が最初から意図したとおりに単体テストをしていたなら、とにかくこの点に到達することはなかったでしょう。私は最終的にDIへの道をスリム化したので。

私のシナリオの別の代替案を具体的に提供させてください

ファクトリパターンを使用すると、1つの場所で依存関係をローカライズできます。テスト時には、コンテキストに基づいて実装を変更できますが、それで十分です。これは、いくつかのクラス構成を抽象化する利点があるため、YAGNIには反しません。

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