NestJS의 철학

NestJS의 철학

NestJS를 처음 접하면 Express 서버 대비 구조가 복잡하다는 인상을 받는다.
파일이 많고, 생소한 개념이 한꺼번에 등장한다. 하지만 그 복잡함에는 이유가 있다. NestJS는 단순히 기능을 모아둔 프레임워크가 아니라, 명확한 철학 위에 설계된 프레임워크다.
이 글에서는 NestJS의 아키텍처 구조가 왜 이렇게 생겼는지, 그 철학을 다뤄보도록 하겠다.
Node.js는 자유롭다. 근데 그 자유가 팀 단위로 가면 문제가 된다. NestJS는 그걸 알고 만든 프레임워크다.
배경: Node.js 서버에는 아키텍처가 없었다

Node.js의 다른 서버 프레임워크인 Express는 자유롭다. 폴더 구조도, 파일 이름도, 레이어 분리 방식도 개발자 재량이다.
이 자유는 처음엔 장점이다. 빠르게 시작할 수 있고, 원하는 대로 짤 수 있다.
하지만 프로젝트가 커지거나 팀이 생기면 상황이 달라진다. 규칙이 없으면 사람마다 구조가 달라지고, 코드를 파악하는 데 시간이 걸린다.
NestJS를 만든 Kamil Myśliwiec은 이 문제를 정면으로 겨냥했다.
"Node 생태계에는 훌륭한 라이브러리가 많다. 하지만 아키텍처 문제를 효과적으로 해결한 것은 없다."
철학 1. Progressive Framework
NestJS는 TypeScript를 기반으로 구축되었으며 OOP(객체지향 프로그래밍), FP(함수형 프로그래밍), FRP(함수형 반응형 프로그래밍)의 요소를 결합한다.
단일 패러다임을 강요하지 않고 세 가지를 상황에 따라 혼용할 수 있도록 설계되어 있다. 이것이 NestJS가 스스로를 Progressive Framework라고 부르는 이유다.
철학 2. 아키텍처를 프레임워크가 강제한다
NestJS의 첫 번째 철학은 구조를 개발자 판단에 맡기지 않는다는 것이다.
프레임워크가 "무엇을 만들지"가 아니라 "어떻게 구조화할지"를 결정해 준다는 점이 Express 등과의 근본적인 차이다. 코드는 세 가지 역할로 나뉜다.

- Module: 도메인 단위로 코드를 묶는 컨테이너. 유저 관련 기능은
UsersModule, 인증은AuthModule등 - Controller: HTTP 요청을 받아서 어디로 보낼지 결정한다. 비즈니스 로직은 존재하지 않는다.
- Service: 실제 비즈니스 로직이 들어가는 곳. DB 조회, 계산, 외부 API 호출 등이 포함된다.
이 구조가 강제되면 새 팀원이 합류해도 코드 파악이 빠르다. 주문 관련 버그가 발생한다면 OrdersModule에 있는 코드를 보면 된다.
규칙을 별도로 문서화할 필요가 없다.
철학 3. 느슨한 결합, 의존성 주입
NestJS의 두 번째 철학은 코드 간 결합도를 낮추는 것이다.
이를 위해 의존성 주입(Dependency Injection, DI)을 핵심 기능으로 내장했다.
UsersService를 컨트롤러 안에서 직접 new로 생성하지 않는다. NestJS의 IoC 컨테이너가 알아서 주입해준다.
이게 왜 중요할까?
첫째, 테스트가 쉬워진다. 실제 DB 연결 없이 Mock 객체를 주입하면 된다.
둘째, 구현체를 교체해도 다른 코드를 건드리지 않아도 된다.
UsersService의 내부가 바뀌어도 UsersController는 수정할 필요가 없다. 인터페이스만 유지되면 된다.
이 원칙은 SOLID의 DIP(의존성 역전 원칙)와 직접 연결된다. NestJS는 이 원칙을 선택지가 아닌 기본값으로 내장했다.
철학 4. Angular에서 가져온 설계 패턴
NestJS의 세 번째 철학은 검증된 패턴을 빌려온다는 것이다. 출처는 Angular다.
Angular는 프론트엔드에서 대규모 애플리케이션의 아키텍처 문제를 해결해왔다. Module, DI, Decorator 기반 설계가 그 중심에 있다. NestJS는 이 패턴을 백엔드로 그대로 가져왔다.
철학 5. 추상화와 직접 접근을 동시에 제공한다
NestJS는 Express/Fastify 같은 범용 Node.js 프레임워크 위에 추상화 계층을 제공하면서도, 개발자에게 하위 플랫폼의 API를 직접 노출한다.
즉, 프레임워크 밖으로 나가고 싶을 때 언제든 가능하다. 생태계 잠금(lock-in)을 최소화하는 설계라고 볼 수 있다.
참고: NestJS 공식 문서