기술 제약을 UX로 흡수하는 프론트엔드 설계 전략

기술 제약을 UX로 흡수하는 프론트엔드 설계 전략

다크모드 마이그레이션과 느린 API 케이스가 증명하는 것—제약은 개발 문제가 아니라 설계 문제다

시맨틱 토큰 CSS 변수 다크모드 마이그레이션 API 지연 UX 패싯 검색 Progressive Disclosure 디자인 시스템 프로덕트 사고
광고

'어떻게 고칠 수 없다면, 어떻게 보여줄 것인가.' 프론트엔드 개발자가 자주 맞닥뜨리는 이 질문은 생각보다 깊은 설계 철학을 담고 있다. API가 느리고, 디자인 시스템이 미비하고, 레거시 색상 코드가 수백 곳에 박혀 있을 때—개발자는 종종 기술적 해결을 먼저 찾는다. 하지만 최근 두 가지 실전 경험담은 다른 방향을 가리킨다. 제약 자체를 UX 설계로 흡수할 수 있다는 것.

하드코딩된 색상이 기술 부채가 된 날

Next.js 15 기반의 AI 서비스 Kepion 팀이 dev.to에 공유한 경험은 흔하지만 뼈아픈 이야기다. 다크모드를 먼저 출시한 팀이 라이트모드를 추가하기로 결정한 순간, bg-zinc-900, text-zinc-400 같은 하드코딩된 Tailwind 색상 클래스가 30개 페이지, 34개 파일에 걸쳐 잠복해 있던 문제가 한꺼번에 터졌다. 결과는 예상 가능했다. 라이트 배경 위에 다크 컴포넌트가 떠 있는, '다크모드를 라이트 껍데기에 억지로 끼워 넣은' 화면이었다.

해결책은 기술적으로 복잡하지 않았다. CSS 커스텀 프로퍼티 기반의 시맨틱 토큰으로 전환하는 것. bg-zinc-900 대신 bg-card를, text-zinc-400 대신 text-muted-foreground를 쓰면, .dark 클래스가 <html>에 토글될 때 CSS 변수 하나가 모든 모드를 처리한다. Tailwind의 dark: 접두사를 수백 군데 붙이는 대신, CSS 파일 한 곳에서 테마를 선언하는 구조다. 문제는 이 '당연한 구조'를 처음부터 갖추지 않았다는 것—그리고 그 이유가 단순히 편의였다는 점이다. zinc-900은 눈에 보이고 예측 가능하지만, bg-card는 간접 추상화를 요구한다. 그 작은 인지적 마찰이 기술 부채로 쌓였다.

이 경험에서 건질 수 있는 시사점은 색상 변수 전략 그 이상이다. 시맨틱 토큰은 단순한 코드 컨벤션이 아니라, 변경 가능성을 시스템 안에 내재화하는 설계 의사결정이다. 라이트모드, 다크모드, 혹은 미래의 세 번째 테마—어떤 변화가 오더라도 CSS 변수 선언부만 손대면 된다는 것. 또한 팀은 테마 전환 시 발생하는 50ms 플래시 문제를 <head> 인라인 스크립트로 해결했다. 렌더링 블로킹이 '나쁜 것'이라는 통념을 깨고, 첫 페인트 이전에 .dark 클래스를 설정하는 것이 오히려 사용자 경험을 지킨다는 실용적 판단이었다. 기술 규칙을 맹목적으로 따르지 않고, 사용자 경험이라는 목표에서 역산하는 사고가 돋보이는 지점이다.

느린 API를 '보이지 않게' 만드는 UX 전략

velog에 공유된 케이스는 또 다른 종류의 제약이다. 내부 API 1개에 외부 API 약 20개를 묶어야 하는 페이지에서, 외부 API 응답이 최대 15초씩 걸리는 상황. 응답 시간 자체를 줄일 방법이 없었다. 개발팀이 선택한 방향은 UX 우회책이었다.

핵심 전략은 두 가지다. 첫째, 패싯 검색(Faceted Search) 기반의 필터 우선 흐름. 페이지 진입 시 아무것도 불러오지 않고, 사용자가 필터(브랜드, 가격대, 상태, 사이즈 등)를 선택한 뒤에야 그 조건으로만 조회하는 방식이다. 항공권 검색에서 날짜와 출발지를 먼저 고르게 하고, 호텔 예약에서 지역과 날짜를 먼저 선택하게 하는 것과 같은 원리다. 무한한 결과를 기다리는 대신, 사용자가 스스로 범위를 좁히는 과정이 검색 경험처럼 느껴지도록 설계한 것이다.

둘째, Progressive Disclosure 기반의 대시보드 구조. 전체 데이터를 한 번에 요청하지 않고, 초기 화면에는 핵심 요약 지표(전체 예약처 수, 오늘 예약 건수, 오류 발생 수 등 빠른 집계)만 먼저 노출한다. 사용자가 특정 항목에 문제를 발견했을 때만 상세 로그와 실패 내역을 드릴다운하는 구조다. 탭이 여러 개일 때 처음부터 모든 탭 데이터를 불러오지 않고, 해당 탭을 클릭할 때만 데이터를 로딩하는 지연 로딩도 함께 적용했다.

이 접근법이 흥미로운 이유는 느림을 숨긴 게 아니라, 느릴 필요가 없는 구조로 바꿨다는 점이다. 사용자가 필터를 고르는 동안 API는 아직 호출되지 않는다. 사용자의 인지 시간이 곧 시스템의 준비 시간이 된다. 기술적 병목을 UX 흐름 안에서 자연스럽게 희석시킨 것이다.

두 케이스가 수렴하는 지점

표면적으로 두 사례는 다른 문제처럼 보인다. 하나는 디자인 시스템의 색상 추상화 문제이고, 다른 하나는 성능 병목의 UX 처리 문제다. 하지만 본질에서 두 케이스는 같은 질문을 공유한다. '이 제약을 기술로 해결하려 하기 전에, 설계 레이어에서 흡수할 수 있는가?'

시맨틱 토큰은 '테마 변경'이라는 요구사항 변화를 CSS 변수 선언부가 흡수하게 만든다. 필터 우선 흐름은 '느린 API'라는 인프라 제약을 사용자의 탐색 행동이 흡수하게 만든다. 두 전략 모두 제약을 없애는 것이 아니라, 제약이 사용자 경험에 직접 충돌하지 않도록 설계 구조 안에 버퍼를 만드는 접근이다.

프론트엔드 개발자가 프로덕트 사고를 갖춰야 한다는 말은 종종 추상적으로 들린다. 하지만 이 두 케이스는 그 실체를 명확히 보여준다. 기술적 한계를 마주했을 때 '어떻게 고칠 것인가' 이전에 '사용자 여정의 어느 지점에 이 제약을 배치하면 가장 덜 방해가 되는가'를 먼저 묻는 것. 그 질문이 시맨틱 토큰을 만들고, 패싯 검색을 만들고, Progressive Disclosure를 만든다.

지금 당장 적용할 수 있는 것들

두 경험이 공통으로 강조하는 실행 원칙은 간단하다. 변경 가능성이 있는 것은 처음부터 추상화하라. 색상이든, API 호출 시점이든, 컴포넌트 가시성이든—나중에 바뀔 가능성이 있다면 직접 노출보다 간접 레이어를 먼저 설계하는 것이 장기적으로 훨씬 싸다. Kepion 팀이 bg-zinc-900 대신 bg-card를 처음부터 썼다면 34개 파일을 건드리지 않아도 됐을 것이다.

또 하나는 사용자 행동을 시스템 준비 시간으로 활용하는 설계 패턴의 가능성이다. 스켈레톤 로더, Optimistic UI, 스트리밍 렌더링—이 모든 기법들은 결국 '사용자가 무언가를 하는 동안 시스템이 준비할 시간을 버는' 전략이다. React Server Components와 Partial Prerendering 같은 최신 렌더링 패러다임이 주목받는 이유도 여기에 있다. 빠른 것을 먼저 보여주고, 느린 것은 뒤에서 채우는 구조.

기술 제약은 사라지지 않는다. 외부 API는 여전히 느릴 것이고, 디자인 시스템은 언제나 불완전할 것이다. 중요한 건 그 제약이 사용자에게 도달하기 전에 어느 설계 레이어가 그것을 받아낼 것인가를 미리 결정해두는 일이다. 그것이 프론트엔드 설계가 단순한 구현을 넘어 프로덕트 설계의 영역과 맞닿는 지점이다.

출처

더 많은 AI 트렌드를 Seedora 앱에서 확인하세요