버전이 지정된 API의 기본 코드베이스를 어떻게 관리합니까?
ReST API에 대한 버전 관리 전략에 대해 읽어 봤는데 그중 어느 것도 기본 코드베이스를 관리하는 방법이 해결되지 않는 것 같습니다.
예를 들어, 단일 필드 대신 개별 forename
및 surname
필드를 반환하도록 고객 리소스를 변경하는 등 API에 많은 주요 변경 사항을 적용한다고 가정 해 보겠습니다 name
. (이 예에서는 관련된 개념을 이해하기 쉽기 때문에 URL 버전 관리 솔루션을 사용하지만 질문은 콘텐츠 협상 또는 사용자 지정 HTTP 헤더에도 동일하게 적용됩니다.)
이제에 엔드 포인트가 http://api.mycompany.com/v1/customers/{id}
있고에 호환되지 않는 다른 엔드 포인트가 http://api.mycompany.com/v2/customers/{id}
있습니다. 우리는 여전히 v1 API에 대한 버그 수정 및 보안 업데이트를 릴리스하고 있지만 새로운 기능 개발은 이제 모두 v2에 초점을 맞추고 있습니다. API 서버에 변경 사항을 작성, 테스트 및 배포하는 방법은 무엇입니까? 적어도 두 가지 해결책을 볼 수 있습니다.
v1 코드베이스에 소스 제어 분기 / 태그를 사용합니다. v1 및 v2는 독립적으로 개발 및 배포되며, 두 버전 모두에 동일한 버그 수정을 적용하는 데 필요한 수정 제어 병합을 사용합니다. 이전 버전을 계속 지원하면서 주요 새 버전을 개발할 때 네이티브 앱의 코드베이스를 관리하는 방법과 유사합니다.
코드베이스 자체가 API 버전을 인식하도록하여 v1 고객 표현과 v2 고객 표현을 모두 포함하는 단일 코드베이스로 끝납니다. 배포 문제 대신 솔루션 아키텍처의 일부로 버전 관리를 처리하세요. 아마도 네임 스페이스와 라우팅의 일부 조합을 사용하여 요청이 올바른 버전에서 처리되는지 확인하세요.
브랜치 모델의 분명한 장점은 이전 API 버전을 삭제하는 것이 사소하다는 것입니다. 적절한 브랜치 / 태그 배포를 중지하면됩니다.하지만 여러 버전을 실행하는 경우 실제로 복잡한 브랜치 구조와 배포 파이프 라인이 될 수 있습니다. "통합 코드베이스"모델은이 문제를 피하지만 더 이상 필요하지 않은 코드베이스에서 더 이상 사용되지 않는 리소스와 엔드 포인트를 제거하기가 훨씬 더 어려워집니다. 간단한 정답이있을 것 같지 않기 때문에 이것이 아마도 주관적이라는 것을 알고 있지만 여러 버전에서 복잡한 API를 유지 관리하는 조직이이 문제를 해결하는 방법을 이해하고 싶습니다.
말씀하신 두 가지 전략을 모두 사용했습니다. 이 두 가지 중에서 두 번째 접근 방식을 선호합니다.이를 지원하는 사용 사례에서 더 간단합니다. 즉, 버전 관리 요구 사항이 간단하다면 더 간단한 소프트웨어 설계를 사용하십시오.
- 적은 수의 변경, 낮은 복잡성 변경 또는 낮은 빈도의 변경 일정
- 나머지 코드베이스와 거의 직교하는 변경 : 공용 API는 코드에서 분기를 "과도하게"(선택한 용어의 정의에 관계없이) 필요없이 나머지 스택과 평화롭게 존재할 수 있습니다.
이 모델을 사용하여 더 이상 사용되지 않는 버전을 제거하는 것이 지나치게 어렵지 않았습니다.
- 좋은 테스트 커버리지는 폐기 된 API 및 관련 지원 코드를 제거하여 회귀가 없음을 보장 함을 의미합니다.
- 좋은 이름 지정 전략 (API 버전 패키지 이름 또는 메서드 이름의 다소 추악한 API 버전)을 통해 관련 코드를 쉽게 찾을 수 있습니다.
- 교차 우려는 더 어렵습니다. 여러 API를 지원하기위한 핵심 백엔드 시스템의 수정은 매우 신중하게 평가되어야합니다. 어느 시점에서 백엔드 버전 관리 비용 (위의 "과도한"에 대한 설명 참조)이 단일 코드베이스의 이점을 능가합니다.
첫 번째 접근 방식은 공존하는 버전 간의 충돌을 줄이는 관점에서 확실히 더 간단하지만 별도의 시스템을 유지 관리하는 오버 헤드가 버전 충돌을 줄이는 이점을 능가하는 경향이 있습니다. 즉, 새로운 공용 API 스택을 세우고 별도의 API 분기에서 반복을 시작하는 것은 매우 간단했습니다. 물론 세대 별 손실은 거의 즉시 시작되었고 분기는 병합, 병합 충돌 해결 및 기타 재미로 변했습니다.
세 번째 접근 방식은 아키텍처 계층에 있습니다. Facade 패턴의 변형을 채택하고 API를 적절한 Facade 인스턴스와 통신하는 공용 버전 계층으로 추상화 한 다음 자체 API 세트를 통해 백엔드와 통신합니다. 귀하의 Facade (이전 프로젝트에서 어댑터를 사용했습니다)는 자체 패키지가되어 독립적이고 테스트 가능하며 백엔드와 서로 독립적으로 프런트 엔드 API를 마이그레이션 할 수 있습니다.
이는 API 버전이 동일한 종류의 리소스를 노출하는 경향이 있지만 전체 이름 / 외명 / 성 예에서와 같이 구조적 표현이 다른 경우에 작동합니다. "내 백엔드 서비스가 공개 API v1에 노출 된 잘못 계산 된 복리를 반환했습니다. 고객은 이미이 잘못된 동작을 패치했습니다. 따라서 업데이트 할 수 없습니다."와 같이 다른 백엔드 계산에 의존하기 시작하면 약간 더 어려워집니다. 백엔드에서 계산하고 v2까지 적용합니다. 따라서 이제이자 계산 코드를 포크해야합니다. " 운 좋게도 이러한 경우는 드물게 발생하는 경향이 있습니다. 실제로 RESTful API의 소비자는 이론적으로 멱 등성 GET
테드 리소스 에 대한 변경 사항이없는 경우에도 버그 간 하위 호환성보다 정확한 리소스 표현을 선호 합니다.
최종 결정을 듣고 싶습니다.
저에게는 두 번째 접근 방식이 더 좋습니다. SOAP 웹 서비스에 사용했으며 REST에도 사용할 계획입니다.
작성할 때 코드베이스는 버전을 인식해야하지만 호환성 레이어를 별도의 레이어로 사용할 수 있습니다. 귀하의 예제에서 코드베이스는 이름과 성을 사용하여 리소스 표현 (JSON 또는 XML)을 생성 할 수 있지만 호환성 계층은 대신 이름 만 갖도록 변경합니다.
코드베이스는 최신 버전, 즉 v3 만 구현해야합니다. 호환성 계층은 최신 버전 v3과 지원되는 버전 (예 : v1 및 v2) 간의 요청 및 응답을 변환해야합니다. 호환성 계층에는 체인으로 연결할 수있는 지원되는 각 버전에 대해 별도의 어댑터가있을 수 있습니다.
예를 들면 :
클라이언트 v1 요청 : v1은 v2에 적응 ---> v2는 v3에 적응 ----> 코드베이스
클라이언트 v2 요청 : v1은 v2에 적응 (건너 뛰기) ---> v2는 v3에 적응 ----> 코드베이스
응답을 위해 어댑터는 단순히 반대 방향으로 작동합니다. Java EE를 사용하는 경우 예를 들어 서블릿 필터 체인을 어댑터 체인으로 사용할 수 있습니다.
하나의 버전을 제거하는 것은 쉽습니다. 해당 어댑터와 테스트 코드를 삭제하십시오.
분기는 나에게 훨씬 더 좋아 보이며 내 경우에는이 접근 방식을 사용했습니다.
예, 이미 언급했듯이 버그 수정을 백 포팅하려면 약간의 노력이 필요하지만 동시에 하나의 소스 기반 (라우팅 및 기타 모든 항목 포함)에서 여러 버전을 지원하려면 최소한 동일한 노력이 필요하여 시스템을 더 많이 만듭니다. 내부에 논리의 다른 분기가있는 복잡하고 괴물입니다 (버전 관리의 어느 시점에서 정의 할 때 case()
코드가 중복되거나 더 나쁜 버전 모듈을 가리키게 될 것입니다 if(version == 2) then...
). 또한 회귀 목적으로 테스트를 분기로 유지해야한다는 사실을 잊지 마십시오.
버전 관리 정책과 관련하여 : 현재 버전에서 최대 -2 개 버전을 유지하고 이전 버전에 대한 지원을 중단하므로 사용자가 이동하도록 동기를 부여합니다.
'developer tip' 카테고리의 다른 글
std :: stou가없는 이유는 무엇입니까? (0) | 2020.09.10 |
---|---|
Android의 C ++에서 Java 메서드 호출 (0) | 2020.09.10 |
Google Colaboratory : GPU에 대한 잘못된 정보 (일부 사용자는 5 % RAM 만 사용 가능) (0) | 2020.09.10 |
전송 인코딩 : gzip 대 콘텐츠 인코딩 : gzip (0) | 2020.09.10 |
엔티티 프레임 워크를 사용하여 ID로 객체를 삭제하는 방법 (0) | 2020.09.09 |