Mas também traz seu próprio conjunto de desafios. Como um conjunto de serviços pode evoluir juntos de uma forma que não quebre o sistema?
À medida que nossas vidas se tornam mais distribuídas, também tem o software em que confiamos. O que vemos como uma única interface de usuário é tipicamente alimentado por uma série de serviços conectados, cada um com um trabalho específico.
Considere a Netflix. Na página inicial, vemos uma mistura de conteúdo: programas assistidos anteriormente, novos títulos populares, gerenciamento de contas e muito mais.
Mas essa tela não é gerada pela netflix.exe rodando em um PC em algum lugar. A partir de 2017, foi alimentado por mais de 700 serviços individuais. Isso significa que a tela inicial é realmente apenas uma agregação de centenas de microsserviços trabalhando juntos. Um serviço para gerenciar recursos da conta, outro para fazer recomendações, e assim por diante.
A mudança para arquiteturas distribuídas traz muitos benefícios: testes mais fáceis, unidades implantáveis menores, desacoplamento mais frouxo, superfícies de falha menores, para citar alguns. Mas também traz seu próprio conjunto de desafios.
Uma delas é manter a retrocompatibilidade entre os componentes. Em outras palavras, como um conjunto de serviços pode evoluir juntos de uma forma que não quebre o sistema? Os serviços só podem funcionar juntos se todos concordarem com vários contratos: como trocar dados e como é o formato dos dados. Quebrar até mesmo um único contrato pode causar estragos no seu sistema.
Mas como desenvolvedores, sabemos que a mudança é a única constante. A tecnologia e as necessidades de negócios inevitavelmente mudam com o tempo, assim como nossos serviços. Isso pode acontecer de várias maneiras: APIs web, mensagens como JMS ou Kafka, e até mesmo em lojas de dados.
Abaixo, veremos algumas práticas recomendadas para a construção de sistemas distribuídos que nos permitem modificar serviços e interfaces de forma a facilitar a atualização.
Web APIs
As APIs web RESTful são uma das principais formas pelas quais os sistemas distribuídos se comunicam. Estes são apenas um modelo básico cliente-servidor: o Serviço A (o cliente) envia uma solicitação para o serviço B (o servidor). O servidor faz algum trabalho e envia de volta uma resposta indicando sucesso ou falha.
Com o tempo, nossas APIs web podem precisar mudar. Seja por mudança de prioridades de negócios ou novas estratégias, devemos aceitar desde o primeiro dia que nossas APIs provavelmente serão modificadas.
Vamos ver algumas maneiras de tornar nossas APIs web retrocompatíveis.
O princípio da robustez
Para criar APIs web fáceis de evoluir, siga o princípio da robustez,resumido como “Seja conservador no que você faz, seja liberal no que você aceita”.
No contexto das APIs web, esse princípio pode ser aplicado de várias maneiras:
Cada ponto final de API deve ter um objetivo pequeno e específico que siga apenas uma das operações crud. Os clientes devem ser responsáveis por agregar várias chamadas conforme necessário.
Os servidores devem comunicar os formatos de mensagens e esquemas esperados e aderir a eles.
Campos novos ou desconhecidos em corpos de mensagens não devem causar erros nas APIs, eles devem apenas ser ignorados.
Versão
A versão de uma API nos permite suportar funcionalidades diferentes para o mesmo recurso.
Por exemplo, considere um aplicativo de blog que ofereça uma API para gerenciar seus dados principais, como usuários, posts em blogs, categorias, etc. Digamos que a primeira iteração tenha um ponto final que cria um usuário com os seguintes dados: nome, e-mail e uma senha. Seis meses depois, decidimos que cada conta agora deve incluir um papel (administrador, editor, autor, etc). O que devemos fazer com a API existente?
Temos essencialmente duas opções:
Atualize a API do usuário para exigir uma função a cada solicitação.
Suporte simultaneamente as APIs antigas e novas do usuário.
Com a opção 1, atualizamos o código e qualquer solicitação que não inclua o novo parâmetro é rejeitada como uma solicitação ruim. Isso é fácil de implementar, mas também quebra os usuários de API existentes.
Com a opção 2, implementamos a nova API e também atualizamos a API original para fornecer algum padrão razoável para o novo parâmetro de função. Embora isso seja definitivamente mais trabalho para nós, não quebramos nenhum usuário de API existente.
A próxima pergunta é como fazemos a versão de uma API? Este debate se arrasta há muitos anos, e não há uma única resposta certa. Muito dependerá da sua pilha de tecnologia, mas, de um modo geral, existem três maneiras primárias de implementar a versão da API:
Url
Esta é a maneira mais fácil e comum e pode ser alcançada usando o caminho:
POST /v2/blog/users
Ou usando parâmetros de consulta:
POST /blog/users?v=2
UrLs são convenientes porque são uma parte necessária de cada pedido, então seus consumidores têm que lidar com isso. A maioria das estruturas registra URLs a cada solicitação, por isso é fácil rastrear quais consumidores estão usando quais versões.
Cabeçalhos
Você pode fazer isso com um nome de cabeçalho personalizado que seus serviços entendem:
API-Version: 2
Ou podemos sequestrar o cabeçalho ‘Aceitar’ para incluir extensões personalizadas:
Accept: application/vnd.mycompany.v2+json
O uso de cabeçalhos para versionação está mais alinhado com as práticas RESTful. Afinal, a URL deve representar o recurso, não uma versão dele. Além disso, os cabeçalhos já são ótimos em passar o que é essencialmente metadados entre clientes e servidores, por isso adicionar na versão parece um bom ajuste.
Por outro lado, os cabeçalhos são complicados de trabalhar em alguns quadros, mais difíceis de testar e não são viáveis de fazer login para cada solicitação. Alguns proxies da internet podem remover cabeçalhos desconhecidos, o que significa que perderíamos nosso cabeçalho personalizado antes que ele chegue ao serviço.
Corpo de mensagens
Podemos embrulhar o corpo da mensagem com alguns metadados que inclue
.png)
.png)
.png)
.png)