HTML-우선 접근으로 공공 성격의 서비스 신청 흐름을 재구성해 접근성, 복원력, 사용 완료율을 크게 개선한 사례.
Jun 10, 2026
이것은 HTML-우선으로 구축해 한 회사의 사용자 수를 말 그대로 하룻밤 사이에 두 배로 만든 이야기다.
내 고객은 한 유틸리티 회사였고, 큰 문제가 있었다. 고객이 그들의 서비스를 신청하려면 웹사이트의 오래된 ASP 폼을 사용하거나, 수동 절차를 따라야 했다. 물론 수동 절차는 회사에 더 비쌌다. 여기에 큰 압박까지 더해졌는데, 이 회사는 규제된 독점 사업자였고 고객 만족도가 96% 아래로 떨어지면(내 기억이 맞다면) 수백만 파운드의 벌금으로 이어질 수 있었다.
이 문제를 해결하려는 이전의 실패한 시도가 두 번 있었고, 둘 다 비용이 매우 많이 들었다. 가장 최근 시도에서는 다른 나라의 계약업체들이 React 앱을 만들었다. 그 React 앱은 고객 불만 때문에 철수되기 전까지 온라인에 올라와 있던 기간이 3일뿐이었다. 나는 그것을 한 번 보고 곧바로 상사에게 “우리는 이걸 맡을 수 없습니다.”라고 말했다. 로딩 스피너와 전역 javascript 상태가 뒤엉킨 난장판이었다. 접근성도 없었다. 이미지 업로드는 폼의 핵심 요소였는데, 이미지를(다른 모든 폼 데이터와 함께) 5mb 제한이 있는 localstorage에 저장하려고 시도하고 있었다!
나는 매우 대담한 결정을 내려 Astro를 사용해 사이트의 새 버전을 만들었다. 그것은 HTML-우선이었다. Javascript는 웹 컴포넌트 안에서 존재했지만, 그것 없이도 완벽하게 동작하는 웹사이트를 점진적으로 향상시키는 역할만 했다.
내 논리는 다음과 같았다:
나는 Terence Eden의 이 일화에 큰 감명을 받았다:
몇 해 전 나는 런던의 한 주거 수당 사무소에서 정책 연구를 하고 있었다. 이런 곳들은 하나같이 전혀 사랑스럽지 않다. 벽에는 가정폭력에서 도망치는 사람들을 위한 도움이 되는 서비스를 안내하는 포스터가 붙어 있어 그나마 조금 밝아 보인다. 출입구의 보안요원들은 들어오는 누구에게나 조심스레 무심하다. 공기에는 파트너들 사이의 긴장된 대화가 가득하고, 그 소리는 소리 지르는 아이들의 소음에 묻힌다.
가운데에는 한 젊은 여성이 딱딱한 플라스틱 의자에 앉아 있다. 그녀 주변에는 세간살이가 들어 있는 캔버스 가방들이 놓여 있다. 지금 그녀가 정서적으로 좋은 상태에 있어 보이진 않는다. 그녀의 손에 꼭 쥐어져 있는 것은 게임기 하나, PlayStation Portable이다. 그녀는 그것을 뚫어지게 바라보며 Candy Crush로 세상을 차단하고 있다.
아니, 적어도 나는 그렇게 생각했다.
그녀의 뒤를 지나가며 나는 그녀의 게임기 화면을 힐끗 보았고, 그녀가 보고 있는 화면을 알아봤다. 그녀는 무료 WiFi에 연결해 GOV.UK의 Housing Benefit 페이지를 보고 있었다. 과일을 자르고 있는 것이 아니라, 지식으로 스스로를 무장하고 있었던 것이다.
PSP의 웹 브라우저는 좋게 말해도 형편없다. 느리고, 자주 메모리가 바닥나며, 한 번에 탭을 3개밖에 열지 못한다.
하지만 GOV.UK 페이지는 단순한 HTML로 작성되어 있다. 가볍게 설계되어 있어서 형편없는 브라우저에서도 동작한다. 반드시 그래야 한다. 이것은 모두를 위한 것이기 때문이다.
여기서 내가 도출한 몇 가지 요구사항은 다음과 같았다:
결국 기본 구성은 폼 위저드의 각 단계가 각각의 페이지가 되도록 하는 것이었다. 사용자가 다음을 클릭하면 폼이 제출된다. 데이터가 API에 의해 유효하다고 판단되면, 브라우저는 다음 단계로 리디렉션된다.
Remix 덕분에 현대에 작게나마 부흥한 오래된 웹 애플리케이션 패턴인 폼 제출과 리디렉션은, 모두가 지나치게 클라이언트 측인 웹 애플리케이션에 익숙해져 있었기 때문에 동료들에게 설명하는 데 시간이 좀 걸렸다. 나는 무겁게 클라이언트 측에서 동작하는 애플리케이션 자체를 반대하는 것이 아니다. 적절한 자리가 있다면 말이다. 하지만 이것은 그저 큰 폼일 뿐이다. 실시간 데이터를 보여주는 것도 아니다. 우리의 사용자는 새로 조성된 주택 단지의 들판 한가운데 서서, Tesco에서 산 10년 된 보급형 Android 폰을 들고 있을 수도 있다. 폼 하나를 렌더링하기도 전에 그들에게 20MB의 javascript를 보내는 것은 터무니없는 일이다.
다음으로 나는 가장 큰 골칫거리 중 하나였던 폼 검증(그리고 폼 및 폼 오류 렌더링)을 다뤘다. 나는 React 검증 라이브러리를 붙잡고 씨름하느라 팀들이 사람-개월 단위의 노력을 낭비하는 모습을 봐 왔다. React 쪽 사람이라면 이것을 비웃을지도 모르겠다. 실력 문제라고 하겠지. 하지만 많은 팀에게는 이것이 현실이다. 매 브라우저에 기본으로 들어 있는 검증 시스템의 형편없는 모조품과 상호작용하고 그것을 유지보수하는 데, 당신 역시 자신이 깨닫는 것보다 더 많은 시간, 그리고 필요 이상으로 훨씬 더 많은 시간을 쓰고 있을 수 있다는 점을 조심스럽게 제안하고 싶다.
그래서 나는 HTML 웹 컴포넌트를 만들었다. 이것들은 기존 HTML을 감싸고 그것에 생명을 불어넣는 단순한 커스텀 요소다. shadow DOM도 없고, javascript에서 HTML을 렌더링하는 일도 없거나 아주 적다. 내가 만든 것은 어떤 HTML 폼이든 감싸고, HTML 검증을 받아들여 현대적으로 보이게 만들었다. HTML 검증 팝업 툴팁이 뜨는 것을 막고, 대신 그 필드와 연결된 aria-describedby 요소에 오류를 배치했다(오늘날에는 대신 aria-errormessage가 권장된다). 사용자가 입력하는 동안 유효한 상태에 도달하면 검증을 지우고, blur와 submit 시점에 다시 검사했다.
폼에 필요한 바로 그 사용자 경험을 1KB도 안 되는 크기로 제공했다. 이것이 실패하면 폼은 브라우저 내장 검증으로 되돌아갔다. 그것마저 실패하면 백엔드 API가 검증을 처리했다. 우리는 사용자의 브라우저가 허용하는 한 최대한 이른 시점에 검증 문제를 알려 주었고, 실패하더라도 언제나 수용 가능한 경험으로 되돌아가게 했다.
그 후 나는 이 웹 컴포넌트의 새 버전을 처음부터 다시 작성했고, 범용 사용을 목표로 했다. 이름은 validation-enhancer다. 나는 이 업계에서 20년 넘게 일해 왔는데, 이것은 내가 지금까지 사용해 본 최고의 폼 검증 라이브러리다. 나는 이것이 매우 자랑스럽다.
코드는 이렇게 단순해서 다루기 쉽다:
<validation-enhancer>
<form>
<label for="my-email">Email</label>
<input type="email" name="my-email" aria-errormessage="my-email-error" required />
<div id="my-email-error"></div>
<button type="submit">Submit</button>
</form>
</validation-enhancer>
결과는 어땠을까? 우리가 출시했을 때 폼을 완료한 사람 수가 두 배가 되었다. 분석 담당자들은 이 사용자들이 대체 어디서 오는지조차 몰랐다. 물론 javascript 기반 분석 패키지는 javascript 실패 때문에 이탈한 사용자를 보지 못한다. 말 그대로 홍수였다! 또 하나는 내가 택한 “백엔드 세션을 유지하고, 사용자 데이터를 절대 잃지 않는다”는 접근이 효과를 발휘했다는 점이다. 한 사례에서는 누군가 시작한 지 한 달 뒤에 폼을 완료했다.
마지막에는 슬픈 후일담이 있었다. 계약 업무의 특성상 나는 다음 일로 옮겨 갔다. 나는 내가 무엇을 만들었는지 후임자에게 설명했고, javascript 없이도 언제나 동작한다고 말했다. 그는 경악하며 “하지만 그러면 우리 일이 훨씬 많아지잖아요.”라고 말했다.
오래된 브라우저를 쓰는 사용자, 네트워크 연결이 좋지 않은 사용자, 보조 기술을 사용하는 사용자를 이탈시키는 것은 용납될 수 없다. 독점 공공 서비스라면 더더욱 그렇다. 수많은 과장과 소음이 우리에게 소프트웨어 산업의 확장기였던 카우보이 같은 서부 개척 시대를 더 끌고 가라고 압박하고 있다. 우리는 그것을 제쳐 두고, 성숙한 산업으로서 스스로를 진지하게 받아들여야 한다. 3G 연결의 PlayStation Portable에서도 동작하는 웹 애플리케이션을 만들어라. 그렇게 하면 모든 사용자에게 동작할 것이고, 30년 후에도 여전히 동작할 것이다.