핵심 정리
호환성이 높은 변경
- 새 optional field 추가
- 기존 field 의미 유지
- unknown member 무시 가능
- enum 확장은 소비자 준비 후 진행
호환성이 낮은 변경
- 기존 field 삭제 또는 rename
- optional field를 required로 변경
- value type 변경
- enum 값의 의미 변경변경 기준
새 field 추가는 가장 안전하지만 소비자가 unknown member를 버틸 때만 안전하다
JSON object는 새 member를 추가하기 쉽습니다. 하지만 소비자가 모르는 field를 오류로 처리하거나, 전체 object를 엄격한 구조로 변환하면서 실패한다면 additive change도 깨지는 변경이 됩니다. 공개 API나 장기 저장 메시지에서는 unknown member를 무시할 수 있는 must-ignore 정책을 설계 초기에 정해 두는 편이 좋습니다.
{
"id": "ord_1",
"status": "paid",
"riskScore": 0.13
}기존 소비자가 id와 status만 읽는다면 riskScore 추가는 안전합니다. 하지만 모든 field 목록을 고정 검증하는 소비자는 실패할 수 있습니다.
required field 추가와 type 변경은 파괴적 변경에 가깝다
새 required field를 추가하면 이전 클라이언트가 보내던 payload가 더 이상 통과하지 않습니다. string이던 field를 number로 바꾸거나, object를 array로 바꾸는 것도 소비자 코드를 깨뜨립니다. 이런 변경은 같은 version 안에서 조용히 진행하기보다 새 endpoint, 새 message type, 명시적 version field로 분리하는 편이 안전합니다.
{
"schemaVersion": 2,
"data": {
"amount": "1200.50",
"currency": "KRW"
}
}version field를 넣는다고 모든 문제가 해결되지는 않습니다. 실제로는 소비자가 어떤 version을 처리할 수 있는지와, 서버가 얼마나 오래 이전 version을 유지할지가 더 중요합니다.
enum 확장은 소비자 코드에서 누락되기 쉽다
enum 값 추가는 새 field 추가보다 위험할 수 있습니다. 소비자가 switch 문에서 모든 값을 exhaustively 처리한다고 가정했거나, unknown enum을 오류로 처리하면 새 값이 들어오는 순간 실패합니다. 상태값은 처음부터 unknown 또는 fallback 경로를 두고, 새 enum을 배포하기 전에 소비자 준비 상태를 확인하는 편이 좋습니다.
변경 판단표
| 변경 | 호환성 판단 |
|---|---|
| optional field 추가 | 보통 안전하지만 unknown member 처리 확인 |
| field 삭제 | 파괴적 변경 |
| field rename | 삭제 + 추가와 같아 파괴적 |
| optional을 required로 변경 | 기존 producer에 파괴적 |
| value type 변경 | 기존 consumer에 파괴적 |
| enum 값 추가 | fallback 없으면 파괴적 |
| field 의미 변경 | 가장 위험한 암묵적 변경 |
주의할 점
JSON 포맷에서 가장 위험한 변경은 문법적으로는 여전히 유효하지만 의미가 바뀌는 변경입니다. 타입과 이름이 같아도 단위, 기준 시각, 상태값 의미가 바뀌면 소비자 코드는 조용히 잘못된 결정을 내릴 수 있습니다.
실패 예시
- amount는 그대로 number지만 단위를 원에서 센트로 바꿈
- 결과: 파서는 통과하지만 소비자 계산이 100배 어긋남
- 대응: 새 field나 새 version으로 분리하고 이전 field 의미를 유지한다참고 링크
2 sources