Server Side Rendering은 부활한다.

공부는 혼자하는 거·2023년 6월 13일
1

잡담

목록 보기
8/11
post-thumbnail

필자는 벡엔드 개발자이다. 간단한 벡오피스나, 사이드 프로젝트 만들 때 프론트엔드는 React를 사용한다. React의 생태계는 프론트엔드 중 끝판왕이라고 할 수 있다. 이것도 있을까 싶은 라이브러리도 찾아보면 다 있고, 관련 문서 및 커뮤니티도 매우 풍부하다.

단지 그 점 때문에, 지금까지 리액트를 쓰는 중이다. 하지만 시간이 지나면 지날수록 점점 더 사용하는데 있어 회의감이 많이 든다.

예전의 영광

상황을 예전으로 돌이켜보자. JS가 별볼일 없던 때, 웹 상에서 페이지 전체를 서버에서 전부 내려주던 시절. Servlet과 JSP, PHP, ASP 가 난립하던 그 시절 웹 세대를 말이다. 현재는 좀 거창해졌지만, 그래도 근본을 따져보면, 웹이란 단지 내 서버(컴퓨터)의 폴더에 있는 파일을 HTTP 프로토콜을 통해서 남들 서버들한테도 공유한다는 개념이 전부이다.

정적인 페이지를 내려주는 데 있어서 서버의 역할은 간단하다. 대표적으로 Apache 같은 서버는 정적인 페이지를 보여주는 데 있어서 웹의 초창기 핵심적인 역할을 담당했다. 문제는 사용자와의 인터렉션이다. 언젠가부터 웹은 사용자와의 상호작용을 통해서 데이터를 동적으로 다르게 보여줘야 할 필요성이 생겼다.

여기서, 당시 Http Agent로서 가장 대표적이었던 브라우저에게는 슬픈 사실이 존재했다. 브라우저에서 해석할 수 있었던 프로그래밍 언어는 JS가 유일했고, (지금은 간혹 가다 브라우저에 .wasm 파일이 있는 걸 확인할 수 있을 거다. 이 주제에 대해서는 나중에 따로 글을 쓰고 싶다.) 그나마 그것도 급하게 만들어진 볼품없는 상태의 언어였다.

WAS의 등장

이러한 필요성에 의해, 여기저기 프로그래밍 각 진영에서 동적인 데이터를 보여줄 수 있는 웹 어플리케이션 서버들이 등장하기 시작했다. 대표적인 게 아파치 재단의 Tomcat 같은 서버였고, 서버 단에서 자바나 php 같은 언어를 해석해 브라우저 단에게 완전한 페이지로 내려줄 수 있게 되었다.

JAVA 진영에서는 JSP가 완전히 집어먹고 있었다. Java Server Pages 의 약자로 기존 자바코드 안에 Html을 우겨넣어야 했던 불편한 Servlet 구조를 조금 손 봐, Html 태그 위에 서버코드를 보기 쉽게 얹어 쓸 수 있게 한 Server Side Template 기술의 일종이었다.

SSR과 MPA. 이러한 것을 가능케 해주는 Template Engine은 사실상 그 시대 웹 상의 표준이었다. 그러나 SSR은 치명적인 약점을 가지고 있었는데, 서버에서 미리 페이지를 다 랜더링해서 브라우저에 전달하기 때문에, 특정 Dom만 타겟해서 랜더링하기가 참 힘들다는 점이었다. 혹여나 네트워크 장애라도 나거나 특정 연산이 과도한 작업을 요구하는 페이지 때문에 서버에서 페이지를 받아오지 못하면, 사용자에게 나쁜 경험을 가져다 주게 돈다. 또한 서버에서 모든 랜더링 연산의 부담을 지우게 했다.

AJAX의 등장

언젠가부터 브라우저에서 지원해주는 API로, XMLHttpRequest라는 것이 나타났다. Ajax는 이 객체를 바탕으로 JS를 바탕으로 서버에 데이터를 요청해서 받아올 수 있는 기술의 통칭을 일컫는다. 필요에 따라 서버와 동기, 비동기 선택해서 통신을 할 수 있으며, 자바스크립트를 기반으로 하기 때문에 응답값을 받아 특정 돔을 조작해 화면조각을 바꿔치기 할 수 있었다. 이 부분이 중요한 포인트이다.

페이지 이동없이, 필요한 부분만 화면을 갈아끼울 수 있으며, 랜더링의 부담을 클라이언트 측에게 분산시킨다. 수신하는 데이터 양을 줄이고, 서버 처리를 기다리지 않고, 비동기 요청이 가능하다. AJAX의 등장은 더욱 인터렉티브한 웹 페이지의 구현을 가능하게 해줬다.

JQuery는 빛과 소금이었다.

문제는 AJAX를 사용하기 위해 쓰는 JS 문법이 너무 장황하고 고통스럽다는 점이다. 당시 브라우저에 종속적이었던 JS를 배우고 싶어했던 이는 아무도 없었다. 물론 나는 JS의 황금기에서 개발자로 살아가고 있지만 아무튼 전 시절을 들어보면 그렇다는 것이다.

다른 언어들과는 괘를 달리했던 혼란스러운 변수 Scope, Fetch도 (지금은 표준으로 들어온) 없었기 때문에 요청을 날리려면 XMLHttpRequest를 직접 조작하여 함수를 만들어야 했다. 부정확한 타입 시스템. 대부분의 편의적인 API를 제공하기 전의 JS는 혼란 그 자체였다.

jQuery는 기본적으로 JS를 쓰기 쉽도록 JS로 래핑한 JS 라이브러리이다. 브라우저 JavaScript를 작성하는 것의 어려움을 많은 사람들이 공감하고 있었고 그 영향 덕분에 엄청나게 빠른 속도로 전파되기 시작했다. 내가 막 웹 개발을 관심가지고 공부를 시작하던 때는 JS를 공부한다는 게, 순수한 JS가 아니라 JQuery를 배우는 것이 표준이었던 시대이다.

아무튼 이 시대 웹 페이지의 개발은 Server Side Template Engine + JQuery 의 조합으로 SSR과 CSR를 적절히 스까 써는 게 추세였다. 아래 그림은 전형적인 스프링부트를 사용한 MPA 앱의 구조이다.

모던 프론트엔드의 등장

React의 등장

모던 프론트엔드 생태계의 첫 시작은 React였다. 사실 그 전에 시초를 연 것은 AngularJS가 먼저이긴 한 것 같지만 구글이 버린 프로젝트이므로.. Jquery가 DOM을 다루는 방식이 가장 쉽고 효율적인 방식으로 인정받으며, 사실상 표준으로 굳어진 상황에서 Facebook이 새로운 Javascript 라이브러리를 발표했다. 리액트가 전략으로 내세웠던 3가지 큰 특징은 다음과 같다.

  1. Component 기반의 View 아키텍처

  2. JSX 문법

  3. Vitual DOM

Node.js의 등장, 웹 브라우저 환경의 변화 등 여러가지 JS 생태계의 큰변혁과 이어서 등장한 리액트는 단숨에 전세계 개발자를 사로잡았다. 모든 UI는 컴포넌트 단위로 조립되며, 마치 JSP를 연상시키는 Html 태그 안에 JS를 첨가할 수 있는 JSX. 그리고 Dom Api을 직접 접근하는 것이 아닌 가상돔과 데이터 바인딩을 통해 화면을 업데이트시킨다는 점.

Single Page Application, 즉 하나의 페이지에서 모든 UI 요소를 컴포넌트 단위로 갈아 끼우는 방식은 모던 웹에서 인터렉티브한 유저 경험을 증진시키는 데 최적의 방법으로 보였다. 데이터를 받아와서 갈아끼우는 방법의 귀찮음도 없어졌다. 리액트에서는 가상 돔. 그리고 기타 SPA 프레임워크에서는 그들만의 방법을 통해서, 서버로부터 데이터를 받아와서 상태를 업데이트 시키기만 하면 자동으로 Dom에 반영이 된다.

SPA 프레임워크의 황금기

아마 지금이 그 시기가 아닐까 하는데, 여러가지 대안이 있지만 React가 다 잡아먹었다고 생각한다. 여전히 70프로 이상의 사이트는 JQuery로 이루어져있다고 얘기하지만, 최근 흐름을 무시할 수는 없다. 내가 생각하기에 React를 가장 인기 있게 만들어준 이유는 그 자유로움에 있다고 본다. 비슷한 시기에 등장한 Vue.js도 강력한 후보였지만, Vue 같은 경우 프레임워크라고 불리는 특성에 맞게 문법과 구조가 딱딱 정해져있다면, React는 좀 더 자유로우며, JS 중심적이다. 필자는 Vue.js는 한 번도 해보지 못했으나 (코드 보기는 많이 봤다) 리액트가 좀 더 자바스크립트 친화적이며 매력적으로 느껴졌다.

이후로 여러가지 다른 좋은 대안들이 나왔다고 하지만, 아무래도 먼저 생태계를 잡아먹은 쪽을 비슷한 류의 다른 쪽이 아주 큰 메리트 없이는 이기지 못한다. 리액트는 무엇보다 든든한 Facebook이 밀어주고 있으며, 이미 리액트를 중심으로 이루어진 거대한 에코시스템을 무시할 수가 없다.

여튼, 최근 웹 트렌드는 서버는 REST API로서만 따로 존재하며, View Layer를 담당하는 쪽이 따로 떨어져나가 독립적인 영역을 선점하는 꼴이 되었다. 서로 별도의 영역을 점유하며 서로 다른 코드베이스를 가지고 따로 진화한다는 점이, 스케일 아웃과 확장성면에서는 유리한 측면이 분명 있을 것이다.

그리고 피로도..

일단 필자는 뭐가 거창한 웹을 바라지 않는다. 내가 바라는 건 그냥 데이터 뿌려주고, 정렬해주고, 간단한 효과와 이벤트들, 보기 그럴듯한 디자인이면 충분하다. 사실 현존하는 대부분의 웹사이트가 그 정도 수준이다. 그런데 리액트와 같은 JS기반 SPA 프레임워크를 쓰면, 그 간단한 거를 하기 위해서 세팅해주는 것도 진짜 너무 피곤하다. 가장 큰 문제는 JS 기반 모던 프론트엔드 환경이 점점 더 복잡해져 간다는 것이다.

일단 webpack이니 vite니 하는 번들러부터, babel 과 같은 트랜스파일러, nodejs 깔아야하고.. 거기다 npm package version은 맞춰야 되지 않나. 환경설정은 env 파일로 관리하고, Type 안전성을 가져오기 위해서 ts 쓸라치면 tsconfig도 작성해줘야 하고, eslint부터, prettier까지, SEO 신경써주기 위해서 SSR 같은 거 설정하려면, 또 next.js이니 뭐니 해서 프레임워크가 튀어나온다.

리액트 자체도 너무 러닝커브가 높다. 리액트 자체에서만 의미있는 각종 기본 hooks들도 외워야 되는 스트레스에, useEffect의 혼란스러운 사용법. 코드 스플리팅이니 뭐니, 하는 각종 테크닉들을 외워야 한다는 스트레스에,

또한 매번 상태관리는 또 어떻게 해야 할지에 대한 고민이 생긴다. 서버가 나눠진다는 것은, 서버에서 받은 데이터를 클라이언트 상태와 동기화해야 되는 부분에 있어서 끈임없이 고민점을 선사하게 된다. 예를 들어 로그인 상태 같은 경우는 그 웹 페이지에서 모든 컴포넌트가 동일한 상태를 맞춰야 될 게 아닌가. 리덕스, Mobx와 같은 툴을 활용해서, 전역 상태를 관리할 수 있지만, 또 하나의 러닝커브이다. 또한 클라이언트 내에서 상태를 일치시킬 뿐만 아니라, 서버와도 일치시켜야 된다. 이러한 점들에 있어서, react-query, swr 과 같은 상태 관리 툴들이 등장하긴 하였지만, 역시나 러닝커브이다.

결국 내가 지향하는 앱에 있어서 신경써야 될 것이 너무 많다. 그냥 혼자 개발할 때 프론트, 벡엔드 나누어져 있다는 거 자체가 힘들다. 가장 화가나는 부분은 내가 JSON으로 던져줄 DTO를 직접 만들고, 또 그걸 그대로 fetch해오는 ajax 함수를 고대로 만들고 있는 거다. 스스로 고생해서 일을 따블로 만드는 짓거리를 하고있는 셈이다.

또 이렇게 둘로 나눠져 있으면 빌드도 각각 따로 해야 되는데 이게 또 그렇게 화가난다. 이전에 thymeleaf + jquery로 뚝딱 만들어서 한방에 JAR로 배포하면, 끝인 걸 세팅을 세세하게 들어가야 된다. 코드베이스도 다른 걸 왔다리갔다리 보면서 고치는 것도 엄청 피곤하다. 보안과 인증/인가 처리하는 것도, 힘들어진다. CORS 설정도 신경써줘야 되며, session 기반으로 뚝딱 로그인 처리하는 것도 힘들어져서 JWT의 도입을 고려하게 된다.

나는 이 피로도에 대해 전적으로 공감한다.

그러다 우연히 이 영상을 보게되었다.

https://www.youtube.com/watch?v=DPAtQU-erM4&lc=UgwKE7PIg0ZOzhX5oqJ4AaABAg.9qbZacp3FE69qfbdtlc2Xv&ab_channel=SpringI%2FO

영상 보고 바로 삘 받아서 간단히 Todo App 만들어보았다.

https://github.com/stella6767/simple-todo

후기를 알려주자면, 개발경험이 진짜 상당히 좋았다.

일단 내가 쓴 건 JTE라는 템플릿 엔진인데, 간단히 말해 JSP version 2라고 생각하면 된다. 자바코드와 1대1 호응되며 자바코드로 컴파일 되기 때문에 문법이 자바랑 거의 똑같음. 당연히 컴파일 타임에 랜더링을 해놓으니, 속도도 타임리프보다 월등하고, 타입체크 문법에러도 사전에 확인할 수 있음. 타임리프처럼 문법이 틀려서 런타임에 에러터져서 확인할 일이 없다. JSP 같은 경우 역시 자바코드로 컴파일되나, EL 표현식은 런타임에 해석되므로 이와 같은 이점을 누릴 수 없다. gradle 플러그인도 지원해서 바이트코드 복붙해서 JAR로 패키징해주는 유틸리티도 지원한다. 핫 리로드 당연지원한다. 무엇보다 인텔리제이 플러그인이 있다.

HTMX는 진짜 혁명이다

서버사이드 랜더링의 가장 큰 단점이, 서버에서 미리 다 랜더링해서 브라우저에 던져주기 때문에, 특정 돔만 타겟해서 조작하기가 힘들다는 것인데, HTMX를 쓰면, JS 1도 없이 DOM 조작해서, 페이지 리로드 하지 않고, 화면조각 갈아끼울 수 있다. 러닝커브 3시간 예상해본다. 당근 서버에서 혼자 알아서 다 하니 CORS니 뭐니 하는 웹 보안정책 신경 쓸 필요도 없고. 배포도 아주 쉽다. 그냥 통째로 JAR 말아서 서버로 띄우면 됨.

Spring-View-Component도 아주 만족스럽다. 루비온레일즈의 ViewComponent에서 영감을 받았다는데, 루비는 모르겠지만, 재사용 가능한 컴포넌트 기반의 UI 구성하는데 굉장히 도움이 많이 된다.

만약 자신이 Spring 기반의 Backend 개발자라면 적극 추천한다. 물론 지금 Todo App 정도 단계여서 크게 판단을 할 수 있는 상황은 아니긴 하다. 하지만 큰 문제가 없다면 앞으로 혼자 사이드하는데 있어서 리액트 쓸 일은 절대 없을 것 같다.

참고

https://seokjun.kim/time-to-stop-react/

https://news.ycombinator.com/item?id=35829733

profile
시간대비효율

2개의 댓글

comment-user-thumbnail
2023년 6월 14일

피로도 부분까지 너무 공감하면서 잘 읽었습니다,, 다들 생각이 너무 비슷한게 한 편으로는 놀랍네요 :0

1개의 답글