미루고 미루다가 오늘 드디어 NestJS의 꽃인 Provider와 필수로 알고 가야되는 Ioc, DI에 대해 포스팅 해보려고한다.
처음 공식문서를 접했을 때엔 이게 무슨소린가 싶었지만 너무나 중요한개념이라서 관련문서를 끊임없이 찾아보았다.
솔직히 개념적으로 모르더라도 NestJS로 개발하는데 큰 어려움은 없지만 제대로 알고 개발을 하고 싶었다.
- Provider
우선 Provider를 사전적 의미로 보면 제공자이다.
뭘 제공하느냐?
의존성을 주입할 수 있다는 말이다.
의존성을 주입할 수 있다는 의미는 object가 다른 object와 다양한 관계를 만들 수 있고,
객체의 인스턴스를 연결해주는 기능은 Nest 런타임 시스템에 위임될 수 있다.
그리고 대부분 NestJS의 클래스는 service, repository, factory ,helper 등 provider로 취급될 수 있다.
- DI ( 의존성 주입, dependency Injection )
먼저 쉽게 위키피디아에 나와있는 5살에게 DI 설명하기를 보자.
너가 스스로 냉장고로 가서 무언가를 꺼내오려고 할 때 문을 닫지 않고 열어두거나 엄마나 아빠가 너가 안먹었으면 좋겠다고 생각하는 것들을 갖게 되는 문제가 생길 수 있어.
아니면 유통기한이 지난 것이나 갖고 있지 않는 것을 찾을 수 있지.
그럴 때 너가 해야할 일은 "점심 먹을 때 마실 게 필요해요"라고 우리에게 말한다면 너가 점심을 먹으려고 할 때 우유를 가져다 줄게.
- 위키피디아 -
즉 DI는 우리가 어떤 것을 필요로 할때 필요하다고 선언을 하면 프로그램은 그것을 가져다 주는 것이다.
다양한 언어에서 클래스를 사용하려면 new 같은 키워드로 인스턴스화 시키지만
여러개의 내용을 업데이트 하게 되면 일일히 다 바꿔줘야되는 번거로움이 있다.
이는 좋지 못한 객체지향 설계이다.
반면 DI는 객체간에 의존성이 줄어들고 재사용성이 높은 코드가 된다.
그리고 코드가 짧아지므로 가독성이 높아진다.
@Injectable() 데코레이터는 이 class를 DI system에 활용하겠다는 것을 의미한다.
private를 사용하면 동일한 위치에서 즉시 NoticeRepository 멤버를 선언하고 초기화 할 수 있다.
DI를 사용하면 NestJS가 Appservice의 생성과 소멸을 알아서 잘 관리해준다.
이런것들을 관리해주는게 IoC Container이다.
- Ioc ( 제어의 역전, Inversion of control )
처음 보자마자 ??? 밖에 안떠올랐다.
쉽게 말해서 프레임워크(NestJS)가 나를 대신해서 제어한다는 것이다.
코드를 보면 이런식으로 NoticeService는 NoticeRepository에 의존하고 있다.
하지만 NoticeRepository 객체의 사이클에는 전혀 관여하지 않는다.
단지 NoticeService의 생성자의 주어진 객체를 가져다 쓰고 있다.
이 역할을 하는 것이 IoC 이다.
위 코드처럼 DI를 구현하기 위해서는 IoC의 컨테이너 기술이 필요하다.
쉽게말해 IoC는 Provider를 다른곳에 주입할 때 사용하는 기술이다.
또한 NestJS는 프레임워크에 IoC를 구현하고 있다.
라이브러리는 내가 주도권을 가지고 각각의 의존성을 설계하고 능동적으로 만드는 반면
프레임워크(NestJS)는 내가 작성한 앱이 수동적으로 프레임워크에 의해 사용된다.
내가 작성한 코드의 동작방식을 NestJS에게 맡기는 거나 다름없다.
이렇게 정리를 해보았는데 부족하거나 이해가 안가는 내용은 NestJS 공식문서를 참조하면 좋을 것 같다.
NestJS 공식문서가 개념잡기엔 정말 최고인듯 싶다...!