이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.
- 일관성 선택은 화면 문구, 버튼 상태, 재시도 흐름을 어떻게 바꾸는가?
- 사용자가 stale data, pending, conflict를 납득하려면 API가 무엇을 알려줘야 하는가?
- UX 보상은 정합성을 낮추는 핑계가 아니라 어떤 설계 계약이어야 하는가?
개요
일관성 선택은 백엔드 내부 구현으로 끝나지 않는다. 사용자는 방금 저장한 값이 안 보이면 저장 실패로 느낀다. 상태가 뒤로 가면 시스템을 믿지 못한다. 결과를 알 수 없는데 다시 시도하라는 버튼만 보이면 중복 요청이 생긴다. 따라서 eventual consistency를 선택했다면 UX도 함께 설계해야 한다.
이 문서가 바꾸는 설계 축
| 축 | 바뀌는 내용 |
|---|---|
| 성능 | optimistic UI와 stale read는 빠른 반응을 만들지만 보정 흐름이 필요하다. |
| 정합성 | pending, stale, conflict 상태를 드러내 사용자 오해를 줄인다. |
| 장애 격리 | 일부 화면을 지연/축소해 핵심 쓰기 경로를 보호한다. |
| 운영 복잡도 | UX 문구, API 상태 코드, CS 대응, 지표 해석을 같이 관리해야 한다. |
UX 상태를 나눈다
| 상태 | 의미 | 사용자 표현 |
|---|---|---|
| Confirmed | 원본에 반영 완료 | 저장됨, 결제 완료 |
| Pending | 접수됐지만 확정 전 | 처리 중, 잠시 후 확인 |
| Stale | 오래된 값을 보여줌 | 최신 정보가 아닐 수 있음 |
| Conflict | 사용자의 변경과 다른 변경이 충돌 | 다시 확인 후 저장 |
| Failed | 확실한 실패 | 실패 사유와 재시도 가능 여부 |
| 백엔드가 이 상태를 구분하지 않으면 프론트는 모두 성공이나 실패로 뭉갠다. | ||
| 그 결과 사용자는 불필요하게 새로고침하거나 같은 요청을 반복한다. |
대표 시나리오
프로필 사진 변경을 예로 든다. 이미지 업로드는 성공했지만 썸네일 생성과 CDN 반영은 비동기다.
| 단계 | 상태 | UX |
|---|---|---|
| 원본 업로드 완료 | Confirmed | 새 사진 저장 완료 |
| 썸네일 생성 중 | Pending | 일부 화면은 이전 사진일 수 있음 |
| CDN 반영 지연 | Stale | 곧 반영 예정 |
| 변환 실패 | Failed | 다시 업로드 요청 |
| 이 기능에 강한 일관성을 요구하면 사용자는 썸네일까지 완성될 때까지 기다려야 한다. | ||
eventual을 택하면 저장 응답은 빨라지지만 처리 중 상태와 실패 보정이 필요하다. |
API 계약
응답은 단순 성공보다 상태를 알려줘야 한다.
POST /profile/photo
202 Accepted
{
"uploadId": "up-10",
"status": "PROCESSING",
"confirmedFields": ["original"],
"pendingFields": ["thumbnail", "cdn"],
"retryAfterMillis": 1000
}프론트는 이 응답으로 버튼을 비활성화하거나 진행 상태를 보여줄 수 있다.
200 OK만 주면 사용자는 모든 화면에 즉시 반영됐다고 기대한다.
Optimistic UI
좋아요 버튼은 optimistic UI가 적합할 수 있다. 사용자가 누른 즉시 count를 올리고, 서버 실패 시 되돌린다.
client_count = server_count + 1
server_result = pending
failure => client_count rollback하지만 결제, 재고, 권한 변경에는 위험하다. optimistic UI는 틀려도 되돌릴 수 있는 행동에만 쓴다. 되돌릴 수 없는 행동은 pending이나 명시적 확인이 더 안전하다.
Stale 표시
stale data를 숨기지 말아야 하는 화면이 있다. 관리자 통계, 재고 대시보드, 정산 화면은 freshness가 의사결정에 직접 영향을 준다.
GET /admin/inventory-summary
200 OK
{
"dataFreshness": "2026-07-01T10:00:00+09:00",
"lagSeconds": 45,
"isRealtime": false
}반면 일반 상품 추천 목록은 freshness를 굳이 노출하지 않아도 된다. 사용자가 이 값으로 중요한 결정을 하는지에 따라 표시 수준을 정한다.
Conflict UX
동시 수정이 가능한 기능은 conflict를 제품 흐름으로 다뤄야 한다.
409 Conflict
{
"code": "VERSION_CONFLICT",
"message": "다른 기기에서 먼저 수정된 내용이 있습니다.",
"serverVersion": 18
}문서 편집, 주소 변경, 관리자 설정은 conflict를 숨기면 마지막 저장이 이전 변경을 덮는다. 사용자에게 비교 화면을 줄지, 서버 값을 우선할지, client 값을 다시 제출하게 할지 정한다.
버튼과 재시도 정책
일관성 상태는 버튼 동작을 바꾼다.
| 상태 | 버튼 정책 |
|---|---|
| Pending | 같은 요청 재전송 방지, 상태 조회 버튼 제공 |
| Unknown | 재결제 버튼 대신 결과 확인 버튼 제공 |
| Stale | 새로고침 또는 최신화 시도 |
| Conflict | 다시 불러오기, 병합, 덮어쓰기 선택 |
| Retryable Failure | 제한된 재시도와 안내 |
| 결제 unknown 상태에서 “다시 결제” 버튼을 바로 노출하면 중복 결제가 생긴다. | |
| UX는 정합성 보호 장치의 일부다. |
화면별 일관성 예시
| 화면 | 일관성 요구 | 허용 UX |
|---|---|---|
| 주문 완료 | 강함 | 확정 또는 pending 확인 |
| 주문 목록 | 중간 | 몇 초 지연 안내 |
| 좋아요 | 약함 | optimistic UI |
| 관리자 재고 | 강함 | freshness와 lag 표시 |
| 추천 피드 | 약함 | stale 표시 생략 가능 |
| 문서 편집 | 강함 | conflict 해결 화면 |
| 한 서비스 안에서도 화면마다 요구가 다르다. | ||
| 그래서 backend API는 화면의 기대를 알아야 한다. |
운영 지표
UX까지 포함한 일관성 지표가 필요하다.
| 지표 | 의미 |
|---|---|
| pending_duration_p95 | 사용자가 처리 중을 얼마나 오래 보는지 |
| stale_view_rate | stale 화면 노출 비율 |
| conflict_rate | 동시 수정 충돌 빈도 |
| optimistic_rollback_rate | optimistic UI 되돌림 비율 |
| duplicate_retry_blocked | 중복 요청 차단 횟수 |
| 기술 지표인 replica lag가 낮아도 특정 화면의 stale_view_rate가 높으면 사용자 문제는 남아 있다. |
개인 프로젝트 기준
- eventual consistency를 쓰는 화면에는 pending/stale 문구를 한 줄이라도 둔다.
- 결제나 주문의 unknown 상태에는 중복 요청 방지 버튼 정책을 둔다.
- optimistic UI는 되돌릴 수 있는 행동에만 쓴다.
- conflict 가능성이 있으면 409 응답과 사용자 안내를 만든다.
- 포트폴리오에서는 “UX로 보상”이 아니라 어떤 상태를 어떻게 보여줬는지 설명한다.
기업 운영 기준
- PM, 프론트, 백엔드가 pending/stale/conflict 용어를 같은 의미로 쓴다.
- CS가 사용자 문의를 처리할 수 있게 상태 코드와 문구를 문서화한다.
- pending이 오래 지속될 때 자동 보정, 알림, 수동 처리 기준을 둔다.
- UX 상태별 metric과 error budget을 서비스 SLO에 연결한다.
- A/B나 제품 실험이 정합성 경계를 약화시키지 않는지 리뷰한다.
위험 신호
- eventual consistency를 선택했지만 화면은 항상 즉시 반영을 기대한다.
- stale 데이터를 성공 응답으로 숨긴다.
- pending 상태에서 사용자가 같은 요청을 반복할 수 있다.
- conflict를 500이나 일반 실패로 처리한다.
- optimistic UI를 결제, 주문, 권한 변경에 적용한다.
- UX 문구가 기술 상태와 다르게 사용자에게 확정처럼 보인다.
확인 질문
확인 질문
- 확인 질문: Eventual consistency를 UX로 보상한다는 말의 정확한 의미는 무엇인가?
- 답변: 불일치를 숨기는 것이 아니라 pending, stale, conflict 상태를 명확히 보여 주고 안전한 다음 행동을 제공하는 것이다.
- 확인 질문: Optimistic UI를 쓰면 안 되는 대표 영역은 무엇인가?
- 답변: 결제, 주문, 재고, 권한처럼 되돌리기 어렵고 틀린 성공이 치명적인 영역이다.
- 확인 질문: UX 지표가 필요한 이유는 무엇인가?
- 답변: replica lag나 projection lag가 낮아도 사용자가 stale 화면이나 pending 상태를 오래 보면 실제 경험은 나쁠 수 있기 때문이다.