회사의 기존 프로젝트 리펙토링에 참여하게 되었다.
일종의 MSA화를 추구하고 있으며, 초기 작업 진행 중이다.
다만 이번에 약간 골때리던 이슈를 하나 만났었는데, 다름 아닌 'DB 모델 파일들을 어떻게 관리하느냐'의 문제였다.
관계로 인해 묶여 있는 모델 파일들을 서버마다 파일로 저장해두고 부르기엔 너무 불편하다.
MSA화 하면서 서버들이 수십 개로 찢어지는데, 모델 파일이 수정되면 수십 개의 repo에 있는 모델 파일들 모두 sync를 맞추어 주어야 한다.
직접하려면 오우....
큰 이슈도 아니라고 생각이 들 수도 있는데, Dockerizing + kubernetes 세팅까지 생각하면 고민 많이 해야하는 문제라고 생각한다.
일단 기존 서버는 특정 repo에서만 모델 파일들을 저장해두고, 도커 이미지를 생성할 때 이미지 내의 폴더로 모델 파일들을 복사한다.
나름 괜찮은 방법(사실 임시방편)이라고 생각한다. 기존 서버에서는 node.js로 진행되었었고, 별다른 문제는 없었을 것이다.
허나, typescript에서는 상황이 다르다..
import부터 타입 체킹까지 모든 외부 파일 참조를 빡세게 가져가기 때문에 결국 실제로 로컬에 파일이 있어야한다.
그리고 nest app 기준으로 그 외부의 파일을 참조하는 것은 원칙적으로 불가능하다. (의미도 없지만)
따라서 좀더 깔끔(?)하게 공통된 파일들을 하나로 묶어 참조하는 방법을 원했다.
첫 시도는 단순히 모델 파일들만 따로 폴더에 모아 루트 경로에 두는 것이었지만, 다른 모듈에서 불러오는 데코레이터들이 하나라도 있는 순간 그 폴더에는 node_modules가 필요하게 되고, 결국 실패.
그러던 중.. Nest 공식 문서에서 monorepo와 관련된 글이 있었다..!
Standard Repo vs MonoRepo
참조 : https://docs.nestjs.com/cli/monorepo
Documentation | NestJS - A progressive Node.js framework
Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Progamming), FP (Functional Programming), and FRP (Functional Reac
docs.nestjs.com
1. Standard Repo
말 그대로 일반적인 프로젝트 폴더구조라고 보면 된다.
여기서 일반적이라 함은 이 프로젝트 하나에서만 하나의 서비스가 완성될 수 있는 구조라고 보면 된다.
달리 표현하자면, 다른 외부 프로젝트의 코드에 의존하지 않는? 정도라고 생각하면 될 것 같다.
이런 느낌?

2. MonoRepo
재사용성이 필요한 코드(변수, 객체, ...)가 있고, 서로 분리되어야하는 프로젝트가 하나의 코드를 필요로 할 때, 그 코드들을 일종의 라이브러리 개념으로 사용할 수 있도록 프로젝트를 구성하는 방식이다.
nest에서는 이렇게 여러 프로젝트를 아울러서 묶은 폴더를 workspace라고 부르고, 이 workspace의 각 app들에 대한 컴파일 옵션, ts-config 옵션, nest cli들을 하나의 파일에서 공통적으로 다룬다.
이런 식으로 구성되어 있다.

tsconfig, build, nest-cli, package 등이 모두 최상위 폴더에서 하나의 파일로만 관리가 된다. (물론 개별적으로 컴파일 옵션을 다르게 주는 방법도 있다)
Nest Library
apps 안에는 기존 서버들이 개별 tsconfig.app.json을 가지고 올라가 있다. (이것도 optional)
그리고 우리가 원하는 공통 코드들, 즉 라이브러리는 libs 폴더에 저장되어있다.
예를 들어, 백엔드에서 뱉어주는 에러들은 보통 통일시켜서 작성하기 마련인데, 이를 라이브러리화해서 공통 코드로 올려두면 다른 app들끼리 서로의 간섭 없이도 편하게 사용할 수 있을 것이다.

각 라이브러리들도 별도로 tsconfig.lib.json을 가지고 있으며, 서로 다른 컴파일 옵션을 취하고 싶을 때 사용할 수 있다.
또한, @nestjs/common과 같이 내장 라이브러리처럼 태그 호출이 가능하다!
nest g lib(or library) <라이브러리 이름>으로 라이브러리 생성을 해보면,

위와 같이 apps 내부에서 어떤 prefix를 통해 호출할 지 결정할 수 있다.
import { ServerError } from "../common/error/server.error.ts"; // 라이브러리화 import { ServerError } from "@my-project/error";
이런 식으로 변경된다! 뭔가 있어보인다..ㅎ
...
그럼 @my-project/error는 nest 컴파일러가 어떻게 찾아줄까?
답은 루트 폴더의 tsconfig에 있다.
{ "compilerOptions": { ... "paths": { "@my-project/error": [ "libs/error/src" ], "@my-project/error/*": [ "libs/error/src/*" ], "@my-project/middleware": [ "libs/middleware/src" ], "@my-project/middleware/*": [ "libs/middleware/src/*" ] } } }
paths 프로퍼티에 라이브러리를 추가할 때마다 자동으로 추가되며, import 시 해당 경로로 치환해서 찾아준다!
+ 다음에는 apps / libs로 분리된 코드들을 dockerizing 후 쿠버네티스에 디플로이먼트로 띄우는 것이랑 nest의 워크스페이스 기능을 더 활용하는 법에 대해 공부하고 올려봐야겠다.
'Back-end > Nest.js' 카테고리의 다른 글
joi를 Nest.js에서 써보자 (joi.extend부터 데코레이터까지) (0) | 2021.06.08 |
---|