Spring vs NestJS

Logan·2024년 5월 16일
1
post-thumbnail
post-custom-banner

NestJS를 사용한 서버 개발을 하는 회사가 점점 늘어나면서 Spring과 NestJS의 차이점에 대해서 궁금해하실 분들이 계실 것 같습니다. 오늘은 NestJS로 커리어를 시작해서 현재는 Kotlin & Spring 프로젝트까지 개발 중인 저의 주관적인 의견을 소개해 드리려고 합니다.



강력한 모듈 구조

NestJS는 Angular 프레임워크의 영향을 받아서 Module-Controller-Service 아키텍처 패턴을 따릅니다. Root Module 내부에서 거의 위의 그림처럼 정형화된 구조의 각 모듈로 구성되게 됩니다. 이는 비교적 자유롭게 아키텍쳐를 구성할 수 있는 Spring에 비해서 엄격하다고 느낄 수 있습니다. 이런 강제성이 마음에 안 드는 사람도 있을 것 입니다. 하지만 NestJS의 탄생 배경 자체가 NodeJS 진영에 체계화된 아키텍쳐를 제공하기 위함이기 때문에 엄격한 그 맛에 사용한다고 볼 수 있습니다.

그러한 이유로 NestJS는 모듈을 생성 시 커맨드 명령어를 제공합니다. 만약 Spring을 먼저 접한 개발자라면 NestJS 실습 중 Nest CLI 가 신선하게 느껴질 수 있습니다. 제가 위의 users 모듈을 생성할 때 마우스는 일절 사용하지 않고 아래의 코드를 이용해서 생성했습니다.

nest g module users
nest g controller users --no-spec
nest g service users --no-spec 


개발 언어의 차이

두 프레임워크를 사용할 때 가장 와닿는 차이는 바로 Kotlin과 TypeScript라는 언어의 차이였습니다. 가장 크게 느꼈던 차이점 3가지만 정리하겠습니다.

1. JVM vs Node

Kotlin과 Typescript(또는 JS)는 각각 JVM과 Node(주로 V8)를 기반으로 작동합니다.
JVM 은 블로킹 I/O, 멀티스레드로 동작하고 Node는 논블로킹I/O, 싱글스레드로 동작한다는 차이점이 있습니다. 이 때문에 처음 아키텍처를 구상할 때 고려하게 되는 포인트에서 차이점이 존재합니다.

Kotlin으로 작업한 프로젝트는 멀티 스레드를 이용한 병렬 처리가 가능하기 때문에 하나의 인스턴스에서 단일 프로세스를 사용할지 다중 프로세스를 사용할지에 대한 고려를 해야합니다. 다중 프로세스 사용 시 메모리 사용 효율성은 줄어들겠지만 안정성, 고가용성 측면에서 유리한 점이 있기 때문입니다. 또한 멀티 스레드를 이용하기 때문에 스레드 동기화가 필요한지 고려해야하고 컨텍스트 스위칭 비용 등을 고려해서 적절한 스레드 개수를 지정해줘야 합니다.

반면에 Typescript 프로젝트의 경우에는 단일 스레드 기반이기 때문에 대부분 멀티 프로세스를 사용하게 됩니다. 그래서 Node 진영에서는 PM2라는 툴을 거의 필수적으로 사용하게 됩니다. (싱글 코어 CPU를 사용하지 않는다는 전제입니다 🙂)

대신 Typescript에서는 신경써야할 다른 부분이 있습니다. 바로 논블로킹I/O라는 특징에 맞게 TS(JS) 함수들 중에는 비동기(+논블로킹) 함수들이 존재합니다. 그래서 비동기 함수들에 대한 숙지가 필요하고 코딩을 하면서 비동기 흐름을 계속 고려하며 작업하게 됩니다. 코틀린의 경우는 비동기를 의도한 경우에만 직접 비동기 함수를 생성해서 사용하면 됩니다.

2. 타입 지정의 유연성

두 언어 모두 정적 타이핑 언어인 것은 맞습니다. 하지만 사용하면서 그 정도에는 차이점이 있습니다.
(물론 TS를 사용한다는 가정입니다. JS는 동적 타이핑이죠.)

먼저, Kotlin은 Java와 마찬가지로 강력한 정적 타이핑 언어입니다. 타입 검사 시에도 명목적 타이핑 (Nominal Type System)을 사용하기 때문에 두 클래스가 동일한 필드를 가지고 있어도 서로 다른 타입으로 간주됩니다. 그리고 대부분 사람들은 직관적으로 명목적 타이핑이 자연스럽다고 느낍니다.

하지만 Typescript는 구조적 타이핑 (Structual type system)을 사용하기 때문에 두 객체가 동일한 구조를 가지면 동일한 타입으로 간주됩니다. 타입의 이름은 Alias처럼 취급되는 것이죠.

즉, Typescript는 타입간 호환성이 좋고 Kotlin은 엄격한 타입 검사가 가능합니다. 무엇이 더 좋은지는 프로젝트의 요구사항마다 다르겠지만, 개인적으로 TS는 몸이 편하고 Kotlin은 마음이 편합니다...

Null 안전성 역시 Kotlin이 더 강력하게 보장하고 Typescript는 선택적으로 안전성을 보장합니다. 때문에 Typescript의 자유도가 더 높게 느껴집니다.

3. 비동기 함수 사용법

비동기 프로그래밍을 할 때에도 두 언어는 문법이 다릅니다. 키워드의 호칭만 다르고 동작 흐름이 같다면 편하겠지만 아쉽게도 그렇지 않습니다.

Typescript는 async, await 키워드를 사용하여 비동기 함수를 지정하고 호출 시 비동기로 호출할지 동기적으로 호출할지가 결정됩니다. 비교적 단순한 문법으로 직관적으로 받아들이기 쉽습니다. 단, await을 사용하지 않으면 Promise 객체를 반환하기 때문에 실수하는 경우가 생길 수 있습니다.

Kotlin은 러닝커브가 비교적 더 높습니다. 비동기 프로그래밍 시 코루틴을 사용하며 suspend, launch, async, runBlocking 등의 키워드를 사용합니다. suspend로 비동기 함수를 생성하여 코루틴 스코프에서 사용하게 됩니다. 코루틴 스코프는 suspend 함수를 동기적으로 실행하며 비동기 실행을 위해서는 launch, async 내부에서 실행시켜야 합니다.



다른 차이점은?

현업에서 느낀 차이점은 솔직히 위의 두 가지가 전부입니다. 프레임워크 자체는 Spring, NestJS 둘 다 Container를 통한 Singleton을 제공하고, DI를 사용하고, AOP가 가능합니다. 사용하는 언어, Life Cycle 및 디테일한 사용법은 다르지만 개발을 하면서 크게 다른점은 느끼지 못했습니다. 다른 차이점을 느끼신 분이 계시다면 댓글로 공유해주시면 감사하겠습니다.

굳~~이 꼽자면, 프레임워크의 차이점이라고 보기는 힘들지만 JS 진영에서 사용하는 NPM, Yarn 등의 패키지 매니저와 PM2라는 프로세스 매니저의 존재 유무입니다. 개인적으로 굉장히 편리하다고 생각하기 때문에 JAVA 진영에도 있었으면 하는 2가지 툴입니다.



그동안 서로 다른 언어와 프레임워크를 동시에 다루면서 새로운 동기부여와 소소한 재미가 있었습니다. 개발자에게 프레임워크의 사용 등은 마이너한 포인트이고 결국 설계하는 능력과 새로운 것을 습득하는 능력이라는 것도 다시금 깨달았던 것 같네요.

글을 마치며 꿀팁(?) 하나 드리자면, 동시에 다수의 언어를 사용하다보면 헷갈릴 때가 있습니다. 그럴 때는 사용하는 언어마다 개발툴(편집기)를 다른 걸 사용하시길 권해드립니다. 저는 VSCode와 IntelliJ를 사용 중인데 개발툴을 나눠두면 그나마 덜 헷갈리더라구요.

제 글이 도움이 되었으면 좋겠습니다. 모두 행복한 개발하세요!!

profile
Dev Log.
post-custom-banner

0개의 댓글