---
type: knowledge
domain: architecture
status: active
last-reviewed: 2026-07-27
---

# 호환성과 계약 진화

> 한 줄 정의
> 계약(API·이벤트·스키마)을 **소비자를 깨지 않고 바꾸는** 판단 기준. 계약의 작성은 [[02_API·데이터 계약]]·[[01_백엔드 설계]], 여기는 그 계약이 **시간이 지나 바뀔 때**의 규칙이다.

## 1. 깨지는 변경과 안 깨지는 변경을 구분한다

| 안 깨진다 (additive) | 깨진다 (breaking) |
|---|---|
| 응답에 필드 추가 | 필드 제거·이름 변경 |
| 선택적 요청 파라미터 추가 | 필수 파라미터 추가 |
| 새 엔드포인트·새 이벤트 타입 | 타입 변경 (string→number) |
| enum 값 추가 (소비자가 unknown 허용 시) | **의미 변경** — 타입은 그대로인데 뜻이 바뀌는 것. 가장 악질: 컴파일도 테스트도 안 잡는다 |

- 소비자는 **관용적으로**(모르는 필드 무시), 생산자는 **보수적으로**(있던 것 유지) — 이 비대칭이 additive 진화를 가능하게 한다.
- 판단이 애매하면 breaking으로 취급한다. "아마 아무도 안 쓸 필드"는 근거가 아니라 희망이다.

## 2. 버저닝 — 기본값은 v1 유지 + additive

- 기본값: **버전 하나를 유지하며 additive로만 진화**한다. URL 버전 분기(v1/v2)는 breaking이 불가피할 때의 최후 수단 — 버전 수만큼 유지보수 대상이 늘어난다.
- breaking이 불가피하면: 새 버전 추가 → 소비자 이전 → 옛 버전 폐기의 3단계이며, 각 단계 사이에 **소비자 이전 확인**이 게이트다.
- 폐기(deprecation)는 선언이 아니라 절차다: 기한 + 마이그레이션 경로 안내 + **사용량 모니터링 — 트래픽 0을 확인한 뒤에만 제거**한다.

## 3. Expand–Contract — 계약 변경의 표준 순서

breaking을 non-breaking의 연쇄로 분해한다:

1. **Expand**: 새 필드·새 형태를 **추가**한다 (옛것과 공존).
2. **Migrate**: 소비자를 새 형태로 옮긴다 — 소비자별 이전 완료를 추적한다.
3. **Contract**: 옛 형태의 사용량 0을 확인하고 제거한다.

각 단계가 독립적으로 배포·롤백 가능해야 한다. 2단계를 건너뛴 Contract가 곧 장애 공지다. 데이터 스키마에 적용한 같은 패턴은 [[마이그레이션·전환 설계]].

## 4. 소비자를 모르면 바꿀 수 없다

- 계약 변경의 전제는 **소비자 목록**이다 — 누가 쓰는지 모르는 계약은 사실상 동결 상태다. 외주·SI에서는 발주사 연동 시스템이 숨은 소비자인 경우가 많다 ([[01_백엔드 설계]] 외부 연동).
- 계약을 문장이 아니라 **계약 테스트**(소비자 주도 계약, CDC)로 잠근다 — 생산자 CI가 소비자의 기대를 검증하면 breaking이 배포 전에 잡힌다. [[아키텍처 스타일 선택]]의 fitness function과 동일 원리.

## 5. 이벤트·스키마의 특수성 — 소비자가 안 보인다

- 이벤트는 발행자가 소비자를 모르는 구조라 breaking의 폭발 반경이 더 크다. **additive-only를 기본 규칙**으로 하고, 스키마 레지스트리가 있으면 호환성 모드(BACKWARD 등)로 강제한다.
- 이벤트에는 스키마 버전을 싣는다 — 소비자가 버전을 보고 분기할 수 있어야 점진 이전이 성립한다.
- 저장된 이벤트·메시지는 코드보다 오래 산다: 옛 스키마를 읽는 능력은 큐가 완전히 소진될 때까지 유지한다.

## 안티패턴

- **조용한 의미 변경** — 필드 타입은 그대로 두고 단위·기준·의미를 바꾸는 것. 반드시 새 필드로 추가한다.
- **미리 만든 v2** — 요구 없는 버전 체계는 추측성 유연성이다 ([[아키텍처 스타일 선택]] 안티패턴).
- **사용량 확인 없는 제거** — "공지했으니 됐다"는 절차의 절반이다. 제거의 근거는 공지가 아니라 트래픽 0.
- **공유 DB로 계약 우회** — 소비자가 생산자의 테이블을 직접 읽으면 스키마 전체가 암묵 계약이 된다 → [[아키텍처 스타일 선택]]의 공유 DB 안티패턴.

## 관련 문서

- [[00_설계 허브]] · [[01_백엔드 설계]] · [[02_API·데이터 계약]] · [[마이그레이션·전환 설계]] · [[분산 신뢰성 패턴]] · [[백엔드 원리]]
