«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
Archives
Today
Total
관리 메뉴

올해는 머신러닝이다.

NestJS에서 추천하는 아키텍처 패턴 본문

스터디/NestJS

NestJS에서 추천하는 아키텍처 패턴

행복한 수지아빠 2025. 2. 13. 10:24

NestJS에서 추천하는 아키텍처 패턴은 여러 가지가 있지만, 대표적으로 Layered Architecture (레이어드 아키텍처), Hexagonal Architecture (헥사고날 아키텍처), Microservices Architecture (마이크로서비스 아키텍처), CQRS (Command Query Responsibility Segregation) 등의 패턴이 많이 사용돼. 각각의 패턴을 설명할게.


1. Layered Architecture (레이어드 아키텍처)

개요

  • 가장 기본적인 NestJS 아키텍처
  • Controller, Service, Repository (또는 Model) 계층을 분리
  • 작은 프로젝트부터 대규모 프로젝트까지 적용 가능

구성 요소

  1. Controller : HTTP 요청을 처리하고, 적절한 서비스 호출
  2. Service : 비즈니스 로직 처리
  3. Repository (or Model) : 데이터베이스와 직접 상호작용 (TypeORM, Prisma 등 사용 가능)
  4. Module : 관련된 컴포넌트들을 그룹화

예제

/src
  ├── users
  │     ├── users.controller.ts
  │     ├── users.service.ts
  │     ├── users.repository.ts
  │     ├── users.module.ts
// users.controller.ts
@Controller('users')
export class UsersController {
  constructor(private readonly userService: UsersService) {}

  @Get()
  getUsers() {
    return this.userService.findAll();
  }
}
// users.service.ts
@Injectable()
export class UsersService {
  constructor(private readonly userRepository: UserRepository) {}

  findAll() {
    return this.userRepository.findAll();
  }
}
// users.repository.ts
@EntityRepository(User)
export class UserRepository extends Repository<User> {
  findAll() {
    return this.find();
  }
}

장점

✅ 유지보수성과 확장성이 좋음
✅ 프로젝트의 모듈화를 쉽게 적용할 수 있음
✅ NestJS 기본 아키텍처와 자연스럽게 연결됨

단점

❌ 계층 간 데이터 흐름이 많아질수록 성능이 저하될 수 있음
❌ 비즈니스 로직이 복잡해질 경우 서비스 계층이 비대해질 위험


2. Hexagonal Architecture (헥사고날 아키텍처, Clean Architecture)

개요

  • 비즈니스 로직과 외부 시스템 (DB, API, UI 등)의 의존성을 분리
  • Domain, Application, Infrastructure, Interface 계층으로 구성
  • 핵심 비즈니스 로직은 Domain에 위치하고, Infrastructure를 통해 외부 시스템과 연결됨

구성 요소

  1. Domain (Core Logic) : 애플리케이션의 핵심 로직 (순수한 TypeScript)
  2. Application (Use Cases) : 도메인 로직을 조작하는 서비스 계층
  3. Infrastructure : 데이터베이스, 외부 API, 파일 시스템 등의 I/O 처리
  4. Interface : Controller, GraphQL Resolver, gRPC Handler 등

예제

/src
  ├── domain
  │     ├── user.entity.ts
  │     ├── user.service.ts
  ├── application
  │     ├── user.use-case.ts
  ├── infrastructure
  │     ├── user.repository.ts
  │     ├── user.database.ts
  ├── interfaces
  │     ├── user.controller.ts
// domain/user.entity.ts
export class User {
  constructor(public id: number, public name: string) {}
}
// application/user.use-case.ts
export class UserUseCase {
  constructor(private readonly userRepository: UserRepository) {}

  findAll(): User[] {
    return this.userRepository.findAll();
  }
}
// infrastructure/user.repository.ts
export class UserRepository {
  findAll(): User[] {
    return [{ id: 1, name: 'John Doe' }];
  }
}
// interfaces/user.controller.ts
@Controller('users')
export class UserController {
  constructor(private readonly userUseCase: UserUseCase) {}

  @Get()
  getUsers() {
    return this.userUseCase.findAll();
  }
}

장점

✅ 핵심 도메인 로직을 보호할 수 있음
✅ 외부 인프라(DB, API) 변경 시 영향도가 적음
✅ 확장성과 유지보수성이 뛰어남

단점

❌ 구조가 복잡하여 작은 프로젝트에서는 과도할 수 있음
❌ 학습 곡선이 높음


3. Microservices Architecture (마이크로서비스 아키텍처)

개요

  • 애플리케이션을 여러 개의 독립적인 서비스로 분리
  • NestJS는 기본적으로 gRPC, Kafka, RabbitMQ, NATS 등의 메시지 큐를 지원

구성 요소

  1. Gateway : API Gateway 역할
  2. Microservices : 각 서비스는 독립적인 데이터베이스와 비즈니스 로직을 가짐
  3. Message Broker : 서비스 간 통신을 위한 메시지 큐 (Kafka, RabbitMQ 등)

예제

/src
  ├── gateway
  │     ├── main.ts
  │     ├── app.module.ts
  ├── user-service
  │     ├── main.ts
  │     ├── user.controller.ts
  │     ├── user.service.ts
  ├── order-service
  │     ├── main.ts
  │     ├── order.controller.ts
  │     ├── order.service.ts
// user-service/main.ts (Microservice)
async function bootstrap() {
  const app = await NestFactory.createMicroservice(UserModule, {
    transport: Transport.TCP,
    options: { host: 'localhost', port: 3001 },
  });
  await app.listen();
}
// gateway/main.ts (API Gateway)
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  await app.listen(3000);
}

장점

✅ 독립적인 배포 및 스케일링 가능
✅ 서비스 간 장애 격리가 가능하여 안정성 향상
✅ 다양한 기술 스택을 혼합하여 사용할 수 있음

단점

❌ 운영이 복잡해지고, 서비스 간 통신 오버헤드가 발생
❌ 데이터 일관성을 유지하는 것이 어렵고, 분산 트랜잭션 처리가 필요


4. CQRS (Command Query Responsibility Segregation)

개요

  • Command (쓰기)와 Query (읽기)를 분리하여 성능 최적화 및 유지보수를 용이하게 함
  • 이벤트 기반 아키텍처와 함께 사용됨

구성 요소

  1. Command : 데이터를 변경하는 작업 (POST, PUT, DELETE)
  2. Query : 데이터를 읽는 작업 (GET)
  3. Event Handlers : 상태 변경을 이벤트 기반으로 관리

예제

/src
  ├── users
  │     ├── commands
  │     │     ├── create-user.command.ts
  │     │     ├── handlers
  │     │     │     ├── create-user.handler.ts
  │     ├── queries
  │     │     ├── get-user.query.ts
  │     │     ├── handlers
  │     │     │     ├── get-user.handler.ts
// commands/create-user.command.ts
export class CreateUserCommand {
  constructor(public readonly name: string) {}
}
// queries/get-user.query.ts
export class GetUserQuery {
  constructor(public readonly id: number) {}
}

장점

✅ 성능 최적화가 가능하며, 읽기/쓰기 분리로 확장성 증가
✅ 이벤트 소싱과 조합하여 히스토리 관리 가능

단점

❌ 구조가 복잡하여 작은 프로젝트에는 오버킬
❌ 데이터 동기화 및 일관성 유지가 어려울 수 있음


NestJS 아키텍처 추천

소규모 프로젝트Layered Architecture
비즈니스 로직이 중요한 프로젝트Hexagonal Architecture
대규모 시스템 & 확장성 필요Microservices Architecture
고성능 데이터 처리CQRS