# URL은 상태 컨테이너다

> Clean Markdown view of GeekNews topic #24100. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=24100](https://news.hada.io/topic?id=24100)
- GeekNews Markdown: [https://news.hada.io/topic/24100.md](https://news.hada.io/topic/24100.md)
- Type: GN+
- Author: [neo](https://news.hada.io/@neo)
- Published: 2025-11-03T09:44:09+09:00
- Updated: 2025-11-03T09:44:09+09:00
- Original source: [alfy.blog](https://alfy.blog/2025/10/31/your-url-is-your-state.html)
- Points: 37
- Comments: 2

## Summary

URL은 단순한 리소스 주소가 아니라 **애플리케이션의 상태를 직렬화하고 복원하는 컨테이너**로 작동합니다. 검색 필터나 보기 모드처럼 **공유 가능한 상태를 URL에 담는 패턴**은 브라우저 히스토리, 캐싱, 협업 경험을 모두 향상시킵니다. 반대로 민감정보나 일시적 UI 상태를 포함하면 보안과 유지보수 모두에 불리하죠. 결국 URL을 **명시적 계약(Contract)** 으로 바라보는 시각이, 프런트엔드 상태 관리의 복잡도를 줄이고 웹의 본질적인 투명성을 되살리는 길임을 상기시켜 줍니다.

## Topic Body

- **URL 구조**가 단순한 주소를 넘어 **애플리케이션 상태를 저장·복원하는 수단**으로 작동함  
- **PrismJS 다운로드 페이지**처럼, URL 하나로 테마·언어·플러그인 설정이 완전히 재현되는 사례 제시  
- **경로, 쿼리 파라미터, 프래그먼트** 등 각 구성요소가 계층적 탐색·필터링·클라이언트 내비게이션 등 다양한 상태를 표현  
- **검색 필터, 페이지네이션, 보기 모드, 날짜 범위** 등은 URL에 포함하기 적합하며, **민감정보나 일시적 UI 상태**는 부적합  
- 잘 설계된 URL은 **공유성·예측 가능성·캐싱 효율성**을 높이며, 웹 애플리케이션의 **신뢰성과 사용자 경험**을 강화함  

---

### URL의 잠재력
- URL은 단순한 리소스 주소가 아니라 **사용자 인터페이스(UI)** 이자 **상태 컨테이너**로 기능  
  - 공유, 북마크, 브라우저 히스토리, 딥링크 등에서 상태를 자동으로 보존  
  - 1991년부터 웹의 기본 상태 관리 메커니즘으로 작동  
- URL의 각 구성요소는 다른 종류의 상태를 표현  
  - **경로(Path)** : 계층적 리소스 탐색 (`/users/123/posts`)  
  - **쿼리(Query)** : 필터·옵션·설정 (`?theme=dark&lang=en`)  
  - **프래그먼트(Fragment)** : 문서 내 위치나 SPA 라우팅 (`#features`, `#/dashboard`)  
- **Text Fragments** 기능은 페이지 내 특정 텍스트로 직접 연결 가능  

### 쿼리 파라미터 패턴
- **구분자(delimiter)** 로 여러 값을 하나의 키에 담는 방식 (`?tags=frontend,react,hooks`)  
- **중첩 데이터**를 JSON 또는 Base64로 직렬화 (`?config=eyJyaWNrIjoicm9sbCJ9==`)  
- **불리언 플래그**는 키 존재 여부로 표현 (`?mobile`)  
- **배열 표기법(bracket notation)** 은 `tags[]=frontend&tags[]=react` 형태로 다중 값 표현  
  - Node의 `qs`나 Express 미들웨어 등에서 자동 인식되지만 표준화는 되어 있지 않음  
- 핵심은 **일관성 유지**  

### URL을 통한 상태 표현 사례
- **PrismJS**: URL 해시로 테마·언어·플러그인 설정 전체를 저장  
- **GitHub**: `#L108-L136`으로 특정 코드 라인 범위 강조  
- **Google Maps**: 좌표·줌 레벨·지도 유형을 URL에 포함  
- **Figma**: 캔버스 위치·줌·선택 요소 등 작업 맥락을 URL로 공유  
- **전자상거래 사이트**: 필터·정렬·가격 범위를 URL에 포함해 검색 상태 복원  

### 프런트엔드 엔지니어링 패턴
- URL에 포함하기 적합한 상태  
  - 검색어, 필터, 페이지·정렬, 보기 모드, 날짜 범위, 활성 탭, UI 구성, 기능 플래그  
- URL에 부적합한 상태  
  - 비밀번호·토큰 등 민감정보, 임시 UI 상태, 미저장 입력, 대용량 데이터, 고빈도 상태  
- 판단 기준: **다른 사용자가 같은 URL을 클릭했을 때 동일한 상태를 봐야 하는가**

#### JavaScript 구현
- `URLSearchParams` API로 쿼리 파라미터 읽기·쓰기 가능  
- `pushState`로 새 히스토리 항목 추가, `replaceState`로 현재 항목 갱신  
- `popstate` 이벤트로 브라우저 뒤로가기 시 UI 복원  

#### React 구현
- React Router의 `useSearchParams` 훅으로 URL 상태를 간결하게 관리  
  - 파라미터 읽기·갱신 시 자동으로 URL과 UI 동기화  

### URL 상태 관리 모범 사례
- **기본값은 URL에 포함하지 않기** (`?theme=dark`만 유지, 기본값은 코드에서 처리)  
- **디바운싱**으로 입력 중 URL 과도한 갱신 방지 (`lodash.debounce` 활용)  
- **pushState vs replaceState**  
  - `pushState`: 필터 변경·페이지 이동 등 되돌릴 수 있는 상태  
  - `replaceState`: 검색 입력 등 세밀한 수정  

### URL을 계약(Contract)으로 보기
- 잘 설계된 URL은 **애플리케이션과 사용자 간의 명시적 계약** 역할  
  - 공개/비공개, 클라이언트/서버, 공유/세션 상태의 경계를 명확히 함  
- **가독성 높은 URL**은 의도를 설명하고, 사람과 기계 모두 이해 가능  
  - `example.com/products/laptop?color=silver&sort=price` 형태가 의미 전달에 유리  
- **캐싱 효율성** 향상  
  - 동일 URL은 동일 리소스로 간주되어 캐시 적중률 상승  
  - 쿼리 파라미터로 캐시 변형 제어 가능  
- **버전 관리와 실험**  
  - `?v=2`, `?beta=true`, `?experiment=new-ui` 등으로 API 버전·A/B 테스트 구분  

### 피해야 할 안티패턴
- **SPA에서 메모리 내 상태만 유지**해 새로고침 시 상태 손실  
- **민감정보를 URL에 포함** (`?password=secret123`)  
- **불명확한 파라미터명** (`?foo=true&bar=2` 대신 `?mobile=true&page=2`)  
- **복잡한 JSON을 Base64로 인코딩**해 과도하게 긴 URL 생성  
- **URL 길이 제한 초과**(브라우저·서버·CDN 제약 존재)  
- **뒤로가기 버튼 무력화** (`replaceState` 남용 시 발생)  

### 결론
- **좋은 URL은 콘텐츠를 가리키는 것 이상으로, 사용자와 애플리케이션 간의 대화**를 표현  
- URL은 **의도·맥락·공유 가능성**을 담는 가장 오래되고 우아한 상태 관리 수단  
- Redux·MobX·Zustand·Recoil 등 복잡한 상태 관리 도구가 존재하지만,  
  **URL이라는 기본 기능을 잊지 않는 것이 진정한 웹의 강점**임  
- 새로고침 시 상태를 잃는 앱은 웹의 본질적 특성을 놓치고 있음

## Comments



### Comment 45804

- Author: neo
- Created: 2025-11-03T09:44:09+09:00
- Points: 1

###### [Hacker News 의견](https://news.ycombinator.com/item?id=45789474) 
- 코드 리뷰 시 가능한 한 많은 **상태(state)** 를 URL에 저장하려고 함  
  새로고침 후 완전히 다른 위치로 이동하거나, 공유한 URL이 엉뚱한 화면을 보여주는 건 사용자 입장에서 모욕적임  
  이런 방식은 개발 속도를 늦추지만, 팀 내에서 UX 인식이 높아지고 뷰에 얼마나 많은 상태를 담는지 명확히 알 수 있음  
  URL이 일종의 **공개 API** 가 되어 제약이 생긴다는 우려도 있지만, 대부분의 URL은 단기적으로만 사용되므로 큰 문제는 아니라고 생각함  
  필요하다면 로드 시 이전 URL을 새 URL로 **마이그레이션** 하는 코드로 해결 가능함
  - 이 접근법이 마음에 들지만, 브라우저 **히스토리 자동완성** 때문에 원치 않는 상태가 불려오는 경우가 있음  
    경로(path) 대신 **쿼리 파라미터**를 쓰면 좀 더 낫다고 생각함
  - 내가 쓰는 업무용 웹앱은 자체 “뒤로가기” 버튼을 만들어서 브라우저의 뒤로가기가 완전히 깨져 있음  
    사용자 입장에서는 “뒤로가기”라는 단어가 브라우저 버튼과 연결되어 있어서 혼란스러움  
    새로고침으로 상태가 초기화되는 건 덜 짜증남. “새로고침 = 처음부터 다시”라는 인식이 있기 때문임
  - 서버 렌더링 페이지라면 새로고침 시 **스크롤 위치**가 자동으로 복원됨  
    JS로 모든 걸 처리하면 이런 기본 기능들이 미묘하게 깨짐
  - URL 설계는 **UX 디자인의 일부**라고 생각함  
    하지만 지금까지 30명 넘는 UX 디자이너와 일했어도 URL에 대한 가이드를 받은 적이 없음
  - 웹이 발전하면서 **새로고침의 의미**가 상황마다 달라졌음  
    특히 모바일에서는 페이지를 초기 상태로 되돌리기 어려워서 새로고침이 가장 빠른 해결책이 됨  
    무한 스크롤이나 복잡한 필터 UI에서는 URL에 상태가 많을수록 초기화가 더 귀찮아짐  
    이미 UX에 불만이 있는 상황에서 URL까지 정리해야 한다면 그건 사용자에게 이중 스트레스임

- 디지털 리터러시가 높은 사람들조차 **URL과 DNS 이해도**가 낮다고 느낌  
  피싱 위험을 줄이고, URL 파라미터(`?t=_`, `utm_`)의 의미를 이해하며, 공유 전 개인정보를 제거할 수 있어야 함  
  HTTPS 자물쇠가 ‘신뢰’를 의미하지 않는다는 점도 알아야 함
  - 하지만 브라우저가 기본적으로 **URL을 숨기거나 축약**하고, 기업들이 QR 코드나 검색어만 홍보하는 환경이라 교육이 어려움

- URL을 상태 컨테이너로 쓰면 내부 구조가 **노출**되고, 버전 관리가 필요해짐  
  브라우저 간 호환성이나 인증 흐름에서도 문제가 생길 수 있음  
  그래도 명령줄 인자처럼 가능한 많은 상태를 URL에 노출하려고 함  
  다만 이는 의도적 **트레이드오프**로, 무지나 경험 부족 때문은 아님

- 오래된 라이브러리지만 여전히 유용한 [**Rison**](https://github.com/Nanonid/rison)을 추천함  
  JSON을 URL에 깔끔하게 저장할 수 있고, Elastic의 **Kibana**에서도 사용됨  
  예시: [http://example.com/service?query=q:'*',start:10,count:10](http://example.com/service?query=q:'*',start:10,count:10)
  - 이런 걸 찾고 있었음! 예전엔 직접 임시로 만들었는데, 이건 훨씬 **표준적이고 정돈된 방식**처럼 보임

- 시스템이 발전하면 상태 구조도 바뀌므로, URL에 상태를 넣으면 진화가 **제약**됨  
  URL은 기본적으로 **영구 문자열**이기 때문임  
  대신 URL을 일종의 **프로토콜**로 보고, 상태를 인코딩·디코딩하는 방식이 적절하다고 생각함  
  단순한 페이지라면 전체 상태를 URL에 담는 것도 가능함
  - 유지 기간이 긴 콘텐츠(예: 블로그 포스트)는 URL 상태 보존이 유용함  
    하지만 피드처럼 “새로고침 시 최신 상태로 돌아가야 하는가?” 같은 **사용자 기대치**에 따라 달라짐
  - 버전 관리를 도입하면 이런 문제를 완화할 수 있음

- URL 길이 제한은 브라우저·서버·CDN·검색엔진 설정에 따라 다르지만, 보통 **2000자 이하**임  
  이 제한 안에서 얼마나 많은 상태를 담을 수 있을지, 혹은 다른 접근법이 필요할지 고민됨
  - 도메인을 제외한 각 문자는 66가지(대소문자, 숫자, 특수문자 `- . _ ~`)를 쓸 수 있으므로, **정보 밀도**는 꽤 높음

- **draw.io**는 전체 상태를 URL에 저장해 공유할 수 있음  
  다이어그램 데이터가 Base64로 인코딩되어 링크 하나로 완전한 복원이 가능함  
  다만 이것이 ‘state container’ 정의에 부합하는지는 확신이 없음

- 나는 셀프호스팅 앱에서 **hash routing (#/dashboard)** 을 사용함  
  서버 측 URL 재작성(.htaccess 등)이 필요 없어서, 완벽하진 않아도 **배포 환경 제약**을 줄일 수 있음

- 최신 **Microsoft Teams**는 모든 화면이 하나의 URL로 처리되어 **북마크 불가**임  
  특정 팀이나 채널을 바로 열 수 없어서 매우 불편함

- **HATEOAS**는 이름이 별로라서 주목받지 못하지만, 결국 웹의 기본 개념임  
  - 사용자 입장에서는 링크를 따라가고 폼을 제출하는 게 곧 HATEOAS임  
    하지만 서버·클라이언트를 모두 제어하는 환경에서는 **추가 복잡성**만 생김  
    특히 클라이언트가 여전히 엔드포인트 구조를 알아야 한다면 URL을 불투명하게 만들 뿐임  
  - 이 주제는 사실 HATEOAS와 직접 관련이 없음. 둘 다 URL을 쓰긴 하지만, HATEOAS는 **상태 저장**이 아니라 **탐색 구조**에 관한 것임  
  - 농담이지만, 결국 HATEOAS는 “**시리얼화된 포맷(cerealization)** ”이라는 말이 어울림

### Comment 45811

- Author: ndrgrd
- Created: 2025-11-03T14:27:02+09:00
- Points: 4

탭 절전 기능을 애용하는데 URL 고정해서 한 덩어리로 움직이는 웹앱은 절전 들어가면 정보가 날아갑니다.   
  
그런데 또 그런 웹페이지들이 하나같이 무거워서 절전을 안 할 수도 없어요.
