Por que é tão ruim compartilhar uma interface entre servidor e cliente?


12

Eu estava lendo a documentação do Spring Cloud Netflix quando descobri uma maneira de compartilhar uma interface entre um servidor HTTP e seu cliente. Eles usam este exemplo para microsserviços, embora não haja motivo para que ele não possa se estender à comunicação HTTP genérica:

// 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 {
}

Isso define uma interface que é usada como servidor (o Spring o @RestControllertransforma em servidor HTTP) e como cliente (o Feign o @FeignClientconfigura para uso do cliente HTTP). As implementações de classe de servidor e cliente podem ser usadas em projetos separados, mas ainda usam a mesma interface para garantir que os tipos correspondam.

No entanto, abaixo do exemplo, eles colocam a seguinte ressalva:

Nota: geralmente não é aconselhável compartilhar uma interface entre um servidor e um cliente. Ele apresenta acoplamento rígido e, na verdade, também não funciona com o Spring MVC em sua forma atual (o mapeamento de parâmetros do método não é herdado).

OK, então não está bem integrado no momento ... mas essa parte vem após o aviso contra o compartilhamento de código e a introdução do acoplamento entre o servidor e o cliente, o que eles acham mais importante. Por que eles acham que é uma má idéia compartilhar uma interface dessa maneira?

Sem ele, você perde a capacidade de garantir que o servidor e o cliente enviem dados uns aos outros que eles possam entender. Você pode adicionar um campo a um, mas não ao outro, e descobrir apenas a incompatibilidade até o tempo de execução. Na minha opinião, não está introduzindo acoplamento, mas apenas revelando o acoplamento que já existe. A necessidade de tornar os servidores completamente independentes é maior do que a necessidade de informar quais tipos de dados eles receberão?


1
O acoplamento existente, em termos de dados / formatação manipulados por clientes / servidores, é determinado pelo protocolo - uma parte da documentação que pode ser usada como convenção . O acoplamento introduzido pelo compartilhamento de uma interface é um acoplamento em tempo de compilação - considere o que acontece quando a interface é alterada (de maneira incompatível com versões anteriores, por exemplo), mas o código do cliente / servidor que usa essa interface é implantado em momentos diferentes. Esse acoplamento no tempo de implantação pode ser mais difícil de gerenciar, especialmente na escala da Netflix.
Castaglia

1
Tenho certeza de que não estou operando na escala da Netflix :) mas se as interfaces forem alteradas de maneira incompatível com versões anteriores , isso não mudará apenas o erro de ser encontrado em tempo de compilação para ser encontrado em tempo de execução? Eles consideram aceitável deixar algumas chamadas de função falharem enquanto atualizam lentamente todos os servidores?
Ben S

1
Possivelmente; depende do código do cliente. Considere também o outro caso: os servidores são atualizados em primeiro lugar, e os clientes agora têm de lidar com (inesperadamente) chamadas falhando ...
Castaglia

1
Apenas curioso, ao compartilhar essa interface, limita de quais idiomas / pilha você pode criar o cliente?
Jeffo

Sim - é um arquivo Java, então você terá que usar Java. Você pode usar outro idioma da JVM, mas eu não tentei.
Ben S

Respostas:


6

O motivo, conforme declarado nos comentários, é que isso resulta no acoplamento rígido da plataforma do cliente à plataforma do servidor. Aqui, isso significa que seu cliente é obrigado a usar o idioma / plataforma que você está usando no servidor para entender o contrato esperado do seu servidor. Observe que há uma diferença entre compartilhar o mesmo código (um artefato de um idioma / plataforma específico) e concordar com um contrato específico.

Muitos projetos usam documentação para seus contratos. Solicitações e respostas de exemplo em um formato neutro (por exemplo, JSON) sobre protocolos padrão (por exemplo, REST). (Veja os documentos da Stripe API , por exemplo). Como é impraticável escrever um contrato baseado em código para todas as plataformas possíveis de clientes que você queira usar ou permitir. Outros ainda usam ferramentas de gerenciamento de API para definir contratos neutros .

Seu exemplo de adição de um campo é uma preocupação separada - um exemplo de por que é importante a versão dos contratos da API. Permita que os clientes usem a versão para a qual foram projetados. Existe uma nova versão da API incompatível com versões anteriores ao lado da antiga. O cliente da versão antiga continua trabalhando até que sua equipe consiga atualizá-la ou até você desativar a versão antiga (após um período de descontinuação / migração). Consulte Mudança Paralela .

Seguir o aviso (implícito no aviso) ajuda o cliente e o servidor a evoluir de maneiras e ritmos que fazem sentido para cada um. Se você puder razoavelmente garantir que seu servidor e cliente sempre compartilhem o mesmo idioma / plataforma E evoluam no mesmo ritmo, use um artefato de código específico do idioma e da plataforma, pois seu contrato provavelmente será válido. No entanto, isso provavelmente não é uma expectativa razoável, especialmente para projetos direcionados ao Netflix OSS (algo especificamente voltado para escalabilidade e desempenho da nuvem, com toda essa complexidade necessária).


2
É realmente esperado que o cliente use a interface? Eu sempre vi essas construções como uma maneira de facilitar a escrita de um cliente. Afinal, você ainda pode escrever um cliente REST em um idioma diferente.
Jimmy T.

1
Exatamente, api continuará a existir, com suas definições de rotas, previne nada a criação de um cliente em outro idioma, mas contanto que você usa java poderia usar a interface
Leonardo Villela
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.