DevInsight

나중에 다시 보려고, AI로 정리해두는 기술 기록

Frontend
조회 18분 읽기

서버가 다시 화면을 책임지는 순간

React가 나쁘다는 이야기가 아니다. 다만 모든 화면이 SPA일 필요는 없다. Python과 HTMX 조합이 왜 다시 주목받는지, 보일러플레이트 피로와 운영 단순성, 저사양·저대역폭 환경에서의 현실적인 이점을 따라가며 살핀다.

#React#Python#HTMX#Django#FastAPI#Server Rendering#SPA#Web Architecture

브라우저가 모든 화면의 주도권을 쥐기 시작한 뒤로, 웹 개발은 종종 지나치게 많은 장비를 싣고 동네 슈퍼에 가는 일처럼 변했다. 화면 하나를 띄우기 위해 bundler를 세팅하고, client-side routing을 붙이고, state management 전략을 고르고, API contract를 따로 설계하고, hydration 경계를 고민하는 과정이 너무 익숙해져서 오히려 이상함을 느끼지 못할 때가 많다. 그런데 이상한 장면이 반복된다. 정작 그렇게 공들여 만든 화면의 대부분은 복잡한 상호작용보다 조회, 검색, 수정, 승인, 다운로드 같은 업무 흐름에 머문다. 화면은 화려해졌지만 운영은 무거워졌고, 사용자는 더 나아진 경험을 체감하지 못한다.

이 지점에서 Python과 HTMX가 다시 호명되는 이유는 단순한 유행이 아니다. React가 틀렸다는 선언도 아니다. 오히려 반대다. React는 여전히 뛰어난 도구다. 다만 모든 문제를 React 식으로 풀 필요가 없다는 아주 상식적인 문장이 뒤늦게 힘을 얻고 있을 뿐이다. 웹은 한동안 “서버는 JSON을 내놓고, 화면은 브라우저가 만든다”는 방향으로 강하게 기울어 있었다. 지금 벌어지는 변화는 그 반대편으로의 회귀라기보다, 화면 책임을 어디에 둘 때 전체 시스템이 덜 피곤해지는지 다시 따져보는 일에 가깝다.

프런트엔드가 아니라 전달 경로의 문제

SPA가 사랑받은 이유는 분명했다. 복잡한 상호작용, 끊김 없는 전환, 굵직한 상태 공유, 풍부한 컴포넌트 생태계. 문제는 이 장점이 너무 넓게 일반화됐다는 데 있다. 내부 관리자 화면, 백오피스, 사내 운영 도구, B2B 포털, 예약 관리, 재고 조정, 승인 플로우 같은 영역까지 똑같은 방식으로 끌어안기 시작하면서 균형이 무너졌다.

이런 종류의 화면은 대개 “페이지 전체를 앱처럼 운용해야 하는가”보다 “업무 단위를 얼마나 안정적으로 처리할 수 있는가”가 중요하다. 사용자가 원하는 것은 놀라운 transition이 아니라, 검색 조건이 유지되고, 저장이 확실하게 반영되고, 목록이 빨리 뜨고, 장애가 났을 때 원인을 추적하기 쉬운 시스템이다. 그런데 SPA는 여기서 자주 과잉이 된다. 브라우저 쪽 상태와 서버 쪽 상태가 따로 존재하고, API 응답의 shape가 바뀌면 화면 전체가 흔들리고, 권한 로직은 다시 프런트와 백엔드에 중복되며, 서버 로그만 봐서는 사용자가 어떤 문맥에서 실패했는지 파악하기 어렵다.

HTMX가 흥미로운 이유는 이 과잉을 정면으로 건드리기 때문이다. HTML을 다시 데이터 포맷으로 대한다. 서버가 완성된 조각을 렌더링해서 보내고, 브라우저는 그 조각을 필요한 위치에 교체한다. 이 방식은 새롭지 않다. 오히려 오래된 웹의 상식에 가깝다. 그런데 오래된 방식이 낡은 방식은 아니다. 네트워크가 충분히 빠르지 않고, 장비가 충분히 좋지 않고, 팀이 충분히 크지 않은 환경에서는 이 단순함이 아주 강한 무기가 된다.

보일러플레이트 피로가 쌓이는 방식

현장에서 SPA의 피로는 기능보다 주변부에서 먼저 시작된다. 화면을 만들기 전에 먼저 기반을 설치해야 한다. 빌드 설정, lint, format, test runner, env 분리, 배포 파이프라인, error boundary, form library, data fetching library, cache invalidation 규칙, 인증 토큰 처리, CSRF나 CORS 방어선, client와 server의 타입 연결. 각각은 합리적이다. 문제는 작은 화면 하나를 추가할 때도 이 체계 전체의 비용을 함께 지불해야 한다는 점이다.

특히 Python 중심 조직에서 이 비용은 더 선명하게 드러난다. 비즈니스 로직은 Django나 FastAPI 쪽에 있는데, 화면을 만들기 위해 별도 Node 생태계를 또 운영해야 한다. 릴리스는 한 번인데 런타임은 둘이고, 장애는 한 군데서 시작돼도 로그는 둘로 갈라진다. 프런트엔드 개발자가 충분한 팀에서는 감당 가능하지만, 많은 조직은 그렇게 구성되지 않는다. 백엔드 엔지니어가 UI를 손대는 순간 생산성이 급격히 떨어지고, 사소한 화면 변경 하나가 큰 배포 이벤트가 된다.

Python과 HTMX 조합은 이 문제를 정리하는 데 능하다. 서버 템플릿과 비즈니스 로직이 가까이 있고, 폼 제출과 검증, 권한 판단, 데이터 조회가 같은 맥락에서 이어진다. 화면을 바꾸는 코드와 데이터를 바꾸는 코드가 지나치게 멀리 떨어져 있지 않다. “왜 이 버튼을 눌렀는데 이런 결과가 나왔는가”를 추적할 때 브라우저 network tab과 API 스펙 문서를 몇 번이나 왕복하지 않아도 된다. 서버 로그, 템플릿, 핸들러, DB 쿼리 사이의 거리가 짧다.

이 짧은 거리는 개발 속도보다 운영 안정성에서 더 큰 힘을 발휘한다. 작은 팀일수록, 그리고 제품보다 업무 시스템에 가까울수록, 아키텍처의 우아함보다 문제를 빨리 고칠 수 있는 구조가 더 중요해진다.

저사양과 저대역폭에서 드러나는 차이

웹의 평균 성능을 이야기할 때 종종 잊히는 사실이 있다. 모든 사용자가 최신 노트북과 안정적인 와이파이를 쓰지 않는다. 오래된 사무용 PC, 가상 데스크톱, 병원이나 공장 내부망, 모바일 테더링, 품질이 들쭉날쭉한 해외 지사 회선은 생각보다 흔하다. 이런 환경에서 JavaScript 번들의 무게는 곧 체감 속도가 된다.

SPA는 첫 진입 비용을 사용자 장치가 감당해야 한다. 코드를 내려받고, 파싱하고, 실행하고, hydration을 끝낸 뒤에야 화면이 안정된다. 현대 프레임워크들은 이 문제를 줄이기 위해 SSR, streaming, islands, partial hydration 같은 기법을 발전시켜 왔지만, 그만큼 복잡성도 함께 올라갔다. 결국 “빠르게 보이게 만들기 위한 기술”이 늘어날수록 시스템은 더 정교한 관리가 필요해진다.

반대로 HTMX는 페이지 전체를 브라우저 애플리케이션으로 만들지 않는다. 필요한 순간에 필요한 HTML 조각만 가져온다. 사용자는 대개 더 적은 JavaScript를 받는다. 브라우저가 해야 할 일이 줄고, 서버가 이미 잘하던 일을 계속 맡는다. 물론 네트워크 왕복은 늘 수 있다. 하지만 내부 도구나 CRUD 중심 화면에서는 이 왕복이 치명적이지 않은 경우가 많다. 오히려 번들 파싱과 client state 동기화 비용이 사라지는 편이 더 이득일 때가 많다.

특히 검색과 필터링, 페이지네이션, 테이블 일부 갱신 같은 상호작용은 HTML 조각 교체와 아주 잘 맞는다. 사용자가 원하는 것은 애니메이션이 아니라 결과다. 결과를 빨리 보여주고, 브라우저가 버벅이지 않게 유지하는 것이 우선이라면 서버가 다시 화면 책임을 지는 쪽이 현실적이다.

HTML을 데이터로 보는 태도

HTMX의 핵심은 “HTML over the wire”라는 오래된 아이디어를 현대적으로 다듬는 데 있다. JSON은 범용적이고 강력하지만, 화면을 만들기 위한 중간 재료이기도 하다. 클라이언트는 JSON을 받아 다시 DOM으로 조립한다. 이 과정에서 API와 UI는 분리되지만, 동시에 의존성도 이중화된다. 데이터 구조를 유지해야 하고, 렌더링 규칙도 유지해야 한다.

서버가 이미 템플릿 엔진을 통해 같은 정보를 HTML로 안정적으로 렌더링할 수 있다면, 그 결과를 곧바로 보내는 편이 더 직선적이다. 버튼 클릭 하나에 전체 앱 상태를 재계산할 필요가 없다. 필요한 조각만 다시 그리면 된다. 예를 들어 승인 상태를 바꾸는 버튼은 다음처럼 아주 소박한 인터랙션으로 끝난다.

<button hx-post="/orders/42/approve" hx-target="#order-row-42" hx-swap="outerHTML"> 승인 </button>

이 짧은 마크업 뒤에는 서버가 렌더링한 새 행(row)이 온다. 성공 메시지를 어떻게 보여줄지, 버튼을 비활성화할지, 권한이 없을 때 어떤 상태를 그릴지는 서버가 통합된 맥락에서 판단한다. React라면 보통 mutation, optimistic update, error rollback, cache invalidation을 생각하게 되는 문제를 더 작은 계약으로 바꾼다. 이 단순함은 생각보다 큰 심리적 해방감을 준다.

단순함이 언제 함정이 되는가

이쯤에서 경계해야 할 것도 있다. HTMX의 장점은 “모든 화면에 적합하다”는 뜻이 아니다. 실시간 협업, 복잡한 드래그 앤 드롭, 대규모 client-side state, 오프라인 우선 동작, 캔버스 중심 인터페이스, 고도로 인터랙티브한 데이터 시각화처럼 브라우저가 주연이어야 하는 영역에서는 React 계열 접근이 훨씬 자연스럽다. 화면 자체가 애플리케이션인 경우, HTMX는 오히려 우회로가 된다.

또 하나의 함정은 fragment 설계를 너무 가볍게 보는 것이다. HTML 조각을 주고받는 구조는 단순해 보이지만, 어떤 단위로 조각을 나눌지, 어느 이벤트가 어느 영역을 갱신할지, 에러 상태를 어떻게 일관되게 렌더링할지는 여전히 설계의 문제다. 무심코 조각을 남발하면 템플릿 간 결합이 깊어지고, 한 영역 수정이 다른 영역의 swap 동작을 깨뜨릴 수 있다. SPA에서 API contract가 중요하듯, HTMX에서는 fragment contract가 중요하다.

서버 성능도 다시 바라봐야 한다. client rendering은 브라우저 CPU를 쓰지만, server rendering은 서버 CPU를 더 쓴다. 사용자 수가 많아질수록 템플릿 렌더링 비용, 캐시 전략, DB 접근 패턴을 제대로 다뤄야 한다. 특히 테이블 조각 하나를 갱신할 때도 관련 쿼리가 반복된다면, 프런트엔드 복잡성을 줄인 대신 백엔드 부담을 키우는 셈이 된다. 단순한 구조는 느슨한 구조가 아니다. 잘 설계된 단순함은 오히려 서버 쪽 규율을 더 요구한다.

운영자는 어디서 차이를 체감하는가

운영 관점에서 이 조합이 주는 가장 큰 변화는 문제의 위치가 명확해진다는 점이다. SPA에서는 사용자가 “저장 버튼을 눌렀는데 반영이 안 됐다”고 말할 때 원인이 여러 층으로 흩어진다. 버튼 클릭 이벤트가 막혔는지, local state는 바뀌었는데 서버 동기화가 실패했는지, 요청은 갔지만 cache invalidation이 비정상인지, optimistic UI가 실패 후 롤백되지 않았는지, 브라우저 확장 프로그램이 스크립트를 방해했는지 살펴봐야 한다.

서버 렌더링 중심 화면에서는 실패 신호가 비교적 선명하다. 요청이 왔는지, 권한이 맞는지, 검증이 통과했는지, 템플릿이 정상 렌더링됐는지, DB 트랜잭션이 완료됐는지, fragment 응답이 예상한 selector에 꽂혔는지 차례로 좁혀갈 수 있다. 관측 가능성도 단순해진다. access log, application log, SQL trace, 응답 시간 분포만 잘 잡아도 상당수 문제를 설명할 수 있다.

이런 시스템에서는 “프런트엔드 장애”와 “백엔드 장애”의 경계가 덜 날카롭다. 누군가는 이것을 후퇴로 보겠지만, 작은 팀에게는 장점이 된다. 책임이 흐릿해지는 대신, 문제를 끝까지 잡아낼 수 있는 사람이 늘어난다. Python을 주력으로 쓰는 조직에서 HTMX가 자주 거론되는 배경에는 기술적 취향보다 이런 운영의 경제성이 깔려 있다.

다시 태어나는 것은 백엔드가 아니다

흥미로운 대목은 여기서 다시 살아나는 것이 단순히 서버 렌더링 기술이 아니라는 점이다. 실제로는 백엔드 엔지니어의 화면 감각, 템플릿 설계 능력, HTTP semantics에 대한 이해, 폼과 검증을 다루는 감각, 캐시와 권한을 엮는 태도가 함께 돌아온다. 한동안 프런트엔드와 백엔드는 너무 깔끔하게 분리된 역할처럼 보였지만, 많은 업무 시스템에서는 그 분리가 비용을 늘리기도 했다.

Python과 HTMX가 주목받는 흐름은 “백엔드가 다시 다 한다”는 선언이 아니다. 오히려 화면을 위해 지나치게 분절된 책임을 다시 묶는 움직임에 가깝다. 이는 백엔드의 부활이라기보다 웹의 재균형이다. HTML, HTTP, form, redirect, cache-control, server-side validation 같은 오래된 도구들이 다시 중요해지는 순간, 개발자는 프레임워크 문법보다 웹의 기본 동작을 더 많이 이해해야 한다. 아이러니하게도 단순해 보이는 방식이 더 깊은 기본기를 요구한다.

React가 남아야 하는 자리

여기서 중요한 선을 분명히 그어야 한다. React를 밀어내자는 이야기는 대개 논점을 흐린다. 실제 문제는 도구의 우열이 아니라 적용 범위의 오판이다. 복잡한 제품 경험, 풍부한 상호작용, 클라이언트 상태가 중심인 애플리케이션, 여러 화면에서 공유되는 UI 동작이 많은 서비스에는 React가 여전히 강력하다. 잘 설계된 component model과 생태계는 대체하기 어렵다.

다만 “웹 화면”과 “웹 애플리케이션”을 구분하는 감각은 다시 필요하다. 모든 웹 화면이 단일 페이지 앱일 필요는 없다. 반대로 모든 화면이 서버 템플릿으로 충분한 것도 아니다. 팀이 다시 배우는 것은 기술 스택이 아니라 선택의 기준이어야 한다. 어떤 화면은 서버가 책임지는 편이 낫고, 어떤 화면은 브라우저가 책임져야 한다. 중요한 것은 한 가지 철학으로 전체를 덮지 않는 일이다.

이 기준이 서기 시작하면 아키텍처는 훨씬 현실적이 된다. 공개 서비스의 핵심 인터랙션은 React로 유지하되, 사내 운영 도구나 단순 업무 화면은 Django 템플릿과 HTMX로 빠르게 구성할 수 있다. FastAPI가 이미 데이터 처리 계층을 맡고 있다면, Jinja 기반 fragment 렌더링을 붙여 작은 인터페이스를 손쉽게 제공할 수도 있다. 프레임워크의 순수성을 지키는 일보다 시스템 전체의 피로를 줄이는 일이 우선이 된다.

화면이 다시 가벼워질 때

웹 개발의 역사는 진자 운동처럼 보일 때가 있다. 서버에서 시작해 브라우저로 크게 기울었고, 이제 일부 무게가 다시 서버 쪽으로 돌아온다. 하지만 이번 변화는 과거로 되돌아가는 복고가 아니다. 브라우저의 가능성을 충분히 경험한 뒤에야 가능한 재배치다. 무엇을 클라이언트에 둘지, 무엇을 서버에 둘지, 어디서 복잡성을 소비할지 더 영리하게 고르는 단계라고 보는 편이 맞다.

결국 많은 팀이 깨닫는 것은 비슷하다. 사용자는 프레임워크를 사지 않는다. 사용자는 일이 되는 화면을 원한다. 빨리 뜨고, 덜 깨지고, 수정이 쉽고, 운영자가 이해할 수 있는 화면 말이다. 그 요구 앞에서는 최신성과 단순성이 종종 충돌한다. 그리고 의외로 자주, 승자는 단순성 쪽이다.

Python과 HTMX가 다시 거론되는 풍경은 그 사실을 잘 보여준다. 거대한 프런트엔드 체계가 늘 정답인 것은 아니다. HTML을 서버가 다시 책임지기 시작하는 순간, 웹은 덜 화려할 수 있지만 더 명확해진다. 복잡함을 감추기 위해 복잡한 도구를 덧붙이는 대신, 처음부터 덜 복잡한 길을 고르는 감각. 아마 지금 다시 주목받는 것은 특정 라이브러리의 성공이 아니라, 그 감각 자체일 것이다.

댓글

댓글을 읽어오는 중입니다.

같이 읽으면 좋은 글

방금 읽은 주제와 이어지는 글을 골랐습니다.

Frontend 전체 보기

이전 글

구독이 끝나면 작업도 끝나는가: Claude Design 논란으로 다시 보는 AI 작업공간 운영 방식의 선택