0. 개요

[ 기존의 구조 ]
보통 express에서는 컨트롤러, 서비스 별로 쭈욱 파일이 모여있다.
- 아래는 과거에 진행한 프로젝트 구조이다. 프로젝트를 진행하면서 mvp가 많아질수록 컨트롤러와 서비스는 많아졌고 점점 도메인 별로 코드를 찾기 어려워졌다.
- 이 구조는 서비스가 확장되면 도메인 별로 흩어져 있기 때문에 파일을 찾아서 개발하는 것이 힘들다.
그래서 좀 더 대규모 서비스의 폴더 구조는 어떻게 설계하는지 궁금해졌고, 이번에는 nest에서 최대한 DDD할 수 있는 폴더 구조를 알아보려 한다.
┣ 📂controllers ┃ ┣ 📜bookMarkController.ts ┃ ┣ 📜checklistController.ts ┃ ┣ 📜scheduleController.ts ┃ ┣ 📜subscribeController.ts ┃ ┣ 📜supplementController.ts ┃ ┗ 📜userController.ts ┣ 📂middlewares ┃ ┣ 📜errorMiddleware.ts ┃ ┣ 📜loginRequired.ts ┃ ┣ 📜validator.ts ┃ ┣ 📜verifyRefreshToken.ts ┃ ┗ 📜verifyToken.ts ┣ 📂routes ┃ ┣ 📜bookMarkRouter.ts ┃ ┣ 📜checklistRouter.ts ┃ ┣ 📜scheduleRouter.ts ┃ ┣ 📜subscribeRouter.ts ┃ ┣ 📜supplementRouter.ts ┃ ┗ 📜userRouter.ts ┣ 📂services ┃ ┣ 📜bookMarkService.ts ┃ ┣ 📜checklistService.ts ┃ ┣ 📜scheduleService.ts ┃ ┣ 📜subscribeService.ts ┃ ┣ 📜supplementService.ts ┃ ┗ 📜userService.ts
[ What is DDD? ]
Domain Driven Design의 약자로 도메인 주도 설계를 말한다.
🔅 Domain (도메인)이란?
1) 사전적의미: '영역', '집합'
2) DDD에서의 Domain: 비즈니스 Domain
3) 비즈니스 Domain: 유사한 업무의 집합
4) 애플리케이션은 비즈니스 Domain별로 나누어 설계 및 개발 될 수 있다.
nest에서 폴더구조를 세워보자!
1. 폴더 구조
이 구조는 일반적인 NestJS 구조가 아니라 새롭게 설정한 구조이다.
'구름톤' 해커톤에서 배운 구조이며 블로그를 참고했다.
(자세한 내용은 해당 블로그를 참고해주세용!)
src ├─auth │ ├─decorators │ ├─domain │ ├─guards │ └─helpers ├─common │ ├─entities │ ├─interfaces │ └─repositories ├─config │ ├─database │ │ └─mysql │ └─jwt ├─database │ └─migrations ├─modules │ └─user │ └─users │ ├─entities │ └─repositories └─providers └─database └─mysql
[ auth ]
인증과 관련된 기능을 작성하는 폴더이다.
[ common ]
공통으로 많이 사용되는 코드들 작성한다. 모든 폴더에서 정말 common하게 사용할 코드들이다.
[ config ]
기존에 프로젝트에서는 dotenv를 사용했는데 이번에는 @nest/config를 이용해서, 환경변수 설정한다.
현업에서는 test, dev, prod 등 여러 환경을 사용하게 되는데 그때마다 다른 환경 변수를 사용할 필요가 있다. @nestjs/config를 통해서 다양한 환경에 다양한 환경 변수를 사용하는 것이 좋다.
config를 관리하는 방법은 해당 블로그를 보고 따라해보자.
👉 Creating Config Files in NestJS
1) 패키지 설치
$ npm i --save @nestjs/config
2) 폴더 구조
src/ └── config/ ├── app/ │ ├── config.module.ts │ ├── config.service.ts │ └── configuration.ts │ └── index.ts ├── database/ │ └── mysql │ ├── config.module.ts │ ├── config.service.ts │ └── configuration.ts │ └── index.ts └── mail/ ├── config.module.ts ├── config.service.ts └── configuration.ts └── index.ts
- configuration.ts: 변수들을 등록해준다.
- configuration.service.ts: 'getter(획득자)' 기반 클래스 함수가 있는 단순한 클래스이다.
- 참고자료: 자바스크립트에서 getter과 setter
@Injectable() export class MysqlConfigService { constructor(private configService: ConfigService) {} get host(): string { return this.configService.get<string>('mysql.host'); } }
- config.module.ts: 앱 구성 관련 클래스를 가져와서 제공한다.
3) 사용 방법
일반적으로 dotenv 방식이라면 다음과 같이 사용한다. (process.env.JWT_SECRET_KEY)
import dotenv from "dotenv"; dotenv.config(); const secretKey = process.env.JWT_SECRET_KEY; // access token 발급 const makeToken = (Object: ITokenInput) => { const token = jwt.sign(Object, secretKey, { expiresIn: "1h" }); return token; };
지금 방식에서는 비즈니스 로직을 구현하는 곳에서 다음과 같이 ConfigService를 import한 뒤 this.config.get('환경 변수')로 사용할 수 있다.
> this.jwtConfig.accessSecretKey
import { JwtConfigService } from '@config/jwt'; @Injectable() export class VerifyGuard implements CanActivate { constructor(private readonly jwtConfig: JwtConfigService) {} private _getPayload(req: Request) { ... const payload = jwt.verify(token, this.jwtConfig.accessSecretKey); } }
[ database ]
migrations파일이 있는 폴더이다.
[ providers ]
외부 서비스(앱)를 말그대로 제공받는 폴더이다.
[ modules ]
비즈니스 로직을 구현하는 곳이다.
modules └─user │ user.module.ts │ └─users │ users.controller.ts │ users.module.ts │ users.service.ts │ ├─entities │ index.ts │ user.entity.ts │ └─repositories index.ts user.repository.ts
이때 user 도메인으로 작성을 하더라도 그 안에서 세부적으로 나뉠 수 있기 때문에 세부적으로 나누고 연관된 도메인끼리 Aggregate한다.
예를 들어, User 객체가 있고, User가 하는 운동 UserActive, UserProfile 객체가 있다면 모두 하나의 Aggregate라고 할 수 있다.
가장 큰 도메인은 단수형, 세부적인 도메인은 복수형.
글이 점점 길어지고 있어 좀 더 자세한 @nest/config과 DDD Aggregate에 대해서는 따로 포스팅을 작성하겠다,
📌 Reference
'프로젝트 개발 기록 > [개발] node.js | nest, express' 카테고리의 다른 글
[Node.js] Nest.js에서 프로젝트 시작하기 (0) | 2022.09.14 |
---|---|
TypeScript + node.js에서 Jest로 단위테스트 하기 (0) | 2022.07.17 |
[TypeScript+Express] Redis로 Refresh Token 관리 (0) | 2022.06.21 |
[TypeScript + Express] Error handling (2) | 2022.06.17 |
댓글