업데이트됨 1개월 전
버전 관리는 API가 약속이기 때문에 존재합니다.
개발자가 여러분의 API와 연동할 때, 그들은 자신의 코드가 계속 작동할 것이라고 믿습니다. 그들은 여러분의 기반 위에 자신의 제품을 쌓아 올리고 있습니다. 그 기반이 흔들리면 그들의 제품도 무너지고—신뢰도 함께 무너집니다.
버전 관리는 그 신뢰를 배신하지 않으면서 발전해 나가는 방법입니다.
무엇이 깨지고 무엇이 깨지지 않는가
모든 변경이 새 버전을 필요로 하는 것은 아닙니다. 그 차이를 이해하면 버전 남발을 막고, 사용자들이 마이그레이션 피로에 시달리지 않도록 할 수 있습니다.
하위 호환성을 깨는 변경은 기존의 기대를 위반합니다:
- 엔드포인트나 필드 제거
- 필드의 타입이나 의미 변경
- 필수 파라미터 추가
- 오류 코드나 응답 구조 변경
하위 호환성을 유지하는 변경은 위반 없이 확장합니다:
- 새 엔드포인트 추가
- 선택적 파라미터 추가
- 응답에 새 필드 추가 (클라이언트는 모르는 필드를 무시해야 합니다)
- 문서화된 동작에 맞게 버그 수정
"개선"과 "하위 호환성 파괴"가 종종 같이 온다는 것을 인식하는 것이 핵심입니다. 잘못 지은 이름의 필드를 고치고 싶으신가요? 하위 호환성을 깨는 변경입니다. 일관성을 위해 응답을 재구조화하고 싶으신가요? 하위 호환성을 깨는 변경입니다. 기존 동작에 영향을 미치는 모든 개선은 선택을 강요합니다: 이것이 깨진 약속의 대가를 치를 만한 가치가 있는가?
버전 관리 전략
URI 버전 관리가 가장 일반적입니다:
버전이 눈에 보이고, 명시적이며, 놓칠 수 없습니다. 개발자들은 모든 URL에서 이것을 확인합니다. 단점이라면 URL이 버전별로 늘어나고, HTTP 캐싱이 각 버전을 완전히 다른 리소스로 취급한다는 것입니다.
헤더 버전 관리는 URL을 깔끔하게 유지합니다:
또는 콘텐츠 협상 방식으로:
이쪽이 더 "RESTful"합니다—HTTP의 내장 메커니즘을 활용하니까요. 하지만 발견하기 어렵습니다. 버전이 헤더 속에 숨어 브라우저 주소 표시줄이나 문서 예제에서는 보이지 않습니다. URL에 버전이 없으면 테스트도 번거로워집니다.
쿼리 파라미터 버전 관리도 있지만 어딘가 어색합니다:
버전은 쿼리 파라미터가 아닙니다—요청하는 대상의 본질적인 속성입니다. 이 방식도 작동하긴 하지만, 실수로 빠뜨리기 쉬워 예기치 않게 어떤 버전으로 기본 설정될 수 있습니다.
버전 관리를 하지 않는 것도 유효한 선택입니다. 일부 API는 절대 하위 호환성을 깨지 않겠다고 약속합니다—오직 부가적이고 하위 호환 가능한 발전만 영원히 이어 나갑니다. GraphQL API가 종종 이 길을 택합니다. 들리는 것보다 훨씬 어렵지만, 그 대신 솔직합니다. 버전 약속을 관리하는 대신, 하나의 약속을 하고 그것을 지킵니다.
대부분의 API는 URI 버전 관리를 선택합니다. 명시적이고, 발견 가능하며, 개발자들이 API를 바라보는 방식과 딱 맞아떨어집니다. 헤더 버전 관리의 이론적 우아함이 URL 속 /v1/이 주는 실용적인 명확성을 넘어서는 경우는 드뭅니다.
버전 생명주기
버전에는 생명주기가 있으며, 이를 잘 관리하는 것이 신뢰받는 API와 외면받는 API의 차이를 만듭니다.
출시: 새 버전이 나옵니다. 무엇이 바뀌었는지, 무엇이 새로 생겼는지, 이전 버전에서 어떻게 전환하는지 문서로 남기세요. 구체적으로—개발자들은 정확히 무엇이 깨지는지 알아야 합니다.
전파: 두 버전이 나란히 운영됩니다. 클라이언트들은 각자의 속도에 맞춰 마이그레이션합니다. 여기서 마이그레이션 가이드가 정말 쓸모 있는지 알게 됩니다.
지원 중단: 이전 버전이 deprecated로 표시됩니다. 종료는 아닙니다—여전히 작동합니다. 하지만 응답에 지원 중단 경고(헤더 또는 메타데이터)가 포함되고, 문서에 경고가 나타나며, 아직 사용하는 개발자들에게 직접 알립니다.
지원 중단 기간은 무척 중요합니다. 공개 API라면 6~12개월이 적당합니다. 기간이 짧으면 안정성을 믿고 로드맵을 짠 개발자들이 분노합니다. 기간이 길면 유지 관리 부담이 곱절이 됩니다.
종료: 이전 버전이 사라집니다. 종료일에 요청은 410 Gone을 반환하거나 새 버전으로 리다이렉트됩니다. 이 시점이면 이전 버전을 여전히 사용하는 모든 사람이 충분한 경고를 받은 상태여야 합니다.
모든 하위 호환성 파괴는 깨진 약속입니다—그리고 약속은 누적됩니다. 충분히 쌓이면, 개발자들은 API를 아예 믿지 않게 됩니다. 그들의 시간을 존중하는 대안을 찾아 떠날 것입니다.
여러 버전 동시 지원
여러 버전을 동시에 운영하는 것은 비용이 큽니다. 모든 버전은 유지 관리해야 할 코드이고, 수정해야 할 버그이고, 적용해야 할 보안 패치입니다.
가장 단순한 방법은 코드 분리입니다: v1 핸들러는 한 곳에, v2 핸들러는 다른 곳에. 경계가 명확하지만 중복이 생깁니다. 공유 로직에서 버그를 고치면, 두 곳 모두에서 고쳐야 합니다.
대안은 공유 코드에 버전별 변환을 추가하는 방법입니다. 핵심 비즈니스 로직은 하나로 유지됩니다. 어댑터나 직렬화기가 데이터를 버전에 맞는 응답 형식으로 변환합니다. 중복은 줄지만 버전 처리 코드가 코드베이스 곳곳에 흩어집니다.
대부분의 API는 그 중간 어딘가에 자리잡습니다: 요청을 버전별 핸들러로 라우팅하고, 비즈니스 로직을 공유하고, 실제로 버전 간에 다른 부분에만 어댑터를 씁니다.
목표는 버전 경계를 명확히 유지하면서, 버전별 코드의 범위를 최소화하는 것입니다.
새 버전을 만들어야 할 때
모든 하위 호환성 파괴가 새 버전을 필요로 하는 것은 아닙니다. 버전에는 비용이 따릅니다—개발자의 마이그레이션 노력, 여러분의 유지 관리 부담, 모두를 위한 복잡성.
하위 호환성을 깨는 변경들은 묶어서 처리하세요. 어차피 v2를 만들고 있다면, 원하던 다른 파괴적 변경들도 함께 담으세요. v1, v2, v3를 짧은 시간 안에 줄줄이 출시하면 마이그레이션 피로만 쌓입니다.
대안도 고려해 보세요. 기존 것을 변경하는 대신 새 엔드포인트를 추가할 수 있을까요? 기능 플래그로 이전 형식과 새 형식을 잠시 함께 지원할 수 있을까요?
영향을 평가하세요. 얼마나 많은 클라이언트가 이를 사용하고 있나요? 마이그레이션이 얼마나 어렵나요? 이 개선이 그 혼란을 감수할 만한 가치가 있나요?
비용을 정당화할 만큼 의미 있는 변경을 위해 메이저 버전을 아껴두세요. 필드 이름 하나 바꾸는 건 아마 아닐 것입니다. 데이터 모델 전체를 재구조화하는 건 아마 그럴 것입니다.
내부 API와 공개 API
내부 API—자신의 애플리케이션에서만 사용하는—는 더 과감하게 버전을 관리할 수 있습니다. 모든 클라이언트를 직접 제어합니다. 마이그레이션을 조율할 수 있습니다. 클라이언트와 서버를 함께 업데이트할 수 있다면 버전 관리 자체가 필요 없을 수도 있습니다.
공개 API는 신중함을 요구합니다. 외부 개발자들이 여러분의 약속 위에 제품을 만들었습니다. 그들에게는 로드맵이 있고, 출시 일정이 있고, 자원의 한계가 있습니다. 그들의 코드를 깨면 돈과 신뢰를 잃게 만드는 것입니다.
API가 더 공개적일수록, 지원 중단 기간을 더 길게, 소통을 더 명확하게, 지원 기간을 더 넉넉하게 가져가야 합니다.
개발자를 존중하는 문서화
버전 문서화는 선택 사항이 아닙니다—개발자들이 여러분의 API에 쏟는 신뢰에 보답하는 방법입니다.
변경 로그는 무엇이 바뀌었는지 정확히 나열합니다: 추가됨, 지원 중단됨, 제거됨, 수정됨. 마케팅 문구가 아닌—기술적 정확성.
마이그레이션 가이드는 이전 버전에서 새 버전으로 가는 길을 보여줍니다. 코드 예제. 자주 빠지는 함정. 개발자들이 묻기 전에 던질 질문들.
버전별 문서화는 개발자들이 자신이 쓰는 버전에 맞는 문서를 볼 수 있게 합니다. 자신의 버전에 있는지도 모를 기능들이 뒤섞인 혼란 대신.
지원 중단 공지는 관련된 모든 곳에 나타납니다: 문서, API 응답(헤더를 통해), 영향 받는 개발자들과의 직접 소통.
흔한 실수들
너무 잦은 버전 업. 6개월 안에 v1, v2, v3는 개발자들을 지치게 합니다. 각 버전은 그들이 원하지도 않은 마이그레이션 작업입니다.
일관성 없는 버전 관리. 같은 API에서 /v1/users와 /api-version-2/posts가 함께 존재하면 혼란을 예고합니다.
너무 짧은 지원 중단 기간. 메이저 버전 종료에 30일 전 통보는 무례합니다. 개발자들에게는 각자의 일정이 있습니다.
마이그레이션 경로 없음. 어떻게 가야 하는지 설명 없이 "v2가 출시됐습니다"라고만 하면 개발자들을 낭떠러지 앞에 세우는 것입니다.
버전 없이 하위 호환성 파괴. v1 동작을 조용히 바꾸는 것은 최악의 깨진 약속입니다—코드가 실패하기 전까지 개발자들이 알아채지도 못하는 약속.
모든 곳에 버전 명시. /v1/api/v1/users/v1/profile은 말이 안 됩니다. API 수준에서 한 번만 지정하세요.
API 버전 관리 자주 묻는 질문
어떤 버전 관리 전략을 써야 하나요?
대부분의 API에는 URI 버전 관리(/v1/users)가 맞습니다. 명시적이고, 발견하기 쉬우며, 개발자들의 기대와 딱 맞아떨어집니다. 헤더 버전 관리는 이론적으로 더 깔끔하지만 실제로는 더 불편합니다—URL, 문서, 브라우저 테스트 어디에서도 버전이 보이지 않습니다.
이전 버전을 얼마나 오래 지원해야 하나요?
공개 API라면 6~12개월의 지원 중단 기간이 일반적입니다. 내부 API는 모든 클라이언트를 직접 제어하므로 더 빠르게 움직일 수 있습니다. 핵심은 개발자들이 자신의 출시 일정을 방해받지 않으면서 마이그레이션을 계획하고 실행할 충분한 시간을 주는 것입니다.
API에 시맨틱 버저닝을 써야 하나요?
전체 형식을 따르지 않더라도 개념은 활용하세요. URL의 메이저 버전(v1, v2)은 하위 호환성이 깨지는 변경을 알립니다. 마이너·패치 버전은 하위 호환이 되므로 투명하게 업데이트할 수 있습니다. URL에 마이너 버전까지 넣는 것(/v1.2/users)은 대부분의 API에 불필요한 복잡성을 더할 뿐입니다.
버전 관리를 완전히 피할 수 있나요?
네, 하위 호환성을 깨는 변경은 절대 하지 않고 오직 부가적인 발전만 하겠다는 약속을 지킬 수 있다면요. 훈련이 필요합니다: 모든 새 기능은 기존 것을 수정하는 게 아니라 확장하는 방향이어야 합니다. GraphQL API가 종종 이 방식을 택합니다. 버전 관리보다 어렵지만, 마이그레이션 부담을 완전히 없앨 수 있습니다.
이 페이지가 도움이 되었나요?