Nest.js에서의 DI 시스템의 주요 구성 요소는 'providers'이다. providers는 값을 제공할 수 있는 것을 나타내며, 그 값은 객체, 함수의 결과 등 다양한 것일 수 있다. 클래스, 값, 팩토리 등 여러 가지 방식으로 provider를 정의할 수 있다.
Nest.js 프레임워크는 TypeScript 기반으로 구축되었기 때문에, 명확한 타입 계약과 함께 의존성을 주입하면서 안전성을 높일 수 있는 장점이 있다. 그러나 이는 단순히 TypeScript 때문만은 아니다. DI는 객체 지향 프로그래밍과 설계 패턴에서 오랜 시간 동안 널리 사용되어 온 개념이며, 동적 타이핑 언어인 JS에서도 DI를 사용하는 것이 가능하다.
Nest에서 정의된 provider는 기본적으로 Singleton이다. 즉, Nest는 특정 provider의 인스턴스를 한 번만 생성하고, 그것을 애플리케이션 전체에서 재사용한다.
필요에 따라 요청 범위의 provider도 제공된다. 이는 특정 HTTP 요청의 처리 동안만 존재하며, 처리가 끝나면 가비지 컬렉션된다.
import { Injectable, Scope } from '@nestjs/common';
@Injectable({ scope: Scope.REQUEST })
export class CatsService {}
사용자 정의 provider를 통해 다양한 방식으로 의존성을 제공할 수 있다. 이는 useValue, useClass, useFactory, useExisting 등의 키워드와 함께 사용된다.
DI를 통해 앱의 다양한 부분에서 같은 서비스나 값을 재사용할 수 있다. 이로 인해 중복 코드를 줄이고 유지 관리를 용이하게 할 수 있다.
DI를 사용하면 테스트 시 실제 서비스 대신 mock 또는 스텁을 쉽게 주입할 수 있다. 이렇게 되면 외부 의존성에 대한 걱정 없이 특정 코드 부분만 테스트할 수 있다.
DI를 통해 애플리케이션의 다양한 부분 사이의 명확한 계약을 정의할 수 있다. 이를 통해 어떤 서비스가 어떤 의존성을 필요로 하는지 명확하게 파악할 수 있다.
DI는 클래스와 그 의존성 사이의 느슨한 결합을 촉진한다. 결과적으로 앱의 부품을 교체하거나 업그레이드하기가 더 쉽다.
의존성을 명시적으로 제공하면 해당 클래스나 함수의 동작 방식을 더 명확하게 이해할 수 있다.