BE/Javascriptㅤ|ㅤTypescript

[Nest] Nest.js란? 기본개념 ( + loose coupling ) + 설치 및 폴더구조 살펴보기

Bans 2022. 7. 20. 20:19

Nest.js

 


 

앞서서 package.json (+package-lock.json) 으로

node 에서의 모듈 버전관리에 관해 간략하게 다뤘었고

(https://bans.tistory.com/22)

 

[npm] 어? 그거 그냥 만들어지던데... [ package.json ]

npm - Node Package Manager Javascript 환경에서 개발을 하는 데 빼놓을 수 없는것이 바로 npm이다. npm - node package manager 패키지를 프로젝트에 설치하거나 갱신 또는 삭제하는데 사용되는 도구를 패키지..

bans.tistory.com

 

TypeScript의 간략한 개념 및

사용하게 된 배경 등을 다뤘었다.

(https://bans.tistory.com/25)

 

[TS] TypeScript란? - 기본개념

TypeScript, 왜 만들어지게 되었는가? - TypeScript 는 Javascript 엔진을 사용하면서 커다란 애플리케이션을 개발할 수 있게 설계된 언어이다 (관련 페이지) 위키백과에 서술되어있는 TypeScript 의 시작 문

bans.tistory.com

 

 

이번엔 위의 개념들을 여럿 통합하여 만들어진

큰 그룹(기업 혹은 개발자들)에서의 큰 프로젝트 개발을 위한 Architecture,

Nest.js Framework (open source project)

에 대해 살펴보고, 기본 설치 및 기본 폴더 구조에 대해 알아보자.

 

Nest.js 공식 Docs의 첫 소개글 (https://docs.nestjs.com/)

 

 

Nest.js 공식 Docs 페이지 에서 확인해볼 수 있는 첫 소개글이다.

Node 를 사용한 서버 애플리케이션을

TypeScript 를 사용하여

효율적인 개발 Architecture (OOP, FP, FRP) 를

지원 및 구축하기 위한 프레임워크(Framework)라고 소개되고 있다.

 

(이를 이해하기 위해 OOP, FP, FRP 에 대한 간략한 이해가 필요하다 )

 

문서에 작성되어있는 다음 내용,

'철학' 의 부분을 살펴보자.

 

 

 

여러 가지 키워드가 나열되지만,

비교적 이해하기 힘들었던 키워드가 '느슨한 결합 (Loose coupling. loose coupled)' 이었다.

왜 느슨한 결합이 확장성과 유지관리성 향상에 도움이 되는 걸까?

 

이를 이해하기 위해서는 그 반대의 개념,

'강한 결합 (Tight coupling)'

에 대해 먼저 이해해볼 필요가 있다.

 

 

Tight coupling - ProductController 는 CashService 와 ProductService 에 '의존하고 있다' (Dependency)

 


제품 구매와 환불 기능을 담고있는 컨트롤러 -> product.controller.js

돈과 관련된 기능을 담고있는 서비스 -> cash.js ( 이후 cash.service.js 로 바꾸어 이름을 저장했다 )
제품과 관련된 기능을 담고있는 서비스 -> product.js ( 이후 product.service.js 로 바꾸어 이름을 저장했다 )

( 컨트롤러 (controller) 는 무엇인가? - MVC 패턴에 관한 개념을 알아보자 )

 

import { CashService } from "./services/cash.js";
import { ProductService } from "./services/product.js";

export class ProductController {
    buyProduct = (req, res) => {
        // 1-1. 가진 돈 검증하는 코드
        const cashService = new CashService();
        const hasMoney = cashService.checkValue();
    //.
    //.
    //.
    //.
    //.         이하생략

 

ProductController 클래스를 살펴보면

checkValue() 함수를 호출하기 위해

cashService 를 새로 (new) 선언해주고 있다.

그리고 호출을 위해 import 한 CashService 는

"./services/cash.js" 의 경로에서 가져오고 있음을 볼 수 있다.

 

만약, 제품 구매를 'Cash' 가 아닌 다른 재화를 통해 구매한다면?

 

실제 서비스에서 흔히 볼 수 있는 경우다.

꼭 현금 재화가 아니더라도

신용구매, 포인트구매, 각자의 서비스의 페이머니를 이용한 구매 등

구매할 수 있는 수단은 다양하다.

 

하지만, 

위의 컨트롤러의 경우

CashService 를 import 하여

사용할 때 마다 새로 선언하여 사용하기 때문에

새로운 재화로 구매하는 경우가 생기면

또 새로운 Service 소스를 작성해야 하며, 모든 코드를 교체해주어야 한다.

 

이러한 상황을 '의존성(Dependency)' 이라고 표현하고, ( 강한 결합 - Tight Coupling )

ProductController 는 CashService 와 ProductService 에 '의존하고 있다' 라고 표현한다.

 

 

위의 예시를 사용하여, 느슨한 결합의 예시를 살펴보자.

느슨한 결합 - Loose Coupling

 

 

ProductController | CashService

index                       | PointService

 

 

컨트롤러와 서비스, 그리고 그 컨트롤러를 이용하는 index까지의 4분할 화면이다.

컨트롤러와 인덱스 파일을 차례로 살펴보자.

 

import express from "express";

import { BoardController } from "./mvc/controllers/board.controller.js";
import { CouponController } from "./mvc/controllers/coupon.controller.js";
import { ProductController } from "./mvc/controllers/product.controller.js";

import { CashService } from "./mvc/controllers/services/cash.service.js";
import { PointService } from "./mvc/controllers/services/point.service.js";
import { ProductService } from "./mvc/controllers/services/product.service.js";

const app = express();
app.use(express.json());

// 서비스 의존성들  
const cashService = new CashService();
const cashService2 = new CashService(); // DI 는 맞지만, single-tone pattern 은 아닌 경우.
const pointService  = new PointService(); // 쿠폰 구매방식이 포인트결제로 변경됨.
const productService = new ProductService(); // new 한번으로 모든 곳에서 재사용 가능 (싱글 톤 패턴)

// 상품 API
const productController = new ProductController(cashService, productService);
app.post('/products/buy', productController.buyProduct); // 상품 구매 API
app.post('/products/refund', productController.refundProduct); // 상품 환불 API

//.. 이하 생략

index.js

 

 

// 서비스 의존성들

이하에 선언한 각 서비스들을, index 에서 각 Controller 들에 

<Parameters>

형태로 전달해주고 있다. 이렇게 전달하게 되면,

const productController = new ProductController(cashService, productService);

위의 cashService 의 부분을, 만일 point 결제로 바뀐다고 한다면

const productController = new ProductController(pointService, productService);

아래와 같이 바꿔서 전달하면, 코드 변경이 크게 없이 기능을 그대로 유지할 수 있을 것이다!

 

이것을 loose coupling, 느슨한 결합이라 부른다.

 


 

자! 이제 (드디어) Nest 를 설치해서

Nest의 기본 폴더구조를 살펴보자

 

 

$ npm i -g @nestjs/cli (혹은 yarn add -g @nestjs/cli)
$ nest new project-name

 

 

위의 명령어를 통해 nest 프로젝트의 첫 시작을 할 수 있다.

그리고 설치 후 처음 나타나는 폴더 구조를 '보일러 플레이트' 라고 표현한다.

 

 

다시한번 정리하지만

Nest 는

큰 그룹(기업 혹은 개발자들)에서의 큰 프로젝트 개발을 위한 Architecture

 

이기에,

함께 규칙을 맞추어 개발을 진행하기 위한 여러 설정파일들을

기본 보일러 플레이트에서부터 찾아볼 수 있다.

 

문법을 위한 eslint,

git (버전관리) 를 위한 .gitignore

줄바꿈 규칙 등을 위한 prettier,

기본 Nest의 설정을 위한 nest-cli 등등..부터

패키지 잠금 파일 yarn.lock (or package-lock.json) 까지

 

위의 설정들의 내용을 기본적으로 숙지한 이후에

실질적인 Nest 개발에 돌입해야 할 것이다.

 

 


 

지금까지 간략하게

Nest 를 사용하는 이유,

Nest 가 제공하는 '느슨한 결합',

 

이를 통해 강력해진 확장성과 유지관리성에 대해 알아보았다.

 

내용이 길어지긴 했지만

아직은 수박 겉핥기 수준..!

나아갈 길이 많다는 것에 막연하고 막막하지 않다면 거짓말이겠지만

앞으로 직접 체험할 Nest 에 대해 기대감이 더 늘어나는 계기가 되었다 😎