서버와 클라이언트간에 인터페이스를 공유하는 것이 왜 그렇게 나쁜 생각입니까?


12

HTTP 서버와 클라이언트간에 인터페이스를 공유하는 방법에 대해 알게되었을 때 Spring Cloud Netflix 설명서를 읽고있었습니다 . 일반 HTTP 통신으로 확장 할 수없는 이유는 없지만 마이크로 서비스에이 예제를 사용합니다.

// The shared interface, in a common library
public interface UserService {
    @RequestMapping(method = GET, value = "/users/{id}")
    User getUser(@PathVariable long id);
}

// The controller, on the server
@RestController
public class UserResource implements UserService {
}

// The same interface used for the client
@FeignClient("users")
public interface UserClient extends UserService {
}

이것은 서버 (Spring @RestController이 HTTP 서버로 바꾼다)와 클라이언트 (The Feign @FeignClient이 HTTP 클라이언트 사용을 위해 설정한다 )로 사용되는 인터페이스를 정의한다 . 서버 및 클라이언트 클래스 구현은 별도의 프로젝트에서 사용할 수 있지만 동일한 인터페이스를 사용하여 유형이 일치하는지 확인하십시오.

그러나 예제 아래에 다음과 같은 경고가 있습니다.

참고 : 일반적으로 서버와 클라이언트간에 인터페이스를 공유하지 않는 것이 좋습니다. 그것은 긴밀한 결합을 도입하고 실제로 현재 형태로 Spring MVC와 작동하지 않습니다 (메소드 매개 변수 매핑은 상속되지 않습니다).

좋아, 지금은 잘 통합되지 않았지만 ...이 부분은 코드 공유 및 서버와 클라이언트 사이의 커플 링 도입에 대한 경고 이후에 발생 합니다. 더 중요합니다. 왜 이런 식으로 인터페이스를 공유하는 것이 그렇게 나쁜 생각이라고 생각합니까?

그렇지 않으면 서버와 클라이언트가 서로 이해할 수있는 서로 다른 데이터를 보내도록 보장 할 수 없습니다. 한 필드에는 필드를 추가 할 수 있지만 다른 필드에는 추가 할 수 없으며 런타임까지 불일치를 발견 할 수 있습니다. 내 생각에, 그것은 커플 링을 소개하는 것이 아니라 이미 존재하는 커플 링을 드러내는 것입니다. 서버가 어떤 유형의 데이터를 수신하는지 알려주는 것보다 서버를 완전히 독립적으로 만들어야합니까?


1
클라이언트 / 서버가 처리하는 데이터 / 포맷과 관련하여 존재하는 커플 링은 프로토콜 ( 협약 으로 사용할 수있는 문서)에 의해 결정됩니다 . 인터페이스를 공유하여 도입 된 커플 링은 컴파일 타임 커플 링입니다. 예를 들어 인터페이스가 이전 버전과 호환되지 않는 방식으로 변경 될 때 발생하는 상황을 고려하지만 해당 인터페이스를 사용하는 클라이언트 / 서버 코드는 다른 시간에 배포됩니다. 그 배포 시간 커플 링은 특히 넷플 릭스 규모로, 열심히 관리하는 수 있습니다.
Castaglia 2016 년

1
나는 확신 나는 넷플릭스의 규모로 운영하고 있지 않다 있어요 :)하지만 인터페이스가 backward- 변경하는 경우 호환되지 않는 방식으로,이는 대신 런타임에 발견되기 컴파일시에 발견되는 오류를 이동하지 않는 이유는 무엇입니까? 그들은 모든 서버를 천천히 업그레이드하는 동안 몇 가지 함수 호출이 실패하게하는 것이 괜찮다고 생각합니까?
벤 S

1
혹시; 클라이언트 코드에 따라 다릅니다. 다른 경우도 고려하십시오 : 서버 가 먼저 업그레이드되고 클라이언트는 이제 예기치 않은 호출 실패를 처리해야합니다 ...
Castaglia

1
이 인터페이스를 공유함으로써 궁금한 점은 클라이언트를 구축 할 수있는 언어 / 스택을 제한 하는가?
JeffO

예 — Java 파일이므로 Java를 사용해야합니다. 당신은 할 수 있습니다 다른 JVM 언어를 사용할 수 있지만, 나는 그것을 시도하지 않았습니다.
벤 S

답변:


6

의견에 명시된 이유는 클라이언트 플랫폼을 서버 플랫폼에 단단히 연결하기 때문입니다. 이는 클라이언트가 서버의 예상 계약을 이해하기 위해 서버에서 사용중인 언어 / 플랫폼을 사용해야한다는 것을 의미합니다. 동일한 코드 (특정 언어 / 플랫폼의 아티팩트)를 공유하는 것과 특정 계약에 동의하는 것에는 차이가 있습니다.

많은 프로젝트가 대신 계약서에 대한 문서를 사용합니다. 표준 프로토콜 (예 : REST)을 통해 중립 형식 (예 : JSON)으로 요청 및 응답 예 ( 예를 들어 Stripe API 문서를 참조하십시오 ). 사용하거나 허용하려는 모든 가능한 클라이언트 플랫폼에 대해 코드 기반 계약을 작성하는 것은 실용적이지 않기 때문입니다. 또 다른 사람들은 API 관리 도구를 사용하여 중립 계약 을 정의 합니다.

필드를 추가하는 예는 별도의 문제입니다. API 계약을 버전 화하는 것이 중요한 이유의 예입니다. 클라이언트가 설계된 버전을 사용하도록합니다. 이전 버전과 호환되지 않는 새로운 API 버전이 있습니다. 이전 버전의 클라이언트는 팀에서 업데이트를 받거나 이전 버전을 폐기 할 때까지 (사용 중단 / 이전 기간 이후) 계속 작동합니다. 병렬 변경을 참조 하십시오 .

(내재적 조언) 경고를 따르면 클라이언트와 서버가 각각에 적합한 방식과 속도로 발전하는 데 도움이됩니다. 서버와 클라이언트가 항상 동일한 언어 / 플랫폼을 공유하고 동일한 속도로 발전 할 것이라고 합리적으로 보장 할 수 있다면 계약에 따라 언어 및 플랫폼 별 코드 아티팩트를 사용하는 것이 좋습니다. 그러나 이는 특히 Netflix OSS를 대상으로하는 프로젝트 (특히 클라우드 확장 성 및 성능을 위해 특별히 조정 된 모든 것)를 목표로하는 프로젝트에 대한 합리적인 기대는 아닙니다.


2
클라이언트가 실제로 인터페이스를 사용해야합니까? 나는 항상 클라이언트를보다 쉽게 ​​작성할 수있는 방법으로 이러한 구조를 보았습니다. 결국 다른 언어로 REST 클라이언트를 작성할 수 있습니다.
Jimmy T.

1
정확하게, 경로 정의와 함께 api는 여전히 존재하지만, 다른 언어로 클라이언트를 생성하는 것을 막을 수는 없지만, java를 사용하는 한 인터페이스를 사용할 수 있습니다
Leonardo Villela
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.