Eu já falei sobre esse assunto antes aqui no blog, em outros artigos, sendo que o principal deles e que recomendo que leia na sequência é o Introdução a Arquitetura de Micro Serviços. A ideia do artigo de hoje é explorar mais o que é um microservice e lhe ajudar no entendimento e no desenvolvimento estudando alguns princípios básicos.
O objetivo principal de usar micro serviços (ou microservices) é ajudar o time de engenharia a entregar produtos mais rápido, de maneira mais segura e com qualidade mais alta. Pequenos serviços desacoplados permitem que os times tenham ciclos de desenvolvimento (sprints ou iterações) rápidos e com mínimo impacto ao resto do sistema.
Um micro serviço é uma pequena porção de software que roda de maneira independente, focada em um único e pequeno (daí o nome micro) conjunto de atividades dentro de um conjunto de serviços muito maior, formando uma arquitetura de micro serviços. Resumidamente é uma versão mais enxuta de web services e web APIs que tradicionalmente os desenvolvedores já faziam há anos.
Em uma arquitetura de micro serviços, múltiplos serviços fracamente acoplados (ou seja, com poucas ou nenhuma dependência entre si) trabalham juntos. Cada serviço foca em um único propósito e tem uma alta coesão (congruência, coerência) de comportamentos e dados relacionados. Note que esta última definição inclui três princípios básicos do design de micro serviços, que vamos ver a seguir.
Os três princípios do design de micro serviços
Quando estamos trabalhando em sistemas que usam a arquitetura de micro serviços devemos sempre ter em mente três princípios básicos.
Propósito Único: cada serviço deve focar em um único propósito e fazê-lo bem. Esta é regra é muito semelhante com o Single Responsibility Principle do acrônimo SOLID, muito utilizado em orientação à objetos.
Assim como o SRP do SOLID diz que uma classe Aluno deve se focar apenas em atender às necessidades de um aluno, o princípio do Propósito Único diz que um micro serviço ‘/alunos’ deve se focar apenas em realizar operações sobre alunos. Precisa lidar com questões financeiras do aluno? Crie outro micro serviço para focar nisso. Precisa fazer uma matrícula, onde tem de lidar com o aluno e com questões financeiras? Crie um terceiro micro-serviço que vai chamar os dois anteriores.
Garantir que cada micro serviço tenha um propósito único não é tão fácil e simples, mas é uma das dicas essenciais principalmente quando você está refatorando uma aplicação monolítica em micro serviços.
Baixo Acoplamento: cada serviço não deve saber nada ou muito pouco dos outros serviços. Eles não devem compartilhar bibliotecas de código, ou apenas o que for genérico e essencial para ter o mínimo de código repetido. Eles devem ter suas próprias validações, seus próprios testes unitários e inclusive não precisam compartilhar sequer a mesma tecnologia ou o mesmo mecanismo de persistência.
Isso tudo para que uma mudança em um serviço não exija mudar outros serviços. Ou que um bug inserido no desenvolvimento de um serviço não atinja o código de outros também. Inclusive a comunicação entre serviços deve ser feita através de interfaces públicas e protocolos leves, funcionando em processos separados.
Este também é um princípio herdado da Orientação à Objetos, onde trabalhamos Loose Coupling ou Low Coupling dentro dos design patterns como sendo um objetivo desejável para garantir boas arquiteturas, muito mencionado no clássico Padrões de Arquitetura de Aplicações Corporativas, do Martin Fowler.
Alta Coesão: cada serviço encapsula todos os comportamentos e dados relacionados juntos. Isso garante que se precisarmos construir uma nova feature sobre um mesmo domínio ou propósito, todas as mudanças devem ser localizadas em um único serviço.
Note que o próprio princípio do Propósito ou Responsabilidade Única dá os subsídios necessários para garantir uma alta coesão, outro tema bem forte nos design patterns da orientação à objetos.
No gráfico abaixo, extraído da Internet, temos a relação entre estes três princípios e como eles se interseccionam para gerar a base desejada para a construção de micro serviços que atendem ao padrão deste tipo de arquitetura.
Quando modelamos microservices nós temos que ser disciplinados em seguir ao menos estes três princípios básicos de design. É o único caminho para atingir o potencial pleno de uma arquitetura de microservices. Deixar qualquer um deles de lado fará com que o seu padrão se torne um antipattern ou anti-padrão, algo que vai te levar a resultados ruins, ao invés do que você espera.
Sem um propósito único, por exemplo, cada microservice pode terminar fazendo muitas coisas, crescendo em uma arquitetura de vários serviços monolíticos. Isso fará com que, além de não colher os benefícios completos de uma arquitetura de microservices, você terá um custo operacional alto para manter isso.
Sem um acoplamento baixo, mudanças em um serviço vão afetar outros serviços, lhe impedindo de liberar releases de maneira rápida, frequente e livre de bugs, que é justamente o benefício principal de uma arquitetura dessas. Mais importante ainda, problemas causados por um alto acoplamento podem ser desastrosos como inconsistências de dados ou mesmo perda deles.
E por fim, sem alta coesão, acabamos gerando uma aplicação monolítica distribuída, muito comum no passado e que há décadas sofremos com legados deste tipo onde, apesar de termos muitos serviços, só podemos aplicar novas features em produção se atualizarmos e implantarmos todos eles em produção, muitas vezes em uma ordem específica e ao mesmo tempo. Na minha opinião e de outros engenheiros com ainda mais experiência, isso é pior do que ter uma grande aplicação monolítica porque a complexidade e o custo operacional disso é muito alto.
O que não é um micro serviço?
Muitas vezes fica mais fácil de entender o que algo é quando definimos o que ele não é, certo?
Um micro serviço não é um serviço que tem um número pequeno de linhas de código ou que faz ‘micro tarefas’. Esta confusão vem do próprio nome, mas não é uma regra e nem é o objetivo desta arquitetura. Os serviços devem possuir a complexidade e quantidade de linhas de código necessárias desde que atendam os três princípios anteriormente descritos.
Um micro serviço não é um serviço construído com a tecnologia mais bacana e hipster que o mercado oferece no momento. Embora a arquitetura de micro serviços te permita sim testar novas tecnologias de maneira muito rápida e fácil, não é um objetivo primário desta arquitetura. Está completamente ok usar qualquer tecnologia que atenda aos princípios anteriores e não faz sentido algum refatorar todos seus micro serviços cada vez que uma nova stack aparece no mercado.
Um micro serviço não tem de ser sempre programado do zero. Quando você está iniciando um processo de refatoração de uma aplicação monolítica, é muito comum que você extraia códigos da aplicação original para os micro serviços e não há problema algum nisso, desde que respeite os três princípios.
Então por hoje é isso, espero que tenha gostado e, caso queira saber mais sobre o assunto, recomendo meu curso de Node.js e MongoDB ou o meu livro sobre micro serviços abaixo.
Olá, tudo bem?
O que você achou deste conteúdo? Conte nos comentários.
[…] a gestão das nossas aplicações. Com a popularização de arquiteturas mais modularizadas como microservices e nanoservices (serverless) e de tecnologias que elevaram essa modularização a um nível nunca […]
[…] a gestão das nossas aplicações. Com a popularização de arquiteturas mais modularizadas como microservices e nanoservices (serverless) e de tecnologias que elevaram essa modularização a um nível nunca […]