비슷한 글을 예전에 썼던 적이 있다. 자세하게 말하면 번역했던 적이 있다.

차이점이 있다면 이번에는 내 경험과 생각을 녹여서 쓴다는 것과, 서버 사이드도 같이 생각해본다는 점 정도 ?

기술적인 부분 외에는 대다수 커뮤니티의 뜻이 아닌 본인의 의견이므로, 생각이 다르신 분이 있다면 꼭 말씀해주시길 바란다.


벌써 2018년이다. 곧 있으면 2019년이 된다.

여태까지 웹은 굉장히 발전했다. 그 발전의 중심에는 자바스크립트가 자리잡고 있다고 해도 과언이 아닐 것이다.

한 5여년 전부터 자바스크립트 붐이 일면서 Node.js 를 시작으로 국내에도 많은 개발자들이 자바스크립트에 대해 관심을 가지게 되었다.

Node.js

Node.js 는 브라우저에서만 동작할거라 생각했던 자바스크립트를 서버에서도 사용가능할 수 있다는 가능성을 보여주었고, 또한 자바스크립트의 자유로운 문법과 V8 의 빠른 성능은 많은 개발자들을 매료시켰다. 정말 많은 사람들이 Node.js 를 한때 사랑했고, 사랑하고 있다. Node.js 덕분에 자바스크립트는 현재 그 어느 언어보다도 개발 생태계가 큰 언어가 되었다.

어느 순간인가, Node.js 를 너무 사랑한 나머지 자바스크립트 만능론에 빠진 사람들이 나오게 되었다. 자바스크립트만 알면 서버와 클라이언트 개발을 모두 할 수 있다는 것이다! 웹의 프론트엔드, 백엔드 개발을 둘 다 잡을 수 있는 자바스크립트는 꽤나 매혹적인 언어임에는 분명했다. MEAN 스택, MERN 스택 등이 활개를 치기 시작했고, 많은 책들이 쏟아져나왔다. 나도 그 당시에 대학원 생활을 하며 그 만능론에 빠진 사람이었다(…). 그걸로 논문을 직접 쓰진 않았지만, 당시 연구실에 있던 친구는 논문을 이걸로 썼고, 나는 논문에서 주장하는 시스템의 개발의 많은 부분을 같이 진행했기에 어쩌다보니 자바스크립트로 쓰여진 (심지어 어쨌든 학술지)논문에 공저로 이름이 오르게 되었다(…).

MEAN 스택

아, 혹시나 MEAN 스택이나 MERN 스택이 뭔지 모르시는 분들을 위한 간단 설명. 자바스크립트로 그야 말로 모~든 것을 다 구성하겠다는 총체적 기술 스택을 의미한다. MongoDB, Express.js, Angular / React, Node.js . MongoDB 는 이름에서 알 수 있듯 (C++로 만들어져있긴 하지만) 자바스크립트 인터프리터가 내장된, 그리고 JSON을 저장하는, 자바스크립트와 아주 끈적한 관계를 가지고 있는 데이터베이스이며, Express.js 는 Node.js 의 웹 프레임워크이다. 굉장히 직관적이고 쉽게 웹 서버를 만들 수 있도록 해준다. Angular 나 React 야 다들 익숙한 자바스크립트 프론트엔드 프레임워크이다.

아직도 자바스크립트로 모든 것을 구성하고 계시는 분들이 있다는 것은 알고, 그것 역시 잘 만들면 아주 좋은 솔루션이라고 생각한다. 일단 브라우저에서는 반드시 자바스크립트를 써야 하니 두말할 것도 없고 (타입스크립트를 쓰건 Nim 을 쓰건 결론적으로 자바스크립트로 컴파일 되니까…), 서버단에서 Node.js 를 쓴다고 해도 사실 왠만한 경우에는 성능이 꽤나 괜찮다. 무엇보다 번거롭게 모델링을 하기 위해 매번 클래스나 구조체를 새로 만들어서 매핑시키는 짓을 안해도 일단 JSON 으로 만들어놓으면 동작한다. 크으! 아주 간단하다. 물론 예외상황 처리 등등은 프로그래머로써의 기본. 그래서 생각하는대로 슥삭 만들어서 동작 시킬 수 있다는 강점을 가지고 있다. 극도의 생산성. 또한 성능도 특정 시점에 다다르기 전까지는 꽤나 빠른 편이다. 만약 초장부터 느리면 소프트웨어 아키텍처의 문제이거나 DB 설계의 문제일테니 그것은 언어 불문 동일.

그런데 Node.js 역시 어떻게 사용하는지? 에 대한 관점도 중요하다고 생각한다. ‘웹서버’ 로 사용하는가? 아니면 ‘API 서버’ 로 사용하는가? 내가 보기에는 대개 사람들은 웹서버로 Node.js 를 사용하기보다는 API 서버로 사용하는 것 같다.

그렇다면 ‘웹서버’ 와 ‘API 서버’ 의 차이는 무엇인가?

일단 웹서버의 정의는 명확하다. 위키피디아 에 따르면, HTTP 요청을 받아서 HTML 문서와 같은 웹 페이지를 반환하는 프로그램 이 웹서버이다. 이미지, JS 파일, CSS 파일 등 무언가 파일을 전송해주는 기능 역시 웹서버의 중요한 기능이지만, 결론적으로는 HTML 을 제공해주는 것이 웹서버의 핵심 역할이다.

API 서버는 명확하게 정의되어 있지는 않다. 대략 커뮤니티에서 이래 저래 많이 사용하는 용어인데, 내가 정의를 해보자면 API 서버의 정의는 다음과 같다. HTTP 요청을 받아서 JSON 과 같은 데이터를 반환하는 프로그램. 그래서 조금 더 정확한 명칭은 Web API 서버 정도인 것 같다. 이 글에서는 커뮤니티에서 많이 사용되는 용어인 API 서버를 계속 사용하도록 하겠다.

이 둘을 나누는 것이 중요한 이유는, 바로 HTML 이 어디에서 만들어지느냐 에 대한 부분을 나누기 때문이다. 직접 개발자가 ‘정적’인 HTML 을 만들어서 ‘파일’의 형태로 올려놓는게 아니라면, 웹서버는 서버에서 HTTP 요청을 받아 ‘동적’으로 HTML 이 만들어낸다. 한편 API 서버는 단순히 데이터만 반환하기 때문에, 브라우저 내에서 이미 동작하고 있는, 렌더링 대기중인 자바스크립트가 데이터를 받아 화면에 보여준다.

결론적으로 서버 입장에서는 만일 HTML 을 반환하게 되면, 다음과 같은 동작을 수행해야 한다.

  1. 사용자의 HTTP 요청을 분석
  2. HTTP 요청에 적합한 데이터 검색
    1. 현재 프로세스 내의 메모리에 존재하는 데이터인가?
    1. 만일 데이터가 1)에 없다면, Redis, memcached 등의 Cache 서버에 데이터가 존재하는가?
    1. 만일 데이터가 2)에 없다면, Database 서버에 존재하는 데이터인가?
  1. HTML 을 만들어 낼 뼈대가 되는 템플릿을 Disk 에서 검색. (어떤 언어에서는 런타임에 메모리에 포함하는 경우도 있음)
  2. 해당 템플릿 데이터에 2번에서 읽은 데이터를 이용하여 HTML 을 만들어내는 문자열 연산
  3. 사용자에게 HTML 반환

즉, 동적으로 HTML을 반환하는 모든 웹서버는 위와 같은 단계를 거쳐 사용자에게 HTML 을 반환하고, 사용자는 그 웹페이지를 브라우저에서 보게 되는 것이다.

여기서 각 단계를 생각해보자. 먼저 1번 단계. 세션, 쿠키 등의 정보가 같이 있다면 관리하기에는 좀 귀찮을 수 있지만, 그렇게 무거운 연산은 아니다. 2번 단계. 서버의 입장에서는 크게 할 게 없다. 그냥 네트워크를 통해 전해오는 데이터를 기다리기만 하면 된다. 지연이 발생할 수는 있지만, 무언가 별도로 연산을 하지는 않는다. 3번 단계. Disk IO 가 발생하긴 하지만, 템플릿 파일이라 해봤자 1MB 도 넘지 않을테니 발생하는 IOPS 는 작을 것이다. 4번 단계. 음… 좀 무겁다. 5번 단계 역시 4번에서 만든, 메모리 상에 존재하는 데이터를 네트워크로 출력해주는 것밖에 없다.

API 서버는 3, 4번 단계가 없어진다. 그리고 HTML 대신에 데이터를 반환하며, 사용자가 해당 데이터를 받아서 HTML 을 만들어낸다. 서버 입장에서는 연산이 거의 없어지는 것이다. 즉 서버가 동일한 하드웨어로 더욱 많은 사용자를 감당할 수 있다는 의미가 되는 것이다. 이렇게 API 서버로부터 데이터를 받아서 사용자가 HTML 을 만들어내는 구조를 싱글 페이지 어플리케이션, SPA 라고 부른다. SPA 는 자바스크립트의 발전으로 가능해지게 되었다.


그러면 웹서버는 필요 없는 것인가? 절대 아니다. 웹서버는 반드시 필요하다. 사용자에게 있어서는 HTML 이 서버에서 만들어져서 브라우저에 도착한뒤 렌더링 되던지, 어떻게 만드는지에 대한 방법(자바스크립트)에 대한 HTML 만 브라우저에 도착하여 렌더링 한 후에 다시 브라우저가 데이터를 요청하여 렌더링 되던지, 결과적으로 화면에 보이는 것이 같다면 의미가 없을 수 있다. 하지만 컴퓨터의 입장에서는 분명히 다른 것이다.

사람인 우리가 왜 컴퓨터의 입장을 따져야 할까? 바로 크롤러 때문이다. 크롤러는 임의의 IP, 도메인으로부터 HTTP 요청을 날려서 HTML 들을 수집하는 프로그램이다. 대개 Google, Naver 등의 검색 서비스를 제공하는 포털 사이트에서 주로 사용하며, 그 외에도 데이터 수집을 목적으로 하는 누구라도 크롤러를 사용할 수 있다. 이 크롤러는 기본적으로 HTML 이 아닌 데이터는 제대로 해석하지 못한다.

쉽게 생각해보자. 예를 들어서 HTML 은 그림과 같다. 잘 완성된 그림이 있으면, 그 그림을 보고 의미를 부여할 수 있다.

위의 그림은 강아지 그림이다. 이를 보고 우리는 ‘이 그림은 강아지이다’ 를 알 수 있는 것이다. 대개의 크롤러는 딱 이 수준으로 동작한다. 그림을 보고 그 그림이 무엇인지 알 수 있는 것처럼, __HTML 을 보고 특정 마크업이나 특정 클래스를 찾아서 제목이 무엇인지, 설명이 무엇인지, 주제가 무엇인지, 그 외에 페이지 내에 존재하는 정보의 일부를 추출__하는 정도의 일만 한다.

한편 SPA 의 경우에는 조금 상황이 다르다. SPA 에서는 웹서버에서 HTML 을 제공하는 것이 아니라 단지 데이터만을 제공하고, 그 데이터를 자바스크립트에서 동적으로 렌더링하여 HTML 을 만들어낸다. 즉, 비유하자면 ‘유클리드 공간 내의 xy 평면에서 원점을 중심으로 반지름이 5인 원을 그리고, 점 (2,5)와 점 (3,8) 을 이은 후, …’ 와 같은 설명(데이터) 이 있는 것이다! 이 설명대로 따라하면 (렌더링 하면) 그림이 나오는 것이다. 크롤러에게는 일반적으로 이러한 설명대로 따라할 수 있는 능력이 없다 (Google 크롤러는 자바스크립트 실행이 가능하다고는 하나, 개발자가 의도한 대로 HTML 을 만들어낼지는 모르겠다; 상용 크롤러 시스템에서 Headless Chrome 등을 이용해서 돌고 있을지 의문…). 크롤러는 데이터 수집이 주요 목적이기 때문이다.


흔히 웹개발이라 하면 다음의 세 용어 중 하나를 떠올리시는 분이 있을것이라 생각한다.

JSP, PHP, ASP

이 세가지 언어는 동적으로 HTML 을 만들어주는데에 도움이 되는 언어들이다. 굉장히 오랜 기간 존재해왔고, 소프트웨어의 신뢰성 또한 오랜 기간동안 많은 사람에 의하여 검증되었다.

한편 이와 비슷한 선상에 있는, 새로운 신흥 강자들로는 Ruby, Python, Node, Go 등이 있다. 이들 모두는 ‘웹서버’ 를 개발하는데에 사용되는 언어들이다.

무슨 선택을 하던 각자의 상황에 맞는 것을 고르면 되지만, 두 분류는 지향하는 바에 있어서 상당한 차이가 있다.

  • JSP, PHP, ASP : ‘웹서버’ 를 개발하는 것이 아니라, 웹서버에서 동작하는 ‘스크립트’ 를 개발하는 것.
  • 그 외의 언어 : ‘웹서버’ 자체를 개발하는 것

JSP, PHP, ASP 는 기본적으로 ‘웹서버’ 자체를 개발하는 것이 아니다. 웹서버 (좀 더 정확한 명칭으로 업계에서는 WAS, 웹 어플리케이션 서버 라는 명칭을 쓴다)에서 동작하는 스크립트를 개발하는 것이다. JSP 의 경우는 대개 Tomcat 이나 Wildfly 에서 동작하는 Java 바이트코드와 JSP 파일, PHP 의 경우는 php-fpm 이나 libapache2-mod-php 같은 외부 CGI 프로세스 / C 함수, ASP 는 ASP.NET 의 경우 .NET 에서 동작하는 바이트코드를 만들어내는 스크립트 파일.

Apache 나 Nginx, IIS 등의 웹서버에서 대신 URL 을 보고 해당하는 처리 로직으로 넘기도록 설정해놓고, 해당 처리 로직에서는 개발한 스크립트가 동작하도록 하는 것이다. 그래서 서버를 중단시키지 않고도 필요한 부분의 파일만 딱 교체할 수도 있다! 이것은 꽤나 장점이다.

그 외의 언어들… 예를 들어서 Python 의 Flask 로 웹 개발을 한다고 해보자. 그러면 HTTP 요청을 처리하는 로직도 만들어야 한다. 제대로 된 요청에는 HTML 을 반환하고 잘못된 요청에는 에러를 반환하는 등의 처리를 전부 Python 코드로 작성해야 한다. 그리고 Flask에서 사용하는 템플릿 언어인 Jinja2 를 이용하여 미리 만들어놓은 템플릿에 DB 에서 읽은 값을 렌더링하여 반환한다.

한편 JSP, PHP, ASP 와는 다르게 Python 으로 동작하고 있는 서버는 서버를 종료하지 않고는 일부분만 수정할 수 없다. 반드시 다운타임을 갖게 된다.


내 생각에는 웹개발을 할때에 무슨 언어를 고르냐는 중요한 문제는 아닌 것 같다. 그럼에도 각각 존재하는 특성을 반드시 잘 알고 있어야 된다는 생각은 한다.

예를 들어 다운타임이 생기면 안되는 서비스에 Node.js 로 서비스를 하는 것은 최선의 선택이 아니다. 그 문제 역시 클러스터링과 롤링 업데이트, 로드 밸런싱을 통해 최소화 할 수 있는 문제이기는 하지만, 그것은 서버가 하나 이상으로 많아지는 것을 의미하며, 서버가 많아진다는 것은 사업적으로는 ‘돈’ 과 직결되는 문제이기 때문에 개발자가 함부로 결정하기는 쉽지 않다. 그래서 Google App Engine 이나 Heroku, Elastic Beanstalk 와 같은 PaaS 서비스가 많이 인기를 끌고는 있다. 내 개인적으로는 핵심적인 서비스가 아니라면 PaaS 를 써도 상관 없겠지만 핵심적인 서비스이면 서버 개발자가 직접 관리하는게 더 낫다고 생각한다. (아니면, PaaS는 너무 서비스 프로바이더에 종속적이기 때문에 차라리 컨테이너 기반으로 Kubernetes 를 사용하는 것이 훨씬 나은 선택이라고 생각한다.)

또한 커뮤니티의 크기나 유명세 또한 결정에 영향을 미친다고 생각한다. 모든 것을 직접 다 개발한다면 내 생각에는 Go 가 짱이다. Go 를 이용해서 웹서버를 만들어도 되고, 순전히 API 서버로만 사용하고 React, Vue 등을 이용하여 SPA 를 구성해도 된다. 성능도 거의 넘사벽 수준으로 빠르다. 다만 상대적으로 Go 개발자가 적은 것을 감안해보면 팀 내에서 모두가 Go 를 쓰기는 쉽지 않을 수 있을 것이다 (지금 회사에서도 나 혼자 쓰고 있다… ㅠㅠ). 유명세가 큰 PHP 는 이미 사용할 수 있는 많은 좋은 레퍼런스들이 있다. 대표적으로 워드프레스는 아주 훌륭한 CMS이다. Go 로 비슷한 것을 만들려면 굉장히 어려울 것이라고 생각한다. 마찬가지로 Laravel 로 굉장히 훌륭한 개발 프레임워크이다. 개발자에게 아주 신선한 경험을 제공한다.

그래서 웹서버 의 경우는 무슨 언어로 개발하여도 상관 없다고 생각하지만, API 서버는 좀 다르다고 생각한다. JSP, PHP, ASP 는 웹을 만들기 위한 아주 좋은 레퍼런스들이 이미 너무나도 많지만, 그 구조의 한계로 인하여 성능에 약간의 손해를 본다. 또한 ‘파일’ 을 기준으로 개발하고, 웹서버 자체는 대개 Apache 나 Nginx, IIS 를 이용하여 해당 스크립트 언어를 처리해주는 서버로 넘겨주는 구조이기 때문에 URL 자체도 자유자재로 바꿀 수가 없다. 특정 라우트를 설정하기 위해서 복잡한 설정을 거쳐서 원하는 곳으로 리다이렉트 시킬 수는 있지만, Python 의 데코레이터보다는 깔끔하지 않다.

개인적으로 가능하다면 React 로 구성하는 유니버설 어플리케이션이 제일 극강의 구조를 가지고 있다고 생각한다. 이 의미는 Node.js 를 이용하여 웹서버와 API 서버를 구축하고, React 를 서버 사이드에서도 렌더링 하도록 Node.js 를 개발하는 것이다. Node.js 가 자바스크립트 엔진인 V8 을 이용하여 동작하기 때문에 유일하게 가능한, 아주 최고의 장점이기도 하다. 또한 자바스크립트 프론트엔드 프레임워크 중 아마 제일 유명한 React 는 사용할 수 있는 많은 레퍼런스들(대개 UI 라이브러리)이 있으며, 상태를 관리하기 위해 나온 훌륭한 디자인 패턴, Flux 패턴의 구현체 Redux 또한 React 와 환상적으로 맞물려 동작한다. 서버에서 렌더링하여 필요한 최소 부분은 HTML 로 렌더링하고, 그 외의 부분은 클라이언트에서 렌더링 하니 그야 말로 환상적. 하지만 개발하는 것 역시 환상적으로 어렵다는 특징이 있다. 이걸 회사 내에서, 팀 내에서 모두가 어느 수준 이상으로 지식을 공유하며 개발하려면 쉽지 않을 것이다…


이런 저런 얘기를 떠들어댔지만, 결론은 다음과 같다.

  1. 프론트엔드 프레임워크? 무엇을 쓰느냐는 사실 별 의미 없다고 생각한다. 상황에 맞는 것을 쓰자. 자바스크립트만 제대로 알면 어느 것을 고르느냐는 큰 문제는 아니다. 핵심은 ‘웹 컴포넌트’. 웹에 존재하는 요소들을 구조적으로 나누는 것. 방법의 차이일 뿐, 프레임워크는 (물론 각 프레임워크의 철학이 담겨있긴 하지만) 웹컴포넌트의 개념만 잘 알면 순전히 선택의 문제라고 생각한다. 난 거의 왠만해서는 Vue 를, 복잡한 상태를 처리할 때에는 React 를 고른다. Angular 는 아예 모든 것을 Angular 로 개발할 때에는 적합한데, 기존에 있는 페이지에서 일부(예를 들어서 페이스북의 사용자 피드를 얻어오는 부분) 만 사용하고자 할 때에는 Angular 는 (가능은 하지만) 적합하진 않다고 생각한다.
  2. 웹서버 개발? JSP, PHP, ASP 도 충분히 좋다 (JSP 는 개발환경에서 많은 리소스를 소모한다는 단점이 있긴 하다). 오히려 다른 언어들보다 더 좋다고 생각한다. 다만 조금 더 세부적인 내용을 이해하고 사용하도록 하자. 나라면 엔터프라이즈 레벨 및 협업에는 PHP나 JSP를, 개인적으로는 Go를 사용할 것이다.
  3. API 서버 개발? 아마 높은 확률로 JSP, PHP, ASP 는 최선의 선택이 아닐 것이다… Python 이나 Node.js, 그리고 무엇보다도 Go 가 최강의 성능을 자랑한다.
  4. React 유니버설 어플리케이션은 다양한 상태를 갖는 복잡한 웹 어플리케이션을 제공하기 위한 최강의 서버이다. ㅗㅜㅑ… 근데 만들기는 너무 너무 어렵다 (그래서 next.js 등을 이용하면 굉장히 편해지기는 한다). 그 말인 즉슨, 웹 어플리케이션의 상태가 복잡한 경우가 아닌데도 서버사이드 렌더링을 구현하는 것은 투머치라고 생각한다.