SPA의 탄생과 발전
-
전통적인 웹: 2000년 Roy Fielding의 REST 정의처럼, 웹은 링크를 선택하면 다음 페이지가 전송되고 렌더링되는 방식이었습니다. 각 사용자 액션은 전체 페이지 새로고침으로 이어졌습니다.
-
AJAX의 등장: 1999년 Microsoft의 XMLHttpRequest와 2005년 Jesse James Garrett가 명명한 AJAX는 느린 브라우저, 불안정한 네트워크, 전체 페이지 새로고침의 비효율성, 그리고 ‘데스크톱과 같은’ 상호작용성에 대한 사용자 기대를 충족시키기 위해 등장했습니다. 이는 서버가 HTML 대신 JSON을 보내고 브라우저가 페이지를 로컬에서 재구성하는 SPA 시대를 열었으며, Angular(2010), React(2013), Vue(2014)와 같은 프레임워크들이 이 아이디어를 공식화했습니다.
SPA 성능 문제의 구조적 원인
-
잦은 백엔드 왕복: 단순한 예시에서는 SPA가 효율적으로 보일 수 있지만, 애플리케이션이 커질수록 프런트엔드는 백엔드에 수십 번의 HTTP 요청을 보내야 합니다. Facebook이나 LinkedIn의 홈 페이지 렌더링에서 볼 수 있듯이, 간단한 UI도 여러 조각으로 나뉘어 각기 다른 HTTP 요청을 필요로 하며, 이는 페이지 렌더링에 수 초가 걸리게 합니다.
-
설계상의 결함: 저자는 이러한 문제가 아키텍트의 무능이 아니라 SPA 설계 자체의 근본적인 결함에서 비롯된다고 주장합니다. SPA는 본질적으로 백엔드에서 검색 가능한 조각들로 구성되어 있기 때문에 여러 HTTP 왕복 통신이 필수적입니다.
-
애플리케이션 계층의 병목: HTTP/2가 요청을 멀티플렉싱하더라도, UI는 JSON이 순서대로 도착하기를 기다려야 하는 애플리케이션 계층에서의 ‘head-of-line blocking’ 현상이 발생합니다. 더욱이, 하나의 요청이 다음 요청에 필요한 권한, 기능 플래그, 또는 엔티티 식별자를 노출하는 경우가 많아 병렬 호출이 워터폴(waterfall) 방식으로 변질됩니다.
-
캐싱의 한계: 수십 개의 엔드포인트가 각기 다른 TTL(Time To Live)을 가지므로 완전한 캐시 적중은 드물며, 부분 적중이라도 브라우저가 런타임에 페이지를 조립하고 조정해야 하는 부담이 있습니다. 이 과정에서 브라우저는 레이아웃 안정화, 로딩 인디케이터, 부분 실패 처리 등 복잡한 작업을 수행해야만 의미 있는 콘텐츠를 사용자에게 보여줄 수 있습니다.
대안: 서버 렌더링 방식의 우수성
-
Stack Overflow 사례: 저자는 Stack Overflow를 SPA가 아닌 서버 렌더링 방식의 성공적인 예시로 제시합니다. 이 웹사이트는 전체 HTML 페이지를 서버에서 렌더링하여 50ms 미만의 단일 요청으로 제공하며, 선택적으로 클라이언트 측 JS 컴포넌트를 사용하지만 서버 HTML의 중심 역할을 부정하지 않습니다. 그 결과, Stack Overflow는 현대 웹에서 최고의 사용자 경험 중 하나를 제공한다고 평가됩니다.
-
서버의 역할 재강조: 서버에서 전체 페이지를 렌더링하는 것이 느릴 수 있지만, 캐싱과 같은 기법으로 해결 가능하며, 서버가 데이터와 내비게이션 상태를 담당하므로 캐싱 전략을 효과적으로 구현할 수 있습니다. 저자는 Roy Fielding의 원칙을 따라 페이지를 새로고침하는 방식이 Gmail과 같은 대규모 SPA보다 더 나은 UX를 제공할 것이라고 강조합니다.