[NestJS] - 4. DI / IoC (의존성 주입/제어의 역전)
이전 포스팅에서 Nest의 모듈 구조에 대해서 간단하게 훑어 보았었는데, 이런 모듈간의 결합이 어떠한 방식으로 이루어지는지에 대해서 알아보려고 한다. Nest.js를 학습하면서 느끼는 것은 Spring과 유사한 면이 있다는 것인데, 아래의 특징들 때문인 것 같다.
싱글턴 패턴 (Singleton Pattern)
싱글턴 패턴은 변하지 않는 속성과 상태를 가지는 하나의 클래스는 하나의 인스턴스만 생성하여 사용하겠다는 디자인 패턴이다.
계산기 클래스를 사용할 때 마다 new 계산기()를 하지 않고 하나의 인스턴스를 필요할 때마다 사용하는 방식 |
- 데코레이터(@Module, @Injectable, @Controller 등 ..)를 통해 작성된 모듈들은 싱글톤 패턴을 따른다.
- 인스턴스를 매번 생성하지 않고, 필요하지 않을 때 인스턴스를 삭제하지 않아도 되어 효율적인 메모리 공간 관리에 용이하다.
- 싱글톤으로 사용할 클래스는 일반적으로 생성자를 통해 공급받는다. 따라서 모듈들의 의존성을 쉽게 파악하고 구조화할 수 있다.
- 생성된 하나의 인스턴스를 사용할 때에는 private readonly를 통해 의존성을 주입받아, 변하지 않는 속성과 상태를 유지할 수 있다.
DI (Dependency Injection, 의존성 주입)과 IoC(Inversion of Control, 제어의 역전)
IoC는 제어의 역전이라는 말 그대로를 따른다. 인스턴스의 생명주기 관리의 측면에서의 IoC에 대해 설명해보면 일반적인 코드에서 인스턴스들을 코드 내에서 생성하고, 삭제하는 것은 개발자들의 영역이었는데, 이를 매번 관리하기란 쉽지가 않다. 따라서 Nest 프레임워크가 객체의 생성과 관리, 제공을 프로그래머가 아닌 프레임워크가 제어의 주체가 되는 것이다.
프로그래머 입장에서는 프레임워크의 규칙만 따라주면 관리와 제어를 프레임워크가 대신 해 주므로 한 작업에 집중할 수 있다.
DI는 의존성 주입이라는 뜻을 가지는데, 이는 외부의 객체가 의존하는 다른 객체를 직접 생성하는 것이 아닌 외부로부터 받는 것을 뜻한다.
NestJS에서는 생성된 싱글턴 인스턴스를 외부에서 변경되지 않게 하기 위해서 보통 생성자를 통해(private readonly 사용) 넣어주는 형태의 DI를 사용한다.
의존성이 무엇이라고 하면 B 클래스에서 A의 기능을 사용하고 있다면 B는 A에 의존하고 있다고 표현한다.
B가 A가 필요하다면 직접 가져오는 것이 아니라 B가 프레임워크에 "나는 이게 필요해"라고 쪽지를 적어두면 프레임워크가 알아서 A를 생성해주고, 가져다주고, 생명주기를 관리해주는 것을 대신 해준다. 이처럼 외부에서 필요한 것을 대신 주입시켜 주는 것을 의존성 주입이라고 표현한다.
만약 위의 그림과 같이 A 클래스를 사용할 때마다 직접 인스턴스를 생성하고 삭제를 한다고 가정해보자. 이 때에 B와 C는 A의 기능이 있어야 작동할 수 있으므로 B와 C는 A에 의존하고 있다.
그러나 시간이 지나 A클래스가 Extend된 A+클래스로 변경을 해야한다고 생각하면, 저 빨간 네모 박스들을 전부 바꾸어 주어야 한다. 이를 강한 결합이라고 한다.
또한, A의 인스턴스들의 생명주기 관리를 B와 C에서 담당해야 한다. 이 과정에서 프로그래머 입장에서는 메모리 관리까지 신경써주어야 하며, 실수는 곧 Memory Leak으로 이어질 수 있다.
인스턴스의 생성과 생명주기 관리, 의존성 주입을 Nest가 담당한다. 다른 클래스에서 A가 필요하다면 B의 Module에서 필요한 것을 요청을 해두고, A를 받을 곳인 생성자에만 명시해두면 Nest가 알아서 해준다는 것이다.
이럴 경우 싱글턴 패턴으로 하나의 인스턴스만 생성하고, 관리는 프레임워크가 해주므로 생명주기 관리에 신경을 덜 수 있다. 프로그래머는 단지 어떻게 사용할 것인가에만 집중할 수 있다.
또한 A 대신 의존해야 할 대상이 바뀌는 경우에도 인스턴스를 사용하는 모든 곳을 바꾸는 것이 아닌, 모듈에서 이게 필요해에서 저게 필요하게 됬어로만 바꿔주면 된다. (느슨한 결합)
Nest의 DI / IoC 동작방식 정리
1. 인스턴스의 생성
- 데코레이터(@Injectable, @Controller, @Module 등)이 붙은 클래스들을 DI 컨테이너에 등록하고 싱글턴 패턴의 인스턴스를 생성한다.
- 인스턴스는 최초 생성 후 필요시 계속 재사용된다.
2. 의존성 주입
- NestJS의 IoC 컨테이너가 Module에 등록된 의존성을 파악한다.
- 생성자를 통해 의존성을 주입한다.
다음 포스팅에서는 실제로 프로젝트에서 여러개의 모듈간에 의존성을 설정해보고 사용해보는 내용을 다루려고 계획중이다.
해당 강의를 들으면서 학습한 내용을 바탕으로 저만의 프로젝트를 만드는 과정을 기록하여 남기는 것을 목표로 하고 있습니다.
주관적인 생각이 들어가 있을 수 있으므로 혹시 틀린 내용이 있다면 피드백 부탁드립니다.
'Backend > Node.js (NestJS)' 카테고리의 다른 글
[NestJS] - 6. 상품 REST API 만들기 (0) | 2023.02.09 |
---|---|
[NestJS] - 5. 모듈 의존성 주입, 다른 모듈의 서비스를 사용해보자 (0) | 2023.02.09 |
[NestJS] - 3. 모듈 구조 - Module/Service/Controller (0) | 2023.02.09 |
[NestJS] - 2. NestJS 프로젝트 생성 (0) | 2023.02.08 |
[NestJS] - 1. NestJS 소개 (0) | 2023.02.08 |