Please enable JavaScript to view the comments powered by Disqus.

[번역] 자바스크립트 프레임워크의 네 시대

Four Eras of JavaScript Frameworks

이 글은 Four Eras of JavaScript Frameworks를 번역한 글입니다.

개발자로 일하며 수많은 기술이 새로 등장하고 사라지는 모습을 반복적으로 보고 있으면 그런 변화와 자극에 조금씩 무심해지는 것 같습니다. 이 글은 지난 십수년간의 프론트엔드 웹 개발의 흐름을 되짚어보며 지금까지 어떤 일이 있었는지, 지금 어디에 와 있는지 진단하고 있습니다. 그런 거대한 흐름을 이해하고 나면 자신이 서 있는 위치와 함께 나 자신의 모습도 보이게 됩니다. 그리고 앞으로의 미래를 바라보며 내가 무엇을 할 수 있는지, 해야 할 일이 무엇인지 파악할 수 있게 되는 것 같습니다. 이래서 역사 공부가 필요한 것일까요? 🙂


나는 자바스크립트를 메인으로 한 개발을 지난 2012년에 시작했다. 나는 어떤 지역 사업체를 위한 웹사이트 개발에 초기부터 참여하여 PHP와 기본적인 CMS를 사용해 만들었다. 그리고 그 업체는 웹사이트를 리뉴얼하면서 많은 기능을 추가하기로 결정했다. 프로젝트 매니저는 나에게 개발에 .NET을 사용하길 원했다(왜냐하면 그가 잘 알고 있는 것이 .NET이었기 때문에). 하지만 페이지 새로고침도 없고, 액션 사이에 긴 딜레이도 없는 네이티브 어플리케이션처럼 보이길 바라기도 했다. 얼마간의 조사와 프로토타이핑 후, 나는 그가 원하는 것이 이제 막 나오기 시작한 최신의 자바스크립트 프레임워크로 웹에서 어플리케이션을 만드는 것과 같은 형태라고 확신했다.

내가 첫 번째로 선택한 프레임워크는 Angular 1이었다. 나는 FuelPHP 백엔드와 함께 클라이언트 사이드도 상당히 많은 부분을 작업했는데, 개발 중에 오픈소스로 공개된 라우터 라이브러리를 사용하던 도중 이슈에 부딪혔다. 그 라이브러리를 사용하면 서브라우트/outlet을 렌더링할 때마다 화면이 깜빡였는데, 그런 모습은 웹사이트를 처음 설계하면서 기대했던 것이 아니었다. 해결책을 찾던 중 누군가가 Ruby on Rails와 Ember 조합을 추천했는데, 한번 시도해보니 깜빡임 현상 없이 기대한 대로 무척 잘 동작했다. 나는 그 프레임워크의 철학, 커뮤니티가 모두 마음에 들었고, 당시의 다른 대안과 비교해봤을 때 전반적으로 매우 생산적인 개발이 가능했다.

그때 이후로 많은 것들이 변했다. 프레임워크들은 나타나고, 사라지고, 그리고 급격히 진화했다. 당신이 지금 자바스크립트로 브라우저에서 앱을 만드는 방식은 과거에는 어떤 주변 기술이었지만 지금은 표준 사례가 된 것이다. 그리고 우리가 사용하는 인프라는 완전히 바뀌어서 새로운 것들을 가능하게 해주고 있다.

당시에는 물론 그 방식에 대해 무척 많은 경쟁과 충돌이 있었다. 나는 프론트엔드 업계에 한동안 몸을 담아 온 대부분 사람이라면 다양한 논쟁에 참여했을 것이라 생각한다. 그 다양한 것들이란 아마도… 모든 것에 대해서다. 어떤 자바스크립트 프레임워크를 사용할 것인지, 어떻게 CSS를 작성할 것인지, 함수형 vs 객체 지향 프로그래밍, 어떻게 상태를 관리할 것인지, 어떤 빌드 시스템과 도구가 가장 유연하고 빠른 것인지 등등. 돌이켜 볼 때 우리가 얼마나 잘못된 것을 맞다고 주장하면서 더 큰 패턴을 놓치고 있었는지를 생각해보면 무척 웃기다. 물론 시간이 지나서 돌아보고 있으니 그렇게 생각할 수 있긴 하다.

그래서 나는 회고를 해 보려고 한다. 지난 몇십 년간의 자바스크립트 개발을 뒤돌아보고 우리가 어디까지 왔는지를. 지난 시간은 다음의 네 시대로 나눌 수 있을 것이다.

  1. 예전 시대
  2. 최초의 프레임워크
  3. 컴포넌트 중심 뷰 레이어
  4. 풀 스택 프레임워크(← 우리는 지금 여기)

각각의 시대는 메인 테마와 중심이 되는 대립이 있었다. 그리고 커뮤니티는 매번 중요한 것을 배웠고, 느리지만 확실히 진전해 나갔다.

오늘날 논쟁은 더 격해졌다: ‘웹은 너무 덩치가 커져 버렸나?’, ‘일반적인 웹사이트가 굳이 React로 작성될 필요가 있나?; 심지어 ‘우리는 자바스크립트를 사용해야 하나?’같은 것들이다. 나는 우리가 지금은 미래를 들여다볼 수 없지만 결국에는 다시 새로운 발견을 할 것이라 생각한다. 지금 우리는 서로 다른 이야기를 하면서 큰 그림을 놓치고 있다. 하지만 그런 과거로부터 얻은 작은 발견이 우리를 미래로 나아가게 만든다.

예전 시대 (The Before Times)

자바스크립트는 1995년 처음 릴리즈되었다. 위에서 언급했듯 나는 그로부터 20년이 지난 후인 2012년부터 자바스크립트를 사용하기 시작했고, 당시의 프레임워크에 대해 설명하려고 하고 있다. 나는 이 시대의 많은 역사에 대해서 설명하려 하겠지만, 당신이 상상할 수 있듯이 이 시대는 또 지배적으로 사용되었던 패턴과 라이브러리, 빌드 툴 등에 의해 여러 개의 하위 시대로 나뉠 수 있다.

다시 말해, 나는 내가 경험하지 않은 것들에 대해서는 얘기할 수 없다. 내가 프론트엔드 앱을 개발하기 시작한 시점에는 새로운 세대의 프레임워크들이 발전 중이었다: Angular.js, Ember.js, Backbone이 그것이었고, 이 외에도 여러 개가 있었다.

이들이 등장하기 전 첨단의 기술은 jQuery나 MooTools 같은 것이었다. 이 라이브러리들은 당시에는 무척 중요했는데, 브라우저마다 다르게 구현된 자바스크립트의 차이를 줄여주는 역할을 했기 때문이다. 예를 들어 Internet Explorer와 Netscape는 Event 구현에 완전히 다른 방식을 사용했는데, 한쪽은 이벤트 버블링이었고 다른 한쪽은 이벤트 캡쳐링을 사용했다. 그리고 그런 차이가 지금의 웹 표준이 두 방식을 모두 포함하고 있는 이유가 되었으나, 어쨌든 예전에는 두 브라우저에서 모두 동작하는 코드를 구현하려면 라이브러리를 사용해야 했다. 그 라이브러리들은 작고 독립적으로 동작하는 UI 위젯을 만드는 데 주로 사용되었다. 어플리케이션의 주된 비지니스 로직은 여전히 form과 HTTP 리퀘스트에 의해 이뤄졌고, HTML을 서버에서 렌더링하여 클라이언트에서 제공하는 방식을 사용했다.

그리고 이 시대에는 내가 아는 한 커뮤니티에서 언급되는 빌드 툴이 그렇게 많지 않았다. 자바스크립트는 아직 모듈을 가지고 있지 않았고(최소한 당시에는 표준이 아니었다), 코드를 import할 수 있는 방법도 없었다. 모든 것은 전역 공간에 존재했고, 코드를 정리하기도 쉽지 않았다.

이런 환경이었으니 자바스크립트가 장난감스러운 언어로 취급당해도 이해할 만 했다. 풀 어플리케이션을 작성하는데 사용할 만한 언어로 인식되지는 않았다. 자바스크립트로 가장 많이 하는 일은 몇 개의 UI 위젯 동작에 필요한 스크립트를 jQuery와 함께 불러온 후 호출하는 것이었다. 시간이 지나면서 XHR이 도입되었고 인기를 얻었으며, 사람들은 클라이언트와 백엔드 사이의 복잡한 플로우가 필요한 UI의 일부분을 싱글 페이지로 구현하기 시작했다. 하지만 앱의 중요한 부분은 여전히 서버에 견고히 유지되었다.

이런 모습은 모바일 앱이 시장을 강타하기 시작했을 때 큰 대비를 보여줬다. iOS와 Android 앱은 처음부터 Objective C와 Java라는 Serious Languages1로 어플리케이션이 모두 구현되었기 때문이다. 게다가 완전히 API 기반이다. 모든 UI 로직은 디바이스 위에서 돌아가며, 서버와의 통신은 단순히 데이터 포맷만 전달하는 것으로 가능하다. 이는 더 나은 사용자 경험을 가능하게 했고, 모바일 앱의 인기는 폭발적으로 성장했다. 그리고 그 인기는 모바일 앱과 웹 앱 중에서 어느 것이 더 나은지 토론하고 있는 오늘날까지 이어지고 있다.

저런 작업을 전부 자바스크립트로 하는 건 처음에는 비웃음당할만한 일이었다. 하지만 시간이 지남에 따라 점점 더 많은 것들이 야심 차게 구현되어 나갔다. 소셜 네트워크는 채팅과 DM 등의 실시간 기능을 추가했고, Gmail과 Google Docs는 데스크탑 어플리케이션과 똑같은 기능을 브라우저에서 구현할 수 있다는 것을 보여줬다. 그리고 점점 더 많은 기업이 점점 더 많은 사용 사례를 웹 앱으로 구현하기 시작했다. 왜냐면 웹은 어디서든 동작하며 유지보수가 더 쉽기 때문이다. 이제 자바스크립트는 더 이상 사소한 앱을 만드는 언어가 아니라는 사실을 세상에 알리기 시작했다.

하지만 자바스크립트를 사용한 앱 개발은 여전히 어려운 일이긴 했다. 자바스크립트는 오늘날 그것이 가진 기능을 모두 가지고 있지 않았다. 앞서 말했듯 모듈이라는 개념이 없었으므로 모든 변수는 전역 공간에 있었고, NPM도 없었으므로 개발자는 외부 라이브러리를 직접 다운로드해서 프로젝트 소스코드에서 정적인 파일들이 있는 폴더에 옮겨둔 후 HTML 파일에 script 태그를 추가하여 불러와야 했다. 그리고 당시의 자바스크립트는 오늘날 갖고 있는 기능의 절반도 없었다. 앱의 대부분은 페이지마다 맞춤 형식으로 개발되었는데, 상태 관리와 렌더링 업데이트에 플러그인마다 다른 시스템을 사용하는 식이었다. 이런 이슈들을 해결하기 위해 최초의 프레임워크가 떠오르기 시작했다.

최초의 프레임워크

2000년대 말과 2010년대 초반 최초의 JS 프레임워크가 풀 클라이언트 어플리케이션 구현에 맞춰 설계되었고 등장하기 시작했다. 이 시대의 주목할 만한 프레임워크 중 일부분은 다음과 같았다.

  1. Backbone.js
  2. Angular 1
  3. Knockout.js
  4. SproutCore
  5. Ember.js
  6. Meteor.js

물론 이 외에도 많은 프레임워크가 있다, 그리고 아마 어떤 면에서 더 큰 규모를 가진 것도 있었을 것이다. 이들은 상대적으로 인기가 좋았고 내가 프로토타이핑이나 개발에 직접 사용했기에 기억하는 것들이다.

그들은 미지의 영토에 발을 들여놓으려는 세대의 프레임워크들이었다. 달리 말하면, 그들이 하려는 것은 매우 야심적이고, 많은 사람이 결코 할 수 없을 것이라 생각했던 것이었다. 당시 단일 페이지(single-page) 자바스크립트는 근본적으로 나쁘다고 비방하는 사람들이 많았다. 그건 많은 면에서 사실이었다. 클라이언트 사이드 렌더링은 검색 엔진이 페이지를 쉽게 크롤링하지 못하도록 했고, 유저는 웹페이지가 페인팅을 시작하기 전까지 몇초 이상 기다려야 하기도 했다. 많은 앱이 웹 접근성에서 최악이었고, 심지어 브라우저에서 자바스크립트 기능을 꺼 버리면 아예 동작하지 않았다.

그러나, 우리는 자바스크립트만으로 앱을 만들었던 경험이 없었기에, 모두 단결하여, 어떤 방법이 최선일지에 대한 아이디어를 끊임없이 쏟아냈다. 대부분의 프레임워크는 다른 프레임워크에 기반한 변형품들이었다. 그래서 그들 대부분이 모델-뷰-something 패턴(Model-View-Controller, Model-View-Producer, Model-View-ViewModel, 기타 등등)의 반복이었다. 이들 중 무엇도 그 길었던 경주를 끝내지 못했다. 어떤 프레임워크도 특별히 직관적이지도 못했고, 사용하다 보면 순식간에 복잡해져 버리곤 했다.

또 이 시대는 자바스크립트를 컴파일하는 방법에 대한 제대로 된 실험이 시작된 시대이기도 하다. Node.js는 2009년에 릴리즈되었고, 이어서 2010년에 NPM이 패키지(서버 사이드)를 도입하면서 등장했다. CommonJS와 AMD는 JS 모듈을 어떻게 정의하는 것이 최선인지에 대해 경쟁했고, Grunt, Gulp, Broccoli 같은 빌드 툴은 모듈들을 어떻게 프로덕션 빌드에 묶어낼 것인지를 놓고 경쟁했다. 이들 대부분은 일반적인 태스크 러너 툴이었는데, 무엇이든 빌드할 수도 있었다. 그러다 보니 자연스럽게 웹 앱 안에 들어가는 요소인 자바스크립트, HTML, CSS/SASS/LESS, 그리고 이 외의 다양한 것들을 빌드하는 데 쓰이게 되었다.

우리는 이 시대에서 매우 중요하고 근본적인 교훈을 배웠다:

  • URL 기반의 라우팅은 필수적이다. 그것을 갖고 있지 않은 앱은 웹을 망가뜨린다. 이는 프레임워크의 시작부터 고려되어야 한다.
  • 템플릿 언어로 HTML을 확장하는 것은 강력한 추상화 계층이다. 다소 투박하게 느껴질지는 몰라도, UI를 앱의 상태와 동기화시키는 것을 더 쉽게 만들어준다.
  • SPA에서 퍼포먼스를 높이는 것은 어렵다, 그리고 네이티브 앱에 없는 많은 제한 요소가 있다. 우리는 앱의 코드를 전부 네트워크에 실어서 전송해야 하는데, 그 전송을 가능한 빨리 끝내고 앱을 실행시켜야 한다. 반면 네이티브 앱은 이미 다운로드와 컴파일이 끝난 상태로 제공된다. 웹 앱을 시작하기 위한 그 일련의 과정들은 엄청난 작업이다.
  • 자바스크립트는 언어로서 많은 이슈를 가지고 있었다. 그리고 개선되어야 할 부분이 정말로 많았다. 그걸 프레임워크가 혼자 할 수는 없다.
  • 우리가 큰 규모의 앱을 구현하기 위해서는 정말로 더 좋은 빌드 툴, 모듈, 패키징이 필요했다.

전반적으로, 이 시대는 무척 생산적이었다. 여러 결점에도 불구하고 많은 경우에서 백엔드 API에서 클라이언트를 분리함에서 오는 이익이 앱의 사이즈에 비례해서 커졌고, 그에 따르는 사용자 경험이 뛰어났다. 만약 역사가 조금 달랐더라면, 이 시대가 계속되어 우리는 지금도 여전히 MV* 스타일을 가진 프레임워크를 계속 만나보고 있었을지도 모른다.

하지만 어디에선가 소행성이 하나 나타나 존재하는 패러다임을 완전히 깨부숴 버렸고, 일부 종의 멸종을 유발하며 우리를 다음 시대로 향하게 했다. 그 소행성의 이름은 React다.

컴포넌트 중심 뷰 레이어

나는 React가 컴포넌트를 발명했다고 생각하지 않는다. 하지만 솔직히 컴포넌트가 언제 처음 등장했는지는 확실히 잘 모르겠다. 최소한 닷넷의 XAML에 유사한 기술이 있었고, 웹 컴포넌트도 그 시기에 스펙 개발이 시작되고 있었다. 궁극적으로는 뭐가 처음이었는지는 상관없다. 어떤 아이디어가 등장하면, 모든 메이저 프레임워크는 그것을 재빠르게 수용한다.

컴포넌트는 모든 것이 잘되도록 만들었다. HTML을 확장하고, 전역에서 오랫동안 살아남는 상태 변수를 줄이고, 자바스크립트 비즈니스 로직이 템플릿에 확실히 연결되도록 했다(JSX, Handlebar 또는 Directives 들이 그렇게 만들었다). 컴포넌트 기반의 어플리케이션은 기존 방식에서 필요했던 추상화의 대부분을 제거했다. 그리고 코드의 라이프사이클을 현저히 단순하게 만들었다. 모든 것은 앱이 아닌 컴포넌트의 라이프사이클과 묶이게 되었고, 개발자로서는 구현 중에 고려해야 할 사항을 훨씬 적게 만들었다.

하지만, 그 시기에 또 다른 도약도 있었는데, 모든 기능을 갖춘 프레임워크가 아닌 “뷰 레이어” 프레임워크라는 말로 자신을 홍보하는 프레임워크들의 등장이었다. 그들은 프론트엔드 앱에 요구되는 모든 문제를 해결하기보다는, 오직 렌더링을 이슈를 해결하는 데 초점을 맞추고 있었다. 프론트엔드 앱의 다른 문제로는 API 통신, 상태 관리 등이 있는데 그것들은 사용자들에게 떠넘겨졌다. 이 시기의 유명한 프레임워크들은 다음과 같다.

  1. React.js
  2. Vue.js
  3. Svelte
  4. Polymer.js

그리고 이 외에도 많고 많은 프레임워크가 있다. 돌이켜보면 뷰 레이어에 초점을 맞춘 두 번째 세대의 프레임워크의 인기는 다음의 두 가지를 가능하게 만들었기 때문이라고 본다.

  1. 스쿠프(scope)를 엄청나게 줄여버렸다. 눈앞에 높인 모든 문제를 해결하려고 하는 대신, 프레임워크의 핵심은 렌더링에 집중하고 있다. 상태 관리 같은 다른 문제들에 대해선 개발 생태계 속에서 많은 아이디어와 방향이 탐구되었다. 그중에는 끔찍한 솔루션들도 무척 많았지만, 좋은 것들도 있어서 다음 세대가 최선의 아이디어를 선택할 수 있도록 길을 닦아 주었다.
  2. 프레임워크를 도입하기 쉽게 만들었다. 모노리스(monolith) 서버 사이드 앱에게 풀 프레임워크를 도입한다는 것은 사실 기존의 앱의 대부분을 새로 작성한다는 말과 같다. 하지만 React나 Vue같은 프레임워크는 서비스 중인 앱에도 중간에 도입해서 1개의 위젯이나 컴포넌트로부터 시작해서 기존의 코드를 점진적으로 마이그레이션 하는 것이 가능하다.

이 두 요소는 두 번째 시대의 프레임워크가 빠르게 성장하도록 하면서 첫 번째 시대가 저물도록 만들었다. 그리고 멀리서 보면 모든 것이 잘 들어맞고 논리적인 혁신을 이룬 것처럼 보인다. 하지만 저 시대를 지나는 중에는 때때로 꽤 좌절스러운 경험도 했었다.

우선 저 관점은 어떤 프레임워크를 업무에 도입할지, 또는 앱을 새로 만들어야 하는지 토론할 때 자주 만나는 것은 아니었다. 대신, “더 빠르다!” 라거나, “더 작다!”, 또는 “당신에게 필요한 모든 것!”이라는 문구를 더 자주 접하게 된다. 또 함수형 프로그래밍이냐-객체 지향 프로그래밍이냐에 대한 토론도 있었다. 그리고 공정하게 얘기하면 이것들은 모두 사실이긴 했다. 뷰 레이어 컴포넌트는 작고(처음에는) 그리고 빠르고(처음에는) 그리고 당신에게 필요한 모든 것이다(당신이 만약 다른 많은 것들을 스스로 한땀 한땀 구현한다면). 그리고 확실히 함수형 프로그래밍 패턴은 자바스크립트를 오염시킨 수많은 문제를 해결했다. 그리고 나는 평균적인 자바스크립트 코드의 품질이 그들 덕분에 좋아졌다고 생각한다.

하지만 현실은, 은제 탄환(silver bullet)따위는 없으며, 결코 있을 수 없다. 뷰 중심의 프레임워크들을 사용해도 여전히 앱은 비대해지고 복잡해진다. 상태는 여전히 관리하기 어렵고, 라우팅이나 SSR같은 근본적인 문제도 풀어야 할 문제다. 그리고 대부분의 사람은 마치 모든 것을 해결하려는 솔루션을 버리고 사용자에게 그 연습을 맡기는 프레임워크를 원하는 것 같았다. 내 경험상 이것은 새로운 제품이나 기능을 출시하려는 엔지니어링 조직에 보편적으로 존재하는 현상이다. 그리고 계획했던 그 모든 기능을 개발하는 데 시간을 충분히 투자하지 못하곤 한다.

하지만 한편으로는 기존의 첫 번째 시대 풀서비스 프레임워크도 이 문제를 제대로 풀지 못하고 있었다. 부분적으로, 이는 수많은 기술적 부채 때문이었다. 첫 번째 시대의 프레임워크는 ES6이 나오기 전, 모듈이 있기 전, Babel과 Webpack이 있기 전이었으며, 그리고 우리가 찾아낸 수많은 해법이 존재하기 전에 만들어졌었다. 그 기술들을 꾸준히 도입하며 프레임워크를 발전시키기는 것은 무척 어려운 일이다(나는 이전에 Ember 프레임워크의 코어 팀 멤버였기 때문에 이를 잘 알고 있다). 그리고 Angular 2가 그랬던 것처럼 프레임워크를 완전히 새로 개발하는 것은 커뮤니티 활동 모멘텀을 크게 낮춰버리는 일이기도 하다. 그러므로 자바스크립트 프레임워크 세계로 오는 개발자들은 바위가 있는 힘든 환경에 오는 것과 같았다. 생긴지 얼마 안 된 올인원(all-in-one) 솔루션을 선택하거나, 모든 것을 자유롭게 고르되 그 길이 최선이길 바라며 프레임워크의 절반을 DIY 해야 한다.

결과적으로(내 경험상 이런 일이 더 자주 일어났다) 이들 뷰 레이어와 함께 구성된 수제 프레임워크가 만들어지고, 그것들은 또 커지고, 복잡해지고, 작업하기가 매우 어렵게 되어버린다. 사람들이 SPA를 사용하면서 생기는 많은 문제는 파편화된 에코시스템이며, 그 문제는 SPA가 폭발적으로 성장하기 시작한 바로 그 시기에서 왔다. 나는 여전히 라우팅을 제대로 못 하거나 디테일을 챙기지 못하는 신규 웹사이트들을 자주 마주치곤 하는데, 그럴 때마다 큰 실망감을 느끼곤 한다.

내가 말했듯 이 시기는 무척 좌절스러웠지만, 결과적으로는 혁신적인 기술이 아주 많이 등장했다. 자바스크립트 생태계는 정말로 빠르게 성장했기에 이들 프레임워크는 그들에게 필요한 최선이 무엇인지 찾아냈다. 그리고 또 몇몇 핵심적인 변화가 일어났다.

  • Babel 같은 트랜스파일러의 사용이 일반화되어 언어를 현대화했다. 새로운 기능이 언어의 표준이 되기까지 몇 년을 기다리는 대신 오늘 당장 사용할 수 있게 되었다. 그리고 자바스크립트 언어 자체도 더 빠른 주기로 새로운 기능을 추가하기 시작했다.
  • ES 모듈이 표준화되어 마침내 현대적인 빌드 툴인 Rollup, Webpack, 그리고 Parcel 등이 개발될 수 있도록 했다. Import 기반의 번들링은 서서히 일반되었고, 이제 자바스크립트가 아닌 스타일시트, 이미지 파일 같은 자원들도 번들링이 가능하다. 설정이 단순해지면서 빌드 툴들은 전반적으로 더 가볍고, 더 빠른 성능을 보여준다.
  • 점점 많은 API가 표준화되면서 Node와 웹 표준 사이의 차이가 조금씩이지만 확실히 줄어들었다. SSR은 실제로 가능성을 가지기 시작했고, 어떤 앱들은 이미 사용하고 있었다. 하지만 여전히 매번 앱마다 맞춤 설정이 필요했다.
  • 엣지 컴퓨팅이 공개되었고, 자바스크립트 기반의 서버 앱에 배포/응답 시간 측면에서 SPA에 있는 장점을 제공해줬다(SPA는 일반적으로 사용자로부터 가까이 있는 CDN에 있는 정적인 파일들 덕분에 로딩 시작을 빨리할 수 있었다. 비록 종단의 디바이스에서는 그 로딩이 완전히 끝나 렌더링이 되기까지 조금 더 오래 걸린다고 하더라도).

이 시대의 끝에, 일부 문제는 여전히 남아 있었다. 예전보다는 더 좋은 패턴을 찾아냈음에도 상태 관리와 반응성은 여전히 어려운 문제였다(그리고 지금도 그렇다). 퍼포먼스는 여전히 어려운 문제다. 상황은 조금씩 나아지고 있긴 하지만 여전히 헤아릴 수 없이 많은 수의 비대한 SPA가 웹에 존재한다. 그리고 웹 접근성 상황은 개선되었지만, 기술 조직에서는 여전히 사후 고려 대상이었다(그리고 지금도). 하지만 이러한 변화들이 다음 시대의 프레임워크를 위한 길을 닦았으며, 이제 그들에 대해 이야기하려고 한다.

풀-스택 프레임워크

개인적으로는 프레임워크의 마지막 시대에서 무척 슬픈 감정을 느꼈다. 그건 내가 지난 4년 동안 Ember의 렌더링 레이어에 매우 깊이 참여하며 앞서 말한 첫 번째 시대의 프레임워크들이 가진 기술 부채들을 해결하려 노력하면서 시간을 보냈기 때문이라고 생각한다. 그리고 3번째 세대의 모든 프레임워크들은 훨씬 더 교묘하게, 이전 세대의 뷰 레이어 프레임워크를 기반으로 만들어졌기 때문이기도 하다. 주목할 만한 것들은 다음과 같다.

  1. Next.js (React)
  2. Nuxt.js (Vue)
  3. Remix (React)
  4. SvelteKit (Svelte)
  5. Gatsby (React)
  6. Astro (Any)

이들 프레임워크는 뷰 레이어의 고도화에서부터 시작했다. 이제 우리는 모두 뷰 레이어 컴포넌트는 프레임워크의 상위에 올라가는 핵심 요소이며, 앱의 다른 부분인 라우터, 빌드 시스템, 폴더 구조 등의 표준화를 시작하는 것이 합리적인 것이라고 동의한다. 느리지만 확실히, 이 메타-프레임워크들은 첫 번째 세대가 제안했던 즉시 사용할 수 있는 올인원 솔루션을 만들기 시작했다. 필요한 기능들은 오픈소스 생태계에서 최선의 패턴을 골라내어 충분히 성숙한 상태에 있다면 프레임워크에 통합하고 있다.

그러고 나서 그들은 한 발짝 더 나아갔다.

지금 시점까진 SPA는 전적으로 클라이언트에 포커스를 맞추고 있었다. SSR은 모든 프레임워크가 간절히 해결하길 바랐으나, 궁극적으로는 서버에서 렌더링 된 HTML을 메가바이트 단위의 자바스크립트 로딩이 완료된 후 교체하기 위한 최적화 수단이었다. 1세대 프레임워크 중 오직 하나, Meteor.js만이 더 크게 생각했었지만 그들의 아이디어인 동형(isomorphic) JS는 결코 뜨지 못했다.

하지만 그 아이디어는 앱의 사이즈와 복잡도가 커지면서 다시 주목받았다. 우리는 그것이 백엔드와 프론트엔드가 함께할 때 정말 유용하다는 것을 알아차렸다. 그렇게 하면 어떤 리퀘스트에 사용할 API 시크릿을 숨기거나, 페이지를 리턴할 때 헤더를 수정하거나, API 리퀘스트 프록시를 구성하는 것 같은 일이 가능하다. 그리고 Node와 Deno가 점점 더 많은 웹 표준을 구현하고, 서버 사이드 JS와 클라이언트 사이드 JS의 간격이 매년 줄어들면서, 이제는 동형 JS가 그렇게 미친 아이디어는 아니었다고 여겨지기 시작한 것 같다. 이것과 엣지 컴퓨팅, 그리고 멋진 도구들을 함께 조합하면 당신은 놀랄 만한 가능성을 얻게 된다.

이 마지막 세대의 프레임워크들은 그 가능성을 전부 활용하여 클라이언트와 서버를 끊어짐 없이 연결하는데, 나는 이것이 얼마나 놀라운지 말로 표현할 수가 없다. 내가 지난 9개월간 SvelteKit을 사용하며 작업을 했었는데, 몇 번이나 “이게 바로 우리가 해야 했던 방식이야”라고 중얼거리며 의자에 등을 기댔는지 셀 수가 없을 정도다.

다음은 최근 내가 믿을 수 없을 정도로 쉽게 했던 작업의 일부다.

  • 어플리케이션에 서버 사이드 OAuth 인증을 추가해서 인증 토큰이 결코 서버 밖으로 나가지 않도록 했다. 우리의 API에 리퀘스트를 보낼 때마다 헤더에 토큰을 추가해주는 API 프록시도 함께 구성했다.
  • 프록시를 사용해 앱의 특정 라우트를 우리의 CDN으로 연결되도록 하여, 어떤 프레임워크에서 만들어진 HTML 페이지든 호스팅이 가능하도록 했다. 이를 통해 유저들이 그들의 커스텀 페이지를 만들 수 있었다(우리의 고객 중 일부에게 제공되는 서비스).
  • 시크릿 키가 필요한 외부 서비스가 필요할 때 여러 가지 1회용 API 라우트를 추가했다(우리의 API에 완전히 새로운 라우트를 추가할 필요가 없고 백엔드 개발자들과 조율할 필요도 없다).
  • LaunchDarkly가 사용되는 곳을 서버 사이드로 옮김으로써 더 적은 자바스크립트를 로드하여 전체적인 비용을 줄였다.
  • 백엔드 라우트에 Sentry 리퀘스트를 위한 프록시를 추가하여 광고 차단 확장 프로그램 때문에 기록되지 않는 에러를 확인할 수 있다.

이는 빙산의 일각일 뿐이다. 이 모델에서 할 수 있는 멋진 일들은 이 외에도 아주 많이 있다. 가장 큰 일 중 하나는 점진적 향상(progressive enhancement)에 어떻게 다시 활력을 불어넣느냐다. 서버와 클라이언트가 결합한 특징을 사용하여 클라이언트 디바이스에 자바스크립트가 비활성화되었을 때 완전한 앱 대신 기본적인 HTML과 HTTP를 제공받을 수 있게 할 수 있다. 내가 SPA를 사용하기 시작했을 때, SPA가 클라이언트 개발의 미래라 생각했었기에 점진적 향상의 구현을 완전히 포기했었다. 하지만 이제 그것이 다시 돌아오기 시작한 모습을 보고 있으니 너무나 기쁘다.

지금까지 말한 내용이 이 프레임워크들을 새로운 세대로 분류하게 만든(어디까지나 실험적인 분류다) 새로운 모습들이다. 이전에는 해결이 어렵거나 불가능했던 문제들은 이제 응답 처리 로직을 조금 바꿈으로서 처리되는 사소한 문제가 되었다. 확실한 성능과 UX는 이제 별도의 설정 없이 즉시 사용하다. 새로운 서비스를 구성하고 만드는 대신 별도의 엔드포인트를 추가하거나 미들웨어를 필요한 만큼 추가할 수 있게 되었다. 그냥, 삶이 달라졌다.

나는 이 세대가 1세대 프레임워크, 2세대 프레임워크, 그리고 유저들 사이에 있는 주요 긴장 지점도 해결했다고 생각했다. 무설정(zero-config) 방식으로 옮겨가는 데서 시작했지만, 나는 그것이 궁극적으로는 2세대 프레임워크를 발전시키고 안정화하려고 노력한 오픈소스 생태계가 이끌었다고 생각한다. 그것은 문화적인 변화였다. 세 번째 세대의 프레임워크는 렌더링만이 아닌 프론트엔드 개발에서 우리가 해결해야 하는 모든 근본적인 문제를 해결하려고 하면서 이제 다시 첫 번째 세대 같은 올인원 솔루션이 되려 하고 있다.

지금 커뮤니티들은 어느 때보다 일치단결하여 SPA가 유발한 많은 문제를 해결하려고 노력하는 것처럼 보인다. 그리고 중요한 사실은, 함께 해결하고 있다는 것이다.

다음은 어디로 갈까?

전반적으로 자바스크립트 커뮤니티는 올바른 방향으로 가고 있다고 생각한다. 마침내 우리는 “오직 뷰 레이어”만이 아닌 풀 어플리케이션을 처음부터 만들어낼 수 있는 성숙한 솔루션을 개발하고 있다. 마침내 우리는 모든 도구가 처음부터 바로 제공되는 네이티브 앱의 SDK와 같은 필드에서 경쟁할 수 있게 되었다. 하지만 여전히 해야 할 일들은 많이 남아있다. SPA에서 웹 접근성은 언제나 뒷전이었다. 그리고 나는 여전히 GraphQL 외부에서 데이터 스토리가 일부 작업을 사용할 수 있을 것으로 생각한다(그걸 좋아하든 아니든, 대부분의 웹은 REST에서 동작한다). 어쨌든 지금의 흐름은 올바르다. 만약 우리가 계속 서로의 솔루션을 공유하는 방향으로 나아간다면 어느 때보다 좋은 방법으로 이 문제들을 해결할 수 있으리라 생각한다.

나는 이 발전 패턴이 더 위쪽으로, 즉 웹 플랫폼 그 자체에 적용되었을 때의 잠재성에 대해서도 무척 기대하고 있다. 웹 컴포넌트는 조용하지만, 여전히 진행되고 있고, SSR과 전역 등록 이슈 해결을 위한 작업이 진행 중이다. 그 스펙은 3세대 프레임워크들과 더 높은 호환성을 가지게 해 줄 것이다. 한편, 웹 어셈블리도 이 발전 패턴을 적용하여 놀라운 결과를 낳도록 만들 수도 있다. 어떤 언어로도 작성할 수 있는 풀-스택 프레임워크를 상상해보라. 동형 러스트, 동형 파이썬, 동형 스위프트, 동형 자바 등등은 마침내 프론트엔드와 백엔드 사이의 장벽을 시스템 끝부분에 아주 조금의 HTML 템플릿만 남겨두고 거의 사라지도록 만들어 버릴 수도 있다(역설적으로 그것은 우리에게 ‘완전함’과 더 나은 UX를 가져다준다).

지금 나에게 미래에 대한 희망이 커 보이는 이유는 우리가 파편화의 시대를 지나왔다는 사실 때문이다. 매일 매일 새로운 자바스크립트 프레임워크가 등장하는 시대는 이제 지났다. 자유와 유연성은 혁신을 낳았지만, 그것들은 지저분하고, 끊어져 있고, 종종 근본적으로 망가진 웹 경험을 낳기도 했다. 개발자들이 한정된 자원과 빡빡한 일정 속에서 수십 가지 옵션들 중에서 고른 도구들을 직접 조립해야 했으니 그럴 만도 했다. 그 결과 어떤 앱들은 놀라울 정도로 빠르고, 안정적이고, 신뢰할 수 있고 사용하기 즐겁지만, 반면 어떤 다른 앱들은 불편하고, 어렵고, 느리고, 망가져 있었다.

우리는 “처음부터 올바른 일을 해주는” 도구를 사용함으로써 개발이 더 쉬워지게 만들 수 있다. 그러면 어쩌면 웹사이트의 평균적인 품질이 조금 더 좋아질 수 있고, 평균적인 웹 경험이 더 부드러워 질 수 있다. 좋은 도구가 모든 사이트를 좋게 만들지는 못한다. 코드의 양은 나쁜 UX에 대한 해결책이 될 수 없다. 하지만 같은 기반을 제공함으로써 모든 사이트는 조금 더 나은 상태에서 시작하게 될 것이다. 그리고 모든 개발은 보다 더 중요한 일에 집중할 수 있게 될 것이다.


  1. C 언어처럼 다양한 형태의 소프트웨어를 구현하는데 사용할 수 있는 언어. Serious란 단순히 ‘작업량이 많다’는 것을 의미한다. 같은 내용을 구현하는데 스크립팅 언어는 더 짧은 시간 안에 작성 가능하다. 기계어는 궁극의 ‘serious’ 언어라고 할 수 있다. 출처 - https://wiki.c2.com/?SeriousVersusScriptingLanguages