--- id: wiki-2026-0508-dependency-injection title: Dependency Injection (DI) category: 10_Wiki/Topics status: verified canonical_id: self aliases: [DI, IoC, dependency injection, constructor injection, DIP, container, factory] duplicate_of: none source_trust_level: A confidence_score: 0.95 verification_status: applied tags: [dependency-injection, ioc, dip, solid, design-pattern, testing, container] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: language: TypeScript / Python / Java framework: Spring / NestJS / FastAPI / Awilix / tsyringe --- # Dependency Injection (DI) ## 매 한 줄 > **"매 class 내부 의 new X — 매 외부 의 inject"**. 매 IoC (Inversion of Control) 의 implementation. 매 SOLID 의 D (Dependency Inversion Principle). 매 testability + 매 swap 의 enable. 매 modern: 매 minimalist (functional injection > heavy container). ## 매 핵심 ### Without DI (tight coupling) ```ts class UserService { private db = new PostgresDatabase(); // 매 매 directly create save(user) { this.db.save(user); } } ``` ### With DI ```ts class UserService { constructor(private db: Database) {} // 매 외부 inject save(user) { this.db.save(user); } } // 매 wiring const service = new UserService(new PostgresDatabase()); ``` ### 매 3 type 1. **Constructor injection** (recommended). 2. **Setter injection**. 3. **Interface injection**. ### 매 lifetime - **Singleton**: 매 1 instance (e.g., DB connection pool). - **Scoped / Request**: 매 매 request. - **Transient**: 매 매 inject 의 새 instance. → 매 wrong choice 의 memory leak / state share 의 cause. ### 매 framework #### Java / Kotlin - **Spring**: 매 enterprise standard, 매 annotation. - **Guice**: 매 lighter. - **Dagger**: 매 compile-time. #### .NET - 매 built-in IServiceCollection. #### TypeScript / JS - **NestJS**: 매 Spring-like. - **Awilix / tsyringe**: 매 lightweight. - **InversifyJS**: 매 decorator-based. #### Python - **FastAPI**: 매 Depends() function. - **Dependency-injector**. - **manual** (most common in Python). #### Go - **Wire** (Google): 매 compile-time. - 매 manual (idiomatic). ### 매 modern critique - 매 heavy DI container 의 over-engineering. - 매 "manual DI" / "functional DI" 의 simpler. - 매 small project 의 anti-pattern (over-abstraction). ### 매 응용 1. **Testing**: 매 mock 의 swap. 2. **Multi-implementation**: 매 dev / prod / test. 3. **Plugin architecture**. 4. **Hexagonal / Clean Architecture**. ## 💻 패턴 ### Constructor injection (TypeScript) ```ts interface Database { save(user: User): Promise; } class PostgresDB implements Database { async save(user: User) { /* ... */ } } class InMemoryDB implements Database { // 매 testing private store = new Map(); async save(user: User) { this.store.set(user.id, user); } } class UserService { constructor(private readonly db: Database) {} async save(user: User) { await this.db.save(user); } } // 매 wiring const prodService = new UserService(new PostgresDB()); const testService = new UserService(new InMemoryDB()); ``` ### NestJS ```ts @Injectable() export class UserService { constructor( @Inject('DATABASE') private db: Database, private logger: Logger, ) {} } @Module({ providers: [ UserService, { provide: 'DATABASE', useClass: PostgresDB }, ], }) export class UserModule {} ``` ### FastAPI (functional DI) ```python from fastapi import Depends, FastAPI app = FastAPI() def get_db() -> Database: return PostgresDB() def get_user_service(db: Database = Depends(get_db)) -> UserService: return UserService(db) @app.post('/users') async def create_user(user: User, service: UserService = Depends(get_user_service)): return await service.save(user) ``` ### Spring (annotation) ```java @Service public class UserService { private final Database db; @Autowired // 매 constructor 의 default 의 optional public UserService(Database db) { this.db = db; } } @Configuration public class AppConfig { @Bean public Database database() { return new PostgresDB(); } } ``` ### Manual DI (Python — common idiom) ```python class UserService: def __init__(self, db: Database, logger: Logger): self.db = db self.logger = logger def save(self, user): self.db.save(user) # 매 main.py def main(): db = PostgresDB(connection_string=os.getenv('DB_URL')) logger = Logger() service = UserService(db, logger) app = create_app(service) app.run() ``` ### Dependency Inversion Principle (DIP) ```ts // 매 ❌ Concrete dependency class OrderService { notifyUser(user: User) { new EmailSender().send(user.email, 'Order confirmed'); } } // 매 ✅ Abstraction interface Notifier { notify(user: User, message: string): Promise; } class OrderService { constructor(private notifier: Notifier) {} async notifyUser(user: User) { await this.notifier.notify(user, 'Order confirmed'); } } // 매 implementations class EmailNotifier implements Notifier { ... } class SMSNotifier implements Notifier { ... } class SlackNotifier implements Notifier { ... } ``` ### Lifetime example (NestJS) ```ts // Singleton (default) @Injectable() class CacheService {} // Request-scoped @Injectable({ scope: Scope.REQUEST }) class RequestContext { constructor(@Inject(REQUEST) private req: Request) {} } // Transient @Injectable({ scope: Scope.TRANSIENT }) class IDGenerator {} ``` ### Test with mock ```ts import { MockProxy, mock } from 'jest-mock-extended'; describe('UserService', () => { let service: UserService; let mockDb: MockProxy; beforeEach(() => { mockDb = mock(); service = new UserService(mockDb); }); it('saves to db', async () => { const user = { id: '1', email: 'x@y.z' }; await service.save(user); expect(mockDb.save).toHaveBeenCalledWith(user); }); }); ``` ### Functional DI (modern minimalist) ```ts // 매 매 high-order function type Deps = { db: Database; logger: Logger }; const createUserService = (deps: Deps) => ({ save: (user: User) => deps.db.save(user), delete: (id: string) => deps.db.delete(id), }); // 매 use const service = createUserService({ db, logger }); ``` ### Wire (Go) ```go // wire.go //go:build wireinject package main import "github.com/google/wire" func InitializeUserService() *UserService { wire.Build(NewPostgresDB, NewLogger, NewUserService) return &UserService{} } ``` ## 매 결정 기준 | 상황 | Approach | |---|---| | Enterprise Java | Spring | | Modern TS backend | NestJS | | Python web | FastAPI Depends | | Small Python | Manual DI | | Testable code | DI (구조 무관) | | Plugin system | DI container | | Single-use script | No DI (overkill) | **기본값**: Constructor DI + 매 manual wiring at composition root. ## 🔗 Graph - 부모: [[Design-Patterns]] · [[SOLID]] · [[Clean-Architecture]] - 변형: [[Constructor Injection]] - 응용: [[Hexagonal Architecture]] · [[Bounded Contexts (DDD)]] - Adjacent: [[Software Architecture Styles]] · [[Architecture Anti-patterns]] · [[Anaemic Domain Model]] · [[Clean-Code-Principles]] ## 🤖 LLM 활용 **언제**: 매 architecture review. 매 testability improve. 매 multi-impl swap. 매 onboarding code. **언제 X**: 매 single function utility (overkill). 매 prototype. ## ❌ 안티패턴 - **Service Locator** (anti-pattern in many views): 매 hidden dependency. - **Magic injection** (annotation overuse): 매 trace 어려움. - **Wrong lifetime**: 매 singleton 가 매 request state 의 hold. - **DI 의 small project 의 force**: 매 over-engineering. - **Field injection**: 매 immutability lose. - **Circular dependency**: 매 design smell. ## 🧪 검증 / 중복 - Verified (Fowler IoC, Spring docs, NestJS docs). - 신뢰도 A. - Related: [[Software Architecture Styles]] · [[Clean-Code-Principles]] · [[Code_Smells]] · [[Bounded Contexts (DDD)]] · [[Anaemic Domain Model]]. ## 🕓 Changelog | 날짜 | 변경 | |---|---| | 2026-05-08 | Phase 1 | | 2026-05-10 | Manual cleanup — types + lifetime + 매 NestJS / FastAPI / Spring / Go Wire / functional code |