--- category: Unified tags: [Design Patterns, OOP, SOLID, Software Architecture] title: Dependency Injection (DI) description: 객체의 생성과 사용을 분리하고, 필요한 의존성을 외부에서 주입하여 결합도를 낮추는 설계 패턴 last_updated: 2026-05-02 --- # Dependency Injection (DI) ## 📌 Brief Summary **의존성 주입(Dependency Injection, DI)**은 객체 지향 프로그래밍에서 객체 간의 결합도를 낮추기 위해 사용되는 설계 패턴입니다. 객체가 내부에서 필요한 의존 객체를 직접 생성(new)하지 않고, 인터페이스를 통해 외부(프레임워크나 컨테이너)로부터 주입받는 방식을 의미합니다. 이는 SOLID 원칙 중 하나인 **의존성 역전 원칙(DIP)**을 실현하는 핵심 메커니즘으로, 코드의 유연성, 재사용성, 그리고 테스트 용이성을 획기적으로 향상시킵니다. --- ## 📖 Core Content ### 1. 주요 주입 방식 * **생성자 주입 (Constructor Injection):** 객체 생성 시점에 의존성을 주입받는 방식으로, 필드를 `final/readonly`로 유지할 수 있어 불변성을 보장하고 가장 권장되는 방식입니다. * **세터 주입 (Setter Injection):** 객체 생성 후 세터 메서드를 통해 의존성을 주입합니다. 선택적 의존성이 있거나 실행 중에 변경이 필요할 때 사용합니다. * **인터페이스 주입 (Interface Injection):** 주입을 담당하는 인터페이스를 통해 의존성을 제공받습니다. (상대적으로 사용 빈도가 낮음) ### 2. 제어의 역전 (IoC)과의 관계 DI는 **제어의 역전(Inversion of Control)**을 실현하는 구체적인 방법 중 하나입니다. 객체의 생성 주기와 의존성 조립의 권한을 객체 자신이 아닌 외부의 **IoC 컨테이너**(Spring의 ApplicationContext, NestJS의 Module 등)로 위임함으로써 개발자는 비즈니스 로직에만 집중할 수 있게 됩니다. ### 3. 실무 설계 패턴 (Frameworks) * **NestJS:** `@Injectable()`과 모듈 시스템을 통해 강력한 DI 컨테이너를 제공합니다. TypeScript의 타입을 토큰으로 활용하여 의존성을 자동 연결합니다. * **Spring Boot:** `@Autowired`나 생성자 주입을 통해 Bean 간의 의존성을 관리합니다. * **Riverpod (Flutter):** 상태 관리 기능에 DI를 결합하여 컴파일 타임 안정성을 제공하고 위젯 트리 외부에서 의존성을 안전하게 제공합니다. --- ## ⚖️ Trade-offs & Caveats ### ✅ Benefits * **낮은 결합도:** 객체 간의 직접적인 참조가 줄어들어 특정 구현체가 변경되어도 이를 사용하는 코드를 수정할 필요가 없습니다. * **테스트 용이성:** 실제 DB나 API 객체 대신 Mock(가짜) 객체를 외부에서 주입하여 독립적인 단위 테스트가 가능합니다. * **유지보수성:** 객체의 생성 로직이 한곳(Composition Root)에 모여 있어 시스템 구성 파악이 용이합니다. ### ⚠️ Challenges * **초기 복잡성:** 단순한 프로젝트에서는 인터페이스 정의와 프레임워크 설정 등이 오버헤드가 될 수 있습니다 (Overkill). * **런타임 오류:** 의존성이 런타임에 주입되므로, 설정 오류로 인한 주입 실패를 컴파일 시점에 발견하기 어려울 수 있습니다 (단, 최신 프레임워크는 이를 상당 부분 개선함). * **코드 추적의 어려움:** 객체 생성 로직이 외부에 감추어져 있어, 코드를 처음 읽는 개발자가 실제 어떤 클래스가 사용되는지 파악하기 위해 미로를 헤매는 현상(The Hidden Maze)이 발생할 수 있습니다. --- ## 🔗 Knowledge Connections ### Related Concepts * [[Dependency_Inversion_Principle]]: DI가 추구하는 근본적인 객체지향 설계 원칙입니다. * [[Hexagonal_Architecture]]: 도메인 포트에 외부 어댑터를 주입할 때 DI를 필수로 사용합니다. * [[Inversion_of_Control]]: 객체의 생명 주기를 프레임워크에 위임하는 상위 개념입니다. ### Practical Application Contexts * **Unit Testing:** 테스트 환경에서 Mock Repository를 주입하여 비즈니스 로직을 검증합니다. * **Polyglot Infrastructure:** 설정 파일만 변경하여 SQL DB 어댑터를 NoSQL DB 어댑터로 교체합니다. --- ## 💡 Adjacent Topics * [[NestJS]]: DI를 기반으로 아키텍처를 강제하는 대표적인 Node.js 프레임워크입니다. * [[Composition_Root]]: 애플리케이션 진입점에서 모든 객체 의존성을 조립하는 지점입니다. * [[Service_Locator_Pattern]]: DI와 유사하지만 객체가 직접 저장소를 호출하여 의존성을 찾는, 지양해야 할 안티패턴입니다. --- *Last updated: 2026-05-02*