Construindo microsserviços em 2019 e além

A arquitetura de microsserviços está sempre evoluindo. Aprenda as práticas recomendadas modernas para a execução correta.

Sten Pittet Sten Pittet

“Microsserviços” é uma prática organizacional de engenharia de software popular e moderna. O princípio norteador dos microsserviços é construir um aplicativo dividindo os componentes de negócios em serviços pequenos que podem ser implementados e operados de forma independente uns dos outros. A separação de problemas entre serviços é definida como “limites de serviço”.

Os limites de serviço estão intimamente ligados às demandas de negócios e aos limites da hierarquia organizacional. Os serviços individuais podem estar vinculados a equipes, orçamentos e planos de ação separados. Alguns exemplos de limites de serviço podem ser serviços de “processamento de pagamento” e “autenticação de usuário”. Os microsserviços diferem das práticas de desenvolvimento de software legadas nas quais todos os componentes foram agrupados.

Este documento vai fazer referência a uma startup imaginária chamada “Pizzup” para ilustrar a aplicação de microsserviços a uma empresa de software moderna.

Como criar microsserviços

Passo 1: Comece com um monólito

A primeira prática recomendada de microsserviços é que você provavelmente não precisa deles. Se você não tem nenhum usuário para o seu aplicativo, o mais provável é que os requisitos de negócios mudem rapidamente enquanto você está construindo seu MVP. Esse cenário ocorre pela natureza do desenvolvimento de software e ao ciclo de feedback que precisa acontecer enquanto você está identificando os principais recursos de negócios que seu sistema precisa oferecer. Os microsserviços adicionam sobrecarga exponencial e complexidade para gerenciar. Por esta razão, manter todo o código e a lógica dentro de uma única base de código reduz a sobrecarga para novos projetos, pois facilita a movimentação dos limites dos diferentes módulos do seu aplicativo.

Por exemplo, com a Pizzup, a gente pode ter começado com uma ideia muito básica do problema que quer resolver para os clientes: a gente quer que as pessoas consigam encomendar pizza on-line.

Um usuário Pizzup diz: "Como um usuário eu posso encomendar pizza on-line!

À medida que a gente começa a pensar na questão do pedido da pizza, a gente vai começar a identificar as diferentes capacidades necessárias no aplicativo, a fim de atender a essa necessidade. A gente precisa gerenciar uma lista das diferentes pizzas que podem ser feitas, permitir que os clientes escolham uma ou várias pizzas, lidar com o pagamento, agendar a entrega e assim por diante. A gente também pode decidir que deixar os clientes criarem uma conta vai facilitar novos pedidos da próxima vez que usarem o Pizzup e, depois de conversar com os primeiros usuários, descobrir que o rastreamento em tempo real da entrega e suporte para dispositivos móveis com certeza seria uma vantagem em relação à concorrência.

Um gráfico que mostra a diferença entre os usos do usuário final e do administrador para o aplicativo Pizzup.

O que era uma necessidade simples no início logo se transforma em uma lista de recursos que você precisa oferecer.

Os microsserviços funcionam bem quando você tem uma boa compreensão das funções dos diferentes serviços exigidos pelo seu sistema. Eles são muito mais difíceis de lidar se os principais requisitos de um aplicativo ainda estiverem sendo trabalhados. Na verdade, é bastante caro redefinir interações de serviço, APIs e estruturas de dados em microsserviços, pois você pode ter muitas outras partes móveis que precisam ser coordenadas. É por esse motivo que a gente aconselha a manter a simplicidade até que você tenha coletado feedback suficiente do usuário para lhe dar a confiança de que as necessidades básicas de seus clientes são compreendidas e planejadas.

Porém, uma palavra de cautela, já que construir um monólito pode logo levar a um código complicado que vai ser difícil de dividir em pedaços menores. Tente o máximo possível ter módulos claros identificados para que eles possam ser extraídos mais tarde do monólito. Você também pode começar separando a lógica da interface do usuário da Web e verificando se ela interage com seu back-end por meio de uma API RESTful por HTTP. Assim fica mais fácil fazer a transição para microsserviços no futuro quando você começar a mover alguns dos recursos da API para diferentes serviços.

Passo 2: Organize suas equipes da maneira certa

Até agora, parecia que a construção de microsserviços é principalmente um assunto técnico. Você vai precisar dividir uma base de código em vários serviços, implementar os padrões certos para falhar normalmente e se recuperar de problemas de rede, lidar com a consistência dos dados, monitorar a carga de serviço etc. Vai haver um monte de novos conceitos para entender, mas uma coisa que não deve ser ignorada é que vai ser necessário reestruturar a forma como suas equipes são organizadas.

Qualquer organização que projete um sistema (de definição ampla) vai produzir um projeto cuja estrutura é uma cópia da estrutura de comunicação da organização.

- Conway's Law

A Lei de Conway é real e pode ser observada em todos os tipos de equipes, e se uma equipe de software for organizada com uma equipe de back-end, uma equipe de front-end e uma equipe de operações separadas, eles vão acabar entregando monólitos front-end e back-end separados que são jogados sobre a equipe de operações para que eles possam gerenciá-lo na produção.

Este tipo de estrutura não serve para microsserviços, pois cada serviço pode ser visto como seu próprio produto que precisa ser enviado independentemente dos outros. Em vez disso, você deve criar equipes menores que tenham todas as competências necessárias para desenvolver e manter os serviços pelos quais elas estão encarregadas. Werner Vogels, CTO da Amazon, descreveu essa situação com a frase "você a constrói, você a executa". Há grandes benefícios em organizar suas equipes dessa maneira. Em primeiro lugar, seus desenvolvedores vão ter uma compreensão melhor do impacto do código na produção — o que vai ajudar a produzir uma versão melhor e a reduzir o risco de ver problemas lançados aos seus clientes. Em segundo lugar, as implementações vão se tornar naturais para cada equipe, pois vão poder trabalhar juntas em melhorias no código, bem como na automação do pipeline de implementação.

Passo 3: Divida o monólito para construir uma arquitetura de microsserviços

Quando você identificou os limites de seus serviços e quando descobriu como é possível mudar suas equipes para serem mais verticais em termos de competências, você pode começar a dividir seu monólito para criar microsserviços. Aqui estão os pontos-chave para pensar nesse momento.

Mantenha a comunicação entre serviços simples com uma API RESTful

Se você ainda não está usando uma API RESTful, agora seria um bom momento para começar a usar em seu sistema. Como Martin Fowler explica, você quer ter "pontos de extremidade inteligentes e pipes burros". Ou seja: o protocolo de comunicação entre seus serviços deve ser o mais simples possível, apenas responsável pela transmissão (e não pela transformação) de dados. Toda a magia vai acontecer nos próprios pontos de extremidade — eles recebem uma solicitação, processam e emitem uma resposta em troca.

É também aqui que os microsserviços podem ser distinguidos do SOA evitando a complexidade do Barramento de Serviço Enterprise. As arquiteturas de microsserviços se esforçam para manter as coisas o mais simples possível para evitar o acoplamento apertado dos componentes. Em alguns casos, você pode estar usando uma arquitetura orientada a eventos com comunicações assíncronas baseadas em mensagens. Porém, mais uma vez, você deve olhar para serviços básicos de fila de mensagens como RabbitMQ e evitar adicionar complexidade às mensagens transmitidas pela rede.

Divida sua estrutura de dados

É bastante comum ter um único banco de dados para todos os diferentes recursos em um monólito. Quando um usuário acessar seu pedido, você vai olhar direto na tabela do usuário para exibir as informações do cliente, e a mesma tabela pode ser usada para preencher a fatura gerenciada pelo sistema de faturamento. Parece lógico e simples, mas com microsserviços você vai querer que os serviços sejam dissociados — para que as faturas ainda possam ser acessadas mesmo que o sistema de pedidos esteja inativo — e porque permite otimizar ou evoluir a tabela de faturas independente de outras pessoas. Ou seja: cada serviço pode acabar tendo seu próprio armazenamento de dados para persistir os dados de que ele precisa.

É claro que assim se criam novos problemas, pois você vai acabar tendo alguns dados duplicados em diferentes bancos de dados. Nesse caso, você deve procurar consistência eventual e adotar uma arquitetura orientada a eventos para ajudar a sincronizar dados em vários serviços. Por exemplo, seus serviços de rastreamento de faturamento e entrega podem estar ouvindo eventos emitidos pelo serviço de conta quando um cliente atualiza suas informações pessoais. Após a recepção do evento, esses serviços vão atualizar seu armazenamento de dados de acordo. Essa arquitetura orientada por eventos permite que a lógica do serviço de conta seja mantida simples, pois não precisa conhecer todos os outros serviços dependentes. Ele simplesmente diz ao sistema o que ele fez e outros serviços ouvem e agem de acordo.

Você também pode optar por manter todas as informações do cliente no serviço de conta e manter apenas uma referência de chave estrangeira em seu serviço de faturamento e entrega. Em seguida, eles interagiriam com o serviço de conta para obter os dados relevantes do cliente quando necessário, em vez de duplicar registros existentes. Não há soluções universais para esses problemas, e você vai ter que analisar cada caso específico para determinar qual é a melhor abordagem.

Crie sua arquitetura de microsserviços para falhas

Vimos como os microsserviços podem lhe proporcionar grandes benefícios em relação a uma arquitetura monolítica. Eles são menores em tamanho e especializados, o que os torna fáceis de entender. Eles são dissociados, o que significa que você pode refatorar um serviço sem temer quebrar os outros componentes do sistema, ou retardar o desenvolvimento das outras equipes. Eles também oferecem mais flexibilidade a seus desenvolvedores, pois eles podem escolher tecnologias diferentes, se necessário, sem serem limitados pelas necessidades de outros serviços.

Em suma, ter uma arquitetura de microsserviços facilita o desenvolvimento e a manutenção de cada capacidade de negócios. Mas as coisas se tornam mais complicadas quando você olha para todos os serviços juntos e como eles precisam interagir para concluir ações. Seu sistema agora está distribuído com vários pontos de falha e você precisa lidar com essa situação. Você precisa levar em conta não apenas os casos em que um serviço não está respondendo, mas também ser capaz de lidar com respostas de rede mais lentas. A recuperação de uma falha também pode ser complicada às vezes, pois você precisa ter certeza de que os serviços que fazem backup e execução não sejam inundados por mensagens pendentes.

À medida que você começa a extrair recursos de seus sistemas monolíticos, faça com que seus projetos sejam criados para falhas desde o início.

Enfatize o monitoramento para facilitar o teste de microsserviços

O teste é outra desvantagem dos microsserviços em comparação com um sistema monolítico. Um aplicativo criado como uma única base de código não precisa de muito para ter um ambiente de teste em execução. Na maioria dos casos, você vai ter que iniciar um servidor de back-end junto com um banco de dados para poder executar seu conjunto de testes.

No mundo dos microsserviços as coisas não são tão fáceis. Quando se trata de testes unitários, ainda vai ser bastante semelhante ao monólito e você não deveria ter mais problemas nesse nível. No entanto, quando se trata de integração e testes de sistema, as coisas vão ser muito mais difíceis. Você pode ter que iniciar vários serviços juntos, ter diferentes armazenamentos de dados em funcionamento, e sua configuração pode precisar incluir filas de mensagens que não seriam necessárias com seu monólito. Nesta situação, fica muito mais caro executar testes funcionais e o número crescente de peças móveis torna muito difícil prever os diferentes tipos de falhas que podem acontecer.

É por esse motivo que você vai precisar colocar uma grande ênfase no monitoramento para poder identificar problemas com antecedência e poder ter a reação adequada. Você vai precisar entender as linhas de base de seus diferentes serviços e ser capaz de reagir não apenas quando eles caírem, mas também quando eles apresentam comportamento inesperado. Uma vantagem de adotar uma arquitetura de microsserviço é que seu sistema deve ser resistente a falhas parciais, portanto, se você começar a ver anomalias no serviço de rastreamento de entrega do aplicativo Pizzup não vai ser tão ruim como se fosse um sistema monolítico. O aplicativo deve ser projetado para que todos os outros serviços apresentem as respostas adequadas e permita que os clientes encomendem pizzas enquanto a gente restaura o rastreamento em tempo real.

Adote a entrega contínua para reduzir o atrito da implementação

O lançamento manual de um sistema monolítico para produção é um esforço tedioso e arriscado, mas possível. É claro que não recomendamos essa abordagem e incentivamos todas as equipes de software a adotar a entrega contínua para todos os tipos de desenvolvimento; porém, no início de um projeto você mesmo pode fazer suas primeiras implementações através da linha de comando.

Essa abordagem não é sustentável quando você tem um número crescente de serviços que precisam ser implementados várias vezes ao dia. Assim, como parte de sua transição para microsserviços, é fundamental que você adote a entrega contínua para reduzir os riscos de falha de lançamento, além de garantir que sua equipe esteja focada na criação e execução do aplicativo, em vez de ficar preso na implementação dele. Com a prática da entrega contínua seu serviço vai passar nos testes de aceitação antes de ir para a produção — é claro que os bugs vão ocorrer, mas ao longo do tempo você vai construir um conjunto de testes robusto que deve aumentar a confiança de sua equipe na qualidade das versões.

Executar microsserviços não é um sprint

Os microsserviços estão se tornando rápido uma prática popular e de adoção ampla no setor. Para projetos complexos, eles oferecem uma maior flexibilidade na forma como você pode criar e implementar software. Eles também ajudam a identificar e formalizar os componentes de negócios de seu sistema, o que é útil quando você tem várias equipes trabalhando no mesmo aplicativo. Mas também há algumas desvantagens claras no gerenciamento de sistemas distribuídos, e a divisão de uma arquitetura monolítica só deve ser feita quando há uma compreensão clara dos limites de serviço.

A construção de microsserviços deve ser vista como uma jornada em vez de um objetivo imediato para uma equipe. Comece aos poucos para entender os requisitos técnicos de um sistema distribuído, como falhar normalmente e escalar componentes individuais. Então você pode extrair mais e mais serviços à medida que ganha experiência e conhecimento.

A migração para uma arquitetura de Microsserviços não precisa ser realizada em apenas um esforço holístico. Uma estratégia iterativa para fazer a migração sequencial de componentes menores para microsserviços é uma aposta mais segura. Identifique os limites de serviço mais bem definidos dentro de um aplicativo monolítico estabelecido e use iterações para que sejam separados em microsserviços próprios.

Resumo

Para recapitular, os Microsserviços são uma estratégia benéfica tanto para o processo de desenvolvimento de código técnico bruto quanto para a estratégia geral da organização de negócios. Os microsserviços ajudam a organizar equipes em unidades que se concentram no desenvolvimento e na propriedade de funções específicas de negócios. Esse foco granular melhora a comunicação geral e a eficiência dos negócios. Existem compensações para os benefícios dos Microsserviços. É importante que as definições dos limites de serviço estejam claras antes de migrar para uma arquitetura de microsserviços. A arquitetura de microsserviços ainda é bastante jovem, mas é uma maneira promissora de desenvolver aplicativos e com certeza vale a pena examinar. Basta lembrar que ela pode não ser (ainda) um bom ajuste para sua equipe.