d8a80f6272
이름만 다른(표기 변형) [[위키링크]]를 대상 문서의 canonical 제목으로 치환해 끊겼던 1,200개 링크를 연결. 제목/파일명 정규화 일치만 적용하고 별칭 매칭은 과병합 위험으로 제외(애매성 가드). 원본은 _link_reconcile_backup/ 에 백업. 도구: Datacollect/scripts/link_reconcile_apply.mjs Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
8.0 KiB
8.0 KiB
id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
| id | title | category | status | canonical_id | aliases | duplicate_of | source_trust_level | confidence_score | verification_status | tags | raw_sources | last_reinforced | github_commit | tech_stack | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| wiki-2026-0508-dependency-injection | Dependency Injection (DI) | 10_Wiki/Topics | verified | self |
|
none | A | 0.95 | applied |
|
2026-05-10 | pending |
|
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)
class UserService {
private db = new PostgresDatabase(); // 매 매 directly create
save(user) { this.db.save(user); }
}
With DI
class UserService {
constructor(private db: Database) {} // 매 외부 inject
save(user) { this.db.save(user); }
}
// 매 wiring
const service = new UserService(new PostgresDatabase());
매 3 type
- Constructor injection (recommended).
- Setter injection.
- 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).
매 응용
- Testing: 매 mock 의 swap.
- Multi-implementation: 매 dev / prod / test.
- Plugin architecture.
- Hexagonal / Clean Architecture.
💻 패턴
Constructor injection (TypeScript)
interface Database {
save(user: User): Promise<void>;
}
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
@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)
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)
@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)
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)
// 매 ❌ Concrete dependency
class OrderService {
notifyUser(user: User) {
new EmailSender().send(user.email, 'Order confirmed');
}
}
// 매 ✅ Abstraction
interface Notifier {
notify(user: User, message: string): Promise<void>;
}
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)
// 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
import { MockProxy, mock } from 'jest-mock-extended';
describe('UserService', () => {
let service: UserService;
let mockDb: MockProxy<Database>;
beforeEach(() => {
mockDb = mock<Database>();
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)
// 매 매 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)
// 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 |