본문 바로가기

Sparta/TIL

24.03.04 TIL - Nest.js 기초

1. Nest.js의 장점

일단 nest와 비교하기 위해 express의 장점부터 꼽아본다면 간단한 서버를 만들 때는 분명히 빠르게 만들 수 있는 장점이 있다.그리고 디렉토리 구조를 설계할 때 자유로운 개발이 가능하다. 하지만, 복잡한 내용이 추가되면 추가적으로 작성해야 하는 코드의 양이 계속해서 늘어나고 필요한 개념들을 새로이 추가하면서 번거롭고 혼란스러워질 수 있다.

 

이러한 단점을 보완해주는 것이 Nest.js이다.

  • 타입스크립트 기반의 웹 프레임워크이기 때문에 자바스크립트에 비해 엄격한 타입체크를 함으로써 여러 에외 상황을 사전에 방지할 수 있다.
  • 레이어드 아키텍처 패턴을 구성할 때 커맨드 하나로 간편하게 대부분의 구성요소를 구현할 수 있다.
nest g co posts

예를들어 이런 명령어라고 한다면 generate controller - Posts라는 뜻이다. '네스트로 포스츠 컨트롤러를 만들겠다.'로 해석할 수 있겠다.

  • 컨트롤러 뿐만 아니라 서비스, 미들웨어, 인터셉터 등 웹서버에 필요한 다양한 구성요소를 커맨드로 정확하게 구현할 수 있다
  • 이렇게 되면 디렉토리 구조도 자동으로 잡아줘서 개발자가 비즈니스 로직의 구현에만 신경쓰고 다른부분은 Nest.js에 일임할 수 있게 된다.

 

 

2. Nest.js 개발환경 구축

1) Nest.js 설치

  • node.js와 typescript가 설치되어 있다면 명령어를 통해 Nest.js를 설치할 수 있다.
npm i -g @nestjs/cli

 

  • 그리고 'nest'라는 명령어를 터미널에 입력하면 명령어에 대한 메뉴얼을 제공한다.
  • 그리고 아래 명령어를 통해 'sparta-nest'라는 이름의 프로젝트를 생성할 수 있다. 그리고 생성하면 어떤 package manager를 사용할 지 물어보는데, 반드시 npm을 선택해야 한다. npm이 nest에 가장 호환이 잘 되기 때문!
nest new sparta-nest

 

 

2) Nest.js 코드를 통한 개념학습

a) main.ts

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
}
bootstrap();

 

이 파일은 Nest.js에서 진입점으로 사용하겠다고 사전에 약속된 파일이기 때문에 임의로 파일의 이름을 변경해선 안 된다.

 

NestFactory 클래스의 create라는 정적 함수를 통해 Nest.js 어플리케이션 인스턴스를 새롭게 생성합니다. 'AppModule이라는 모듈을 루트 모듈로 사용하는 Nest.js 어플리케이션 인스턴스를 생성해줘'라는 의미로 해석하면 된다.

 

b) 모듈

Nest.js에서 모듈은 애플리케이션의 특정 부분을 캡슐화하며, 관련된 컴포넌트, 서비스, 그리고 다른 모듈들을 그룹화
하는데, 이를 통해 레이어드 아키텍처 패턴과 같은 구조적인 아키텍처 패턴을 효과적으로 구현하고 관리할 수 있다.

 

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

 

main.ts에 있던 AppModule은 app.module.ts라는 파일에 정의되어 있는데 모듈을 만들게되면 '모듈이름'이라는 디렉토리가 src디렉토리 아래에 생기며 그 디렉토리 안에 '모듈이름.module.ts'으로 파일이 생성된다.

 

그리고 '@'이 붙는 키워드가 보이는데, 이를 데코레이터라고 하며 해당 클래스나 함수가 어떤 역할을 수행하는지에 대해 Nest.js에 알려주는 역할이다. 여기서는 @Module이라는 데코레이터가 import, controller, provider라는 속성을 가지고 있다.

 

  • imports
    •  현재 모듈에서 사용하려는 다른 모듈들의 목록을 정의합니다.
    • 이 속성에 명시된 모듈들은 주로 필요한 프로바이더(서비스)를 제공합니다.
    • 예를 들어, API 호출을 위해 자주 사용되는 HttpModule이나 데이터베이스 작업을 위한 TypeOrmModule 등이 여기에 포함될 수 있습니다.
  • controller
    • 현재 모듈과 관련된 컨트롤러의 목록을 정의
    • 이 컨트롤러들은 해당 모듈의 요청 처리 로직을 담당한다.
  • provider
    • 현재 모듈에서 사용하거나 제공하는 서비스, 리포지토리, 팩토리 등의 목록을 정의
    • 이들은 주로 피즈니스 로직 처리나 데이터 액세스 같은 작업을 수행한다.
  • exports
    • 현재 모듈에서 다른 모듈로 제공하려는 서비스의 목록을 정의
    • 이 송성에 명시된 서비스들은 외부에서도 사용할수 있으며, 따라서 다른 모듈에서 특정 서비스를 사용하려면 해당 서비스를 exports에 포함시켜야 한다.

 

3. IoC와 DI

1) IoC(제어 역전)

Inversion of Control의 준말로 개발자가 사용하고 싶은 객체를 직접 생성하는 것이 아니라 객체의 생명주기 관리 자체를 외부(여기서는 Nest.js IoC 컨테이너)에 위임한다. 즉, 객체의 관리를 컨테이너에 맡겨서 제어권이 넘어갔다는 것을 뜻하는 말이다.

 

a) 전통적인 방법의 한계

this.appService = new AppService();

위와 같이 객체를 직접 생성하는 방식을 전통적인 방식이라고 표현하는데 이렇게 되면 AppController는 AppService의 구체적인 구현에 강하게 결함된다. 즉 의존하는 서비스가 변경되면 개발자도 그에 맞춰 코드를 수정해야 하니, 자주 변경되는 서비스가 있다면 개발자는 작업량이 늘어나고 번거로운 일이 반복된다는 것이다.

 

b) IoC 원칙에 따른다면?

IoC 원칙은 모듈 간 결합도를 낮추기 때문에 하나의 모듈이 변경되어도 다른 모듈들에는 영향을 최소화되어 웹 어플리케이션을 지속 가능하고 확장성 있게 해준다.

 

 

Ioc원칙을 사용하면, AppController는 AppService의 구체적인 구현보다는 인터페이스나 추상 클래스에 의존하게 된다. 즉 서비스의 변경에는 관계 없이 사용할 수 있다. 이것은 코드 결합도의 감소를 듯하고 다른 구현체로 쉽게 교체할 수 있다는 말이다.  이런 원칙을 지원하는 것이 Nest.js이다!!

 

 

2) DI(의존성 주입) - IoC 원칙 구현방법

  constructor(private readonly appService: AppService) {} // 살포시 연착륙

 

위 코드는 Nest.js에서 제공하는 의존성 주입 매커니즘을 사용한 방식이다. Nest.js에서는 DI 컨테이너를 사용하여 이 원칙을 구현하는데, 여기서 AppService의 인스턴스는 Nest.js의 DI컨테이너에 의해 생성되고 관리된다. 따라서 개발자는 new AppService()와 같이 객체를 직접 생성하고 관리할 필요가 없이 코드의 결합도를 낮추고 유연성과 테스트 용이성을 향상시킬 수 있다.

'Sparta > TIL' 카테고리의 다른 글

24.03.06 TIL - Typescript(2)  (0) 2024.03.07
24.03.05 TIL - Typescript  (0) 2024.03.06
24.02.29 TIL - 예외처리(throw/try/catch/finally)  (0) 2024.03.03
24.02.27 TIL Mocking  (1) 2024.02.28
24.02.26 TIL - test code(1)  (0) 2024.02.27