LASSIC Media らしくメディア

2026.07.31 らしくコラム

依存性注入(DI)とは|疎結合とテスト容易性

システム開発の発注担当者やプロジェクトマネージャーが、開発会社との設計レビューで「依存性注入(DI)を採用します」という説明を受ける場面があります。実装の細部まで踏み込まなくても、DIが何を解決する仕組みかを押さえておけば、その説明の妥当性を判断する材料になるでしょう。名前だけを聞いて通り過ぎてしまうと、後になって「なぜこの設計になっているのか」を追いにくくなる原因にもなりかねません。

本稿は、部品どうしの結びつきをゆるめ、差し替えやテストをしやすくするDIという設計手法に絞って整理する記事です。オブジェクト指向設計の一般論やデザインパターン(GoF、Gang of Fourがまとめた設計パターン集)全般の解説は、他の記事に譲ります。発注・レビューの現場で使える形に、論点を絞り込みました。

コンセントにプラグを差し込むイメージ。必要な部品を外部から渡す依存性注入の比喩

この記事のポイント

  • 依存性注入(DI)は、部品を内部で自前生成せず外部から受け取ることで、部品どうしの結びつきをゆるめる設計手法です。
  • 自前生成と外部注入の違いを比較表で整理し、テストのしやすさや実装の差し替えやすさへの影響を確かめます。
  • 発注・レビューの場面では、テスト容易性の要件化やDIコンテナの採用方針、過剰設計になっていないかの見極めが論点になります。

依存性注入(DI)とは

依存性注入(DI、Dependency Injection)とは、あるプログラム部品が必要とする別の部品を、その内部で自前で作らず、外部から渡してもらう作りにする設計手法です。Wikipedia日本語版でも、あるオブジェクトが依存する別のオブジェクトを外部から受け取るデザインパターンとして説明されています*1

たとえるなら、大工が現場で使う道具を自分で一から作らず、道具箱から受け取って使う関係に近いものです。部品Aが部品Bという道具を内部で生成するのではなく、外側から渡された道具を使う発想が、DIの骨格になります。

この結びつきの弱さは「疎結合」と呼ばれ、反対に部品どうしが強く結びついた状態は「密結合」と呼ばれます。部品Aのコードの中に部品Bの具体的な作り方が書き込まれているほど密結合に近づき、Aのコードを直さずにBを差し替えられるほど疎結合に近づく、という関係でとらえるとよいでしょう。

この考え方はめずらしいものではなく、Spring FrameworkやASP.NET Core(Microsoft社が提供する.NET向けの開発基盤)など、幅広いフレームワークが標準機能として組み込んでいます*2*3。次の章では、DIを使わない場合との対比から、その値打ちを確かめていきます。

DIは、より広い概念である制御の反転(Inversion of Control、IoC。部品の組み立てを誰が主導するかという考え方)を実現する、具体的な手段の一つに位置づけられます*4。呼び出す側が部品の生成や組み立てを自分で握るのではなく、外側の仕組みに委ねる、という主導権の移動がIoCの骨子です。DIはその移動を「外部から渡してもらう」という形で実現する手法だと捉えると、位置づけがつかみやすいでしょう。開発会社との会話で「IoC」という語が出てきた場合も、根っこにある考え方はDIと同じだと理解しておけば、議論についていきやすくなります。

なぜ使うのか 自前生成と外部注入の違い

部品Aが必要とする部品Bを、Aの内部でその都度new(生成)する作り方があります。実装を始めた当初はシンプルに見える作り方ですが、この作り方では、AのコードがBという具体的な実装に直接結びつくため、Bを差し替えたいときはAのコードにも手を入れることになります。

図
図:部品を内部で自前生成する設計と、外部から注入する設計の対比

外部から渡す形にすると、この結びつきをゆるめられます。Aは「Bという役割を持つ何か(インターフェース)」だけを知っていればよく、実際にどの実装を渡すかは呼び出す側が決められるからです。渡す部品を差し替えれば、Aのコードを変えずに振る舞いを切り替えられます。

観点 自前生成(内部でnew) 外部から注入(DI)
部品どうしの結合 呼び出す側が具体的な実装に直接結びつく 呼び出す側は役割(インターフェース)だけを知る
テストのしやすさ 本物の部品しか使えず単体テストがしにくい 偽物(モック)を渡して単体で検証できる
実装の差し替え 呼び出す側のコードごと書き換えが必要になる 渡す部品を差し替えるだけで済む
導入時の準備 追加の設計はほぼ不要ですぐに書き始められる インターフェースの定義や登録作業が別途必要になる

自前生成のまま部品の数が増えていくと、ある実装を差し替えたいときに、呼び出す側のコードをひとつずつ洗い出して直す作業が発生します。影響範囲の特定に手間取れば、改修の作業量がふくらみ、想定外の手戻りにつながることもあるでしょう。

部品を渡す三つの方法

外部から部品を渡す方法には、いくつかの型があります。Wikipedia日本語版では、代表的な方法として次の三つが挙げられています*1

  • コンストラクタ注入:部品を生成するときに、コンストラクタの引数として渡す方法
  • セッター注入:生成した後、専用のメソッド(セッター)を通じて渡す方法
  • インターフェース注入:部品を受け取るための専用インターフェースを実装し、その経由で渡す方法

このうち、コンストラクタ注入は、部品が生成された時点で必要な依存関係がすべてそろう作りにできるため、広く使われている方法です*2。どの方法を選ぶかは実装の細部にあたるため、発注担当者が個別に指定する場面は限られていますが、開発会社がどの方法を基本方針にしているかを聞いておくと、設計思想を把握する手がかりになるでしょう。

方法が違っても、「部品を使う側が自分で組み立てず、外から受け取る」という骨格そのものは共通です。実装方法の名前を覚えるより、この骨格を押さえておくほうが、レビューの場では役立つはずです。

この対比が示すのは、「誰が部品を組み立てるか」という役割の置き場所の違いです。次の章では、この違いが実務のどんな場面で効いてくるのかを見ていきます。

どう役立つか テストの容易性とDIコンテナ

前の章で整理したのは「結合がゆるむ仕組み」でした。この章では、その仕組みが日々の開発でどう効いてくるかを具体的に見ていきます。

もっとも分かりやすい効果は、テストの場面に現れます。本物のデータベースに接続する部品の代わりに、決まった値だけを返す偽物(モック)を注入すれば、データベースを用意せずにロジックだけを検証できるのです。

外部サービスへの接続や決済処理のように、テストのたびに本物を動かしにくい部品ほど、この恩恵は大きくなります。偽物の実装は、目的に応じて呼び出しを記録して検証に使うものや、決まった値を返すだけの単純なものなど、いくつかの型に使い分けられることもあるでしょう。

実装の切り替えも楽になります。開発中は簡易なログ出力の実装を渡し、本番運用では監視基盤と連携する実装に差し替える、といった使い分けが、呼び出す側のコードを直さずに実現できます*3。Microsoft社の公式ドキュメントでも、ログ出力の実装を差し替える例が、DIの典型的な利点として紹介されています*3

部品の数が増えてくると、どの部品にどの実装を渡すかという組み立て作業そのものが煩雑になります。ここを引き受けるのがDIコンテナ(注入をまとめて管理する仕組み)です。あらかじめ「この役割にはこの実装を使う」と登録しておけば、部品を生成して受け渡す手間をコンテナ側が肩代わりしてくれます。Spring FrameworkのIoCコンテナや、.NETの組み込みサービスコンテナが代表例です*2*3

DIコンテナは、受け渡しだけでなく、生成した部品をいつまで使い回すか(ライフサイクル)も管理します。アプリケーション全体で一つだけ使い回す設定や、処理のまとまりごとに新しく作り直す設定など、部品の性質に応じて使い分けられているのです*3。発注担当者がここまで細部を把握する必要はありませんが、DIコンテナが「受け渡し」と「使い回し方」の両方を引き受ける仕組みだと知っておくと、開発会社との会話が噛み合いやすくなるはずです。

単体テストを増やしやすくなる性質は、CI(継続的インテグレーション。コードを変更するたびに自動でテストを走らせる仕組み)とも相性がよいものです。モックに差し替えた単体テストをCIパイプラインに組み込めば、外部サービスの状態に左右されず、変更のたびに自動で検証を回せます。

決済代行サービスと連携するシステムを開発するケースで考えてみます。開発中や検証環境では、実際に決済を発生させずに済む偽物の実装をDIで注入し、失敗時の挙動やエラー処理を繰り返し試すことができます。本番環境に切り替える段になれば、実際の決済代行サービスと接続する実装に差し替えるだけで済み、呼び出す側のコードには手を入れずに移行できるでしょう。

外部サービスとの接続を伴う開発では、こうした使い分けが検証の効率に直結します。この使い分けができる設計になっているかどうかは、契約前の技術評価でも確認しておきたいポイントです。

注意点 過剰設計にしない勘所

ここまでDIの利点を見てきましたが、どんな場面でも取り入れるべき仕組みとは限りません。この章では、導入を見送ったほうがよい場面や、運用に入ってから出てくる負担を整理します。利点だけを聞いて導入を決めると、規模に見合わない設計になりやすいでしょう。

規模が小さく、部品の差し替えもテストの独立も必要としないシステムでは、DIを持ち込む分だけインターフェースの定義や登録作業が上乗せされます。短期間で使い捨てる検証用のスクリプトのような場面まで型どおりに適用すると、コード量ばかり増えて見通しが悪くなることがあるでしょう。

DIコンテナの設定は、部品の数が増えるほど膨らんでいきます。「どの実装がどこに渡されているか」がコンテナの設定側に隠れてしまい、コードを読むだけでは処理の流れを追いにくくなる場合もあります。設定ファイルや登録コードが増えた分、変更時に見落とす箇所も増えやすくなるのです。

動作中にどの実装が実際に使われているかをコードの見た目だけで追いにくく、不具合の原因調査に一手間かかることもあります。ログ出力や開発環境の補助機能を活用し、実際に注入された実装を特定できる状態にしておくとよいでしょう。

Martin Fowler氏も、サービスの組み立てを使う側から切り離すという原則自体が重要であり、テストのしやすさを理由に無条件でDIを選ぶべきではないと指摘しています*4。乱用すれば、結合をゆるめるはずの仕組みが、かえって全体の見通しを悪くする一因になりかねません。

過剰設計の兆候を見分ける

現場でよく見られる過剰設計の兆候を、レビューの目印として挙げます。当てはまる箇所が多いほど、DIの適用範囲を見直す余地があると考えられます。

  • 実装が一つしかないのに、インターフェースだけが増え続けている
  • 設定ファイルや登録コードを追わないと、どの実装が使われているか分からない
  • 差し替えの予定もテストの独立も見込まない部品にまでDIを適用している
場面 DIが向く例 DIが過剰になりやすい例
実装の性質 外部サービスや将来切り替える見込みのある部品 実装が一つしかなく、切り替えの予定もない部品
運用期間 数年単位で保守し、機能追加が続くシステム 短期間で役目を終える検証用・使い捨てのツール
テストの重み 単体テストで細かなケースまで検証したい部分 結合テストや手動確認で足りる小さな処理

この表を見比べると、DIの向き不向きは技術の優劣ではなく、対象システムの性質で決まることが分かるはずです。案件ごとに右側の欄に当てはまる部品が多ければ、DIの適用範囲を絞る判断も選択肢に入ります。

発注・レビューで押さえる点

DIそのものを一から実装する場面は限られており、実務では既存のフレームワークやコンテナを選び、正しく使うことが中心になります。発注やレビューの段階で確認しておきたい論点を挙げます。

いずれの論点も、DIという言葉の是非を問うものではなく、「今回のシステムにどこまで適用するか」という程度の問題です。開発会社の提案を鵜呑みにするのではなく、対象システムの規模や運用期間に照らして、適用範囲の妥当性を確認する姿勢が求められます。以下では、代表的な三つの確認先を具体的に見ていきましょう。

テスト容易性を要件に含めるかどうかを決める

結合テストだけで足りるシステムなのか、単体テストで細かなケースまで確かめたいシステムなのかによって、DIをどこまで徹底するかは変わってきます。要件定義の段階で、テストの粒度と対象範囲をすり合わせておくと、設計方針のぶれを防げるはずです。

とくに、リリース後も機能追加が続く見込みのシステムでは、後から単体テストを足しやすい構造にしておく価値が大きいでしょう。反対に、短期間で完結する案件では、テストの網羅性より開発のスピードを優先する判断もあり得ます。

DIコンテナ・フレームワークの採用方針を確認する

採用する言語やフレームワークに、DIコンテナが標準で備わっているかどうかを確認します。SpringやASP.NET Coreのように組み込みの仕組みがある場合は、それを使うのが手堅い選び方です。自作のコンテナを一から用意する提案があった場合は、その理由を確認しておくとよいでしょう。

過剰設計になっていないかを見極める

すべての部品にインターフェースを用意し、隅々までDIで組み立てる設計は、一見きれいに見えても保守の負担を増やすことがあります。差し替えの見込みやテストの必要性が薄い部品にまでDIを適用していないか、レビューの観点として持っておくことが大切です。

契約・見積もりで確認する点

DIの採用は実装方針の一部であるため、見積もり金額そのものを直接左右する項目として扱われるとは限りません。ただし、単体テストの範囲を広げる方針であれば、テストコードの作成分を見積もりに含めているかどうかを確認しておく必要があります。

あわせて、採用予定のDIコンテナやフレームワークについて、開発チームが実務での使用経験を持つかどうかも聞いておきたい点です。使い慣れていない仕組みを新規に採用する場合は、設計レビューの回数を増やすなど、契約の中でチェックポイントを設けておくと、後工程での手戻りを抑えやすくなるでしょう。

チーム体制と引き継ぎへの影響を確かめる

DIコンテナの設定は、どの実装がどこに渡されるかを暗黙のうちに決めてしまう性質を持ちます。設計思想を共有できていない担当者が引き継ぐと、コードを目で追うだけでは処理の流れをつかみにくく、改修に時間がかかることがあるでしょう。保守を別の会社や社内チームへ引き継ぐ計画がある場合は、DIコンテナの設定内容や部品の一覧を、引き継ぎ資料に含めるよう依頼しておくことをおすすめします。

あわせて、開発を担当したチームが継続して保守にあたるのか、途中で体制が変わるのかによっても、必要な引き継ぎの厚みは変わってきます。体制変更の可能性がある案件では、設計方針をドキュメント化しておくよう、契約段階から求めておくと、引き継ぎ後の混乱を抑えやすくなります。

まとめ

ここまでの内容を、発注・レビューの現場で使える判断のポイントとして整理します。

  • 依存性注入(DI)は、部品が必要とする別の部品を内部で生成せず、外部から受け取る設計手法です。
  • 自前生成では呼び出す側が具体的な実装に結びつく密結合になりますが、外部注入では役割(インターフェース)だけを知っていれば済む疎結合になります。
  • テスト時に偽物(モック)を渡せる点、実装の切り替えが楽になる点、DIコンテナが組み立てや使い回し方を自動化する点が実務上の利点です。
  • 小規模なシステムや差し替えの見込みが薄い部品にまで適用すると、設定や抽象化のコストがかえって負担になります。
  • 過剰設計の兆候(実装が一つしかないのに抽象化だけが増えている等)が見られたら、適用範囲を見直す機会と捉えましょう。
  • 発注・レビューでは、テスト容易性の要件化、DIコンテナの採用方針、過剰設計の見極め、引き継ぎ資料の整備を確認するとよいでしょう。

LASSICに相談するメリット

DIをどこまで徹底するか、既存のフレームワークに任せるか自作で組み立てるかは、テストのしやすさと保守のしやすさの両方に関わる設計判断です。「開発会社の提案するDIコンテナの採用方針が妥当か判断しにくい」「テスト容易性をどこまで要件に入れるべきか整理したい」といった悩みは、業務要件と実装の両面を見ないと結論を出しにくいものでしょう。体制変更を見込んだ引き継ぎ資料の整備や、過剰設計になっていないかの点検は、外部の目を交えることで判断のぶれを抑えられます。LASSICでは、要件定義の段階からアーキテクチャ方針の整理、実装、公開済みシステムの設計見直しまで一貫してご相談いただけます。まずは現行の設計を一緒に見直すところからでも対応が可能です。お気軽にお声がけください。

よくある質問

依存性注入は、小規模なシステムでも取り入れるべきですか。

規模が小さく、部品の差し替えもテストの独立も見込まないシステムでは、DIを持ち込む分だけ設定や抽象化のコストが上乗せされます。差し替えの予定がなく、単体テストの対象にもならない部品であれば、自前生成のままで十分な場合が多いでしょう。DIを検討する目安は、実装の切り替えやテストの独立性が今後必要になるかどうかです。判断に迷う場合は、まず変更や差し替えが見込まれる部品だけに絞って適用し、様子を見ながら範囲を広げる進め方をおすすめします。

依存性注入とデザインパターン全般は、同じものと考えてよいですか。

同じものではありません。デザインパターン(GoF)は生成・構造・振る舞いに関する幅広い設計の型を扱う分野で、DIはそのうち「部品をどこで組み立てるか」という一点に的をしぼった設計手法です。DIコンテナのようにフレームワーク化されたものもありますが、DI自体はオブジェクト指向設計の一般論より狭い、限定的な概念として捉えるのが適切です。両者を混同すると、DIの説明にオブジェクト指向全般の話が混ざり、論点がぼやけやすくなるので注意しましょう。

DIコンテナを使うと、テストは自動的にしやすくなりますか。

コンテナを導入するだけで、テストのしやすさが自動で手に入るわけではありません。部品どうしがインターフェースを介してやり取りする設計になっていて初めて、モックへの差し替えが機能します。コンテナは登録した実装を組み立てて渡す役割を担うものであり、設計そのものを疎結合にするかどうかは別の作業です。設計の段階でインターフェースを介した組み立てになっているかを確認しておくことが、テストのしやすさにつながります。

DIを導入すると、設定はどのくらい増えますか。

増える量は、部品の数や採用するフレームワークによって変わるため、一概には言えません。SpringやASP.NET Coreのような標準機能を使う場合は、登録コードが数行で済むことも珍しくないでしょう。一方で部品の種類が多いシステムでは、どの役割にどの実装を渡すかという登録作業がまとまった分量になることもあります。導入前に、対象となる部品の範囲を絞っておくと見通しを立てやすくなります。設計書やコードレビューの場で、登録内容が一覧できる形になっているかを確認しておくと、後からの見直しがしやすいでしょう。

DIを採用すると、見積もりの工数は増えますか。

DIの採用そのものが見積もり金額を直接押し上げるとは限らず、あくまで実装方針の一部として扱われます。単体テストの範囲を広げる方針とセットで採用する場合は、テストコードの作成分が見積もりに含まれているかを確認しておくとよいでしょう。開発チームが採用予定のDIコンテナに使用経験を持つかどうかも、あわせて聞いておきたい点です。初めて扱うフレームワークであれば、学習の時間を見込んで、スケジュールに余裕を持たせておくことをおすすめします。

著者:テレリモ総研編集部 鈴木 亮佑

LASSICでは、国内ニアショア開発体制を活かし、DIを含むアーキテクチャ方針づくりやフレームワーク選定から実装、公開済みシステムの設計見直しまでを一貫して支援する体制です。要件定義の段階から実装、テスト、リリース後の運用・保守まで、工程を分けずに任せられる点も強みでしょう。担当チームの体制が変わる場面でも、設計方針を引き継ぎ資料に落とし込む工程を含めて対応します。DIコンテナの採用方針やテスト容易性の要件化でお困りの際も、ご相談いただけます。


アーキテクチャ設計・システム開発のご相談はLASSICへ

元請(プライムベンダー)として、要件整理からご提案・開発・保守までお手伝いします。まずはお気軽にご相談ください。

無料相談はこちら

ご不明な点はお問い合わせフォームからもご連絡いただけます。

出典


View