Microsserviços
Tags: beginners, microsservices, development, architecture
Published: 2023-11-17 18:56:00

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y3511ionan2yyqs5qqan.png)

# Sumário

1. Introdução
2. Monolitos, o mundo antes dos microsserviços
3. Monólitos vs Microsserviços
    - Monólitos
    - Microsserviços
4. Quando usar microsserviços?
5. Microsserviços
    - Pontos de atenção
    - Exemplos de microsserviços
6. Continue seus estudos

# Resumo

Este artigo busca oferecer um guia claro e prático sobre microsserviços, explorando não apenas os benefícios e exemplos dessa abordagem, mas também considerações essenciais, ferramentas como Docker e Kubernetes, além de práticas cruciais como mensageria e testes automatizados. Ao compartilhar essas perspectivas, esperamos fornecer uma base sólida para aqueles que buscam entender, implementar e otimizar arquiteturas baseadas em microsserviços em seus projetos de desenvolvimento de software.

# Introdução

No cenário dinâmico e evolutivo da tecnologia, onde a computação em nuvem se firma como uma pedra angular e novas aplicações surgem constantemente, o conhecimento sobre microsserviços torna-se indispensável. Este artigo busca proporcionar uma orientação prática, compartilhando insights que encurtam a curva de aprendizado em um tema crucial para o desenvolvimento de software na era contemporânea.

## Monolitos, o mundo antes dos microsserviços

Um monolito é, sem dúvida, a abordagem mais simples para o desenvolvimento de um projeto de software, caracterizada pela concentração de todas as funcionalidades em um único processo executado no mesmo ambiente. É provável que todo desenvolvedor tenha experiência com projetos desse tipo, seja durante a faculdade ou em cursos, já que representa uma maneira direta de transformar uma ideia em realidade. Nesse contexto arquitetônico, cada serviço da aplicação é desenvolvido e implementado em conjunto com os demais serviços existentes.

- Acoplamento
	- Sistemas monolíticos apresentam alto acoplamento, como vimos nos nossos exemplos, toda e qualquer modificação implica na necessidade de realizar um deploy de toda a aplicação. Esta criticidade no deploy fere inclusive o pensamento de entrega contínua da cultura Devops.
- Escalabilidade limitada
	- Escalar um sistema monolítico é um desafio peculiar, não sendo possível escalar apenas uma parte do sistema, você precisará escalar toda a aplicação, mesmo que apenas um dos seus componentes esteja necessitando deste ajuste. Neste tipo de sistema, escalar significará adicionar recursos como CPU, RAM e armazenamento no servidor, esta escalabilidade tem limite físico e financeiro.
- Manutenção e implementação
	- Dar manutenção em um sistema legado, com um milhão de funcionalidades e relações que você nunca nem viu, ser torna uma grande dor de cabeça. Pequenas modificações podem se tornar pull requests enormes, os testes (se existirem) levarão bem mais do que 10 minutos, e o deploy será crítico e tenso.
- Tecnologia uniforme
	- Não interessa que lidar com arquivos em GO seja muito mais simples, ou que construir uma interface em C# seja mais intuitivo, se o sistema foi construído em JAVA, toda nova funcionalidade também deverá ser escrita em JAVA.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yjzzk6okl0bfcxsswpr4.png)

## Monólitos vs Microsserviços

Ao optarmos pela abordagem de microsserviços em vez da monolítica, a diferença fundamental reside na resiliência do sistema diante de falhas específicas. É importante ressaltar que, embora o erro ainda pudesse ocorrer da mesma forma, o impacto poderia ser significativamente reduzido. Vamos considerar um exemplo prático: suponha que o erro estivesse relacionado ao envio de e-mails. Em um ambiente de microsserviços, a aplicação continuaria funcionando globalmente, permitindo o cadastro e movimentação de mercadorias, mesmo que a funcionalidade de envio de e-mails estivesse comprometida.

Embora esse exemplo possa parecer simplista, ele ilustra a ideia de que, em situações de instabilidade, certas partes do sistema podem ser afetadas, mas outras permaneceriam operacionais. Uma analogia mais concreta pode ser observada em plataformas populares como o Instagram. Durante períodos de instabilidade, os "stories" podem enfrentar problemas, enquanto o feed continua funcionando sem interrupções aparentes.

Essa descentralização de funcionalidades em microsserviços é particularmente benéfica para aplicações críticas, como redes sociais massivamente utilizadas, exemplificadas pelo Instagram e TikTok. Em ambientes de microsserviços, a falha em uma parte específica do sistema não compromete sua totalidade, evitando assim a perda de credibilidade junto aos usuários, mesmo quando algumas funcionalidades estão temporariamente indisponíveis.

## Quando usar microsserviços?

Após lermos os benefícios do uso dessa abordagem, podemos pensar que nunca mais iremos desenvolver um sistema monolítico mas isso é uma péssima ideia. Sim, as vantagens são ótimas mas a complexidade desta abordagem é alta, equipes com pouca experiência terão imensa dificuldade de performar de maneira satisfatória. Uma outra situação delicada é a relação de custo e benefício dessa abordagem que precisa ser discutida, de fato ela resolverá muitos problemas mas será que você já precisa se preocupar com isso?!

> As consequências de nossos atos são sempre tão complexas, tão diversas, que predizer o futuro é uma tarefa realmente difícil. — Alvo Dumbledore

As palavras de Dumbledore são bem certeiras no mundo do desenvolvimento. Não é viável nos preocuparmos com cenários que podem nunca chegar. É com o objetivo de evitar excessos de engenharia, que surge o conceito de “_**MonolithFirst**_”.

Este conceito, defendido por Martin Fowler, vai recomendar que comecemos nosso projeto com um monolito e somente quando for necessário, façamos a mudança para microsserviços. Pode parecer contra intuitivo, afinal queremos desenvolver o melhor e mais moderno sempre, mas precisamos ter o cuidado de entender que o melhor envolve muito mais coisas do que apenas hype.

Ao iniciar nossa aplicação como um monolito, ganharemos velocidade para desenvolver, errar e corrigir. Algo que ouvi essa semana e gostei muito é que desenvolvimento é sobre feedback, quanto mais rápido temos feedback, mais rápido corrigimos e melhoramos nossa aplicação. Quando nossa aplicação estiver robusta, bem escrita, com as regras de negócio bem amarradas, o cliente estiver satisfeito e tivermos a demanda por maior disponibilidade, ou ainda quando estiver inviável manter o sistema, aí sim começaremos a estrangular nosso monolito buscando criar serviços especializados, nossos microsserviços.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/12rajmk0c7eyg1oyzuaf.png)

# Microsserviços

Agora que já entendemos as vantagens e motivações por trás dessa abordagem, podemos nos debruçar sobre o tema principal deste artigo. Microsserviços representam uma abordagem arquitetônica e organizacional no desenvolvimento de software que se fundamenta na descentralização de responsabilidades e processos de um sistema.

- Desacoplamento
	- Como cada serviço será desenvolvido e implementado isolado dos demais, o impacto de alterações e modificações será consideravelmente menor
- Escalabilidade
	- Escalar um microsserviço é de certa forma simples uma vez que podem ser escalado individualmente, reduzindo custos e otimizando recursos.
- Tecnologia Variada
	- O primeiro serviço foi escrito em JAVA, mas agora você precisa lidar com arquivos e quer usar GO?! Tudo bem, os serviços são independentes, permitindo que novas funcionalidades sejam desenvolvidas com a melhor ferramenta para aquela tarefa. Podemos ter uma aplicação com quantos microsserviços quisermos, com quantas linguagens forem necessárias.
- Facilidade de manutenção e de implantação
	- Realizar manutenção em uma aplicação que usa microsserviços possibilita que as modificações e alterações sejam realizadas em um único serviço, os testes executados serão apenas daquele serviço, ganhamos tempo e tornamos o deploy muito mais simples ao diminuir riscos — com isso nos aproximamos dos objetivos de integração e desenvolvimento contínuo.
	- Uma outra possibilidade dessa escolha arquitetônica é a criação de equipes especializadas em cada aspecto da nossa aplicação, isso torna nosso time mais dinâmico e mais eficiente para resolver possíveis chamados, atendendo com eficiência as demandas dos nossos clientes.
	- Quando um serviço sair do ar os demais continuarão funcionando, diminuindo a frustração dos usuários do sistema o que pode resultar em um menor impacto as operações


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/af1vzltjm52jpucihxx0.png)

## Pontos de atenção

### Organização dos repositórios

É necessário muito cuidado ao decidir como os repositórios de cada serviço será criado. Há duas estratégias para organização de repositórios, monorepos ou multi-repos. O mais intuitivo para a organização é pensarmos em utilizar vários repositórios, mantendo cada serviço 100% independente dos demais, e isso é totalmente aceitável e faz muito sentido. Quando atuamos em projetos com uma quantidade aceitável de repositórios, é consideravelmente simples manter todos os serviços atualizados mas e quando trabalhamos com 200, 300 serviços diferentes?! É nesses casos que monorepos ganham espaço.

Em sistema grandes e complexos, a abordagem intuitiva de manter cada serviço em repositórios separados pode impactar toda a governança do projeto, dificultando e até impossibilitando uma gerência das equipes envolvidas. Um outro ponto é que, para serviços interligados, será muito mais trabalhoso ao desenvolvedor preparar sua máquina para desempenhar o seu trabalho, perdendo eficiência.

Monorepos não são novidade dentro do mundo do desenvolvimento, Linux e Windows já usavam essa abordagem mas tem ganhado força nos últimos anos dentro da cultura Devops que prega, entre outras coisas, a total participação e integração das equipes envolvidas.
### Comunicação entre microsserviços

Não adianta criarmos vários microsserviços se eles não interagem para solucionar o problema do cliente, então como integrar esses serviços?! Ao separar um sistema em microsserviços, vamos encontrar as relações entre as parte e como as interações devem ser implementadas.

A comunicação síncrona é a mais habitual em softwares, onde cada nova ação depende do término da anterior. Um site que realiza um chamada HTTP a um servidor, precisa esperar os dados chegarem para então renderizar em tela, ou seja há uma sincronicidade das informações.

Já a comunicação assíncrona, embora menos utilizada em outras arquiteturas, é fundamental para um bom funcionamento de microsserviços. Você deve lembrar que uma das vantagens nessa abordagem é o desacoplamento entre as partes do nosso sistema, sendo assim se algo para de funcionar, o sistema pode continuar operando mesmo que sem aquela funcionalidade. Mas agora imagine que toda comunicação fosse síncrona, isso seria possível?!

Vamos pensar em uma rede social, você cria a sua conta e já tem acesso a algumas funcionalidades, para que acesse outras é necessário que sua conta seja verificada. Essa verificação pode ocorrer ou não em sequência, o serviço de e-mails talvez tenha saído do ar por algum erro no processamento mas isso não vai impactar o usuário que pode continuar mexendo sem que sua aplicação trave e fique esperando essa confirmação.

### Automatização e Padronização

Para criarmos microsserviços de modo eficaz é de bom tom que usemos modelos, padrões, _templates_, capazes de abstrair e diminuir a manualidade da operação. O ajuste para funcionamento de um sistema com essa abordagem é fino, precisando garantir a sincronicidade das informações, manter contratos entre interfaces e outros mil e um detalhes. Se para cada novo serviço for necessário implementar do zero, perderemos tempo e aumentaremos o risco de falhas no nosso sistema.

### Logs e Monitoramento

A essa altura do artigo, imagino que já deve estar percebendo que certas práticas comuns no desenvolvimento de sistemas centralizados não serão possíveis aqui. Dentre essas práticas algo que tive muita dificuldade trabalhando em um sistema com microsserviços foi a dificuldade de investigar bugs. Quando usamos um código monolítico é fácil *entupir* o código com breakpoints (ou console.log) para acompanharmos o funcionamento do sistema mas se o sistema é descentralizado, como fazer isso, como acompanhar os fluxos se muitas vezes não são síncronos, como identificar requisições que falharam, processos que quebraram, como examinar tudo?!

Por isso o uso de logs e ferramentas de monitoramento serão fundamentais. É nítido que todo sistema se beneficia do uso dessas tecnologias mas para microsserviços é fundamental, será a única forma de rastrear as requisições e interações do nosso sistema.

O monitoramento por sua vez permitirá uma ação proativa da equipe de desenvolvimento, identificando erros antes mesmo que a massa de clientes perceba. Além da detecção de falhas temos alguns outros pontos como:

1. Visibilidade
    
    Será que todos os serviços estão realmente disponíveis?! Cada serviço pode estar sendo disponibilizado em estruturas de clouds diferentes, em lugares geográficos diferentes.
    
2. Detecção de Falhas
    
    Falhas em microsserviços menos utilizados podem passar despercebidos pelos usuários devido sua baixa frequência de uso, uma ferramenta de monitoramento permitirá as equipes de desenvolvimento envolvidas atuar antes mesmo que o usuário final perceba.
    
3. Otimização de Desempenho
    
    Se o foco do dessa abordagem é o desempenho, com certeza vamos quere manter o desempenho do sistema. O monitoramento dos status dos nossos serviços permitirá identificar gargalos, prever sobrecargas do sistema, e esse conhecimento prévio permitirá ajustes e melhorias na nossa infra de modo a garantir o desempenho da aplicação.
    

## Exemplos de microsserviços

Sendo o ponto para criarmos microsserviços o momento após a criação de um monólito, teremos como técnica principal de criação de microsserviços o estrangulamento do nosso monólito, onde iremos remover de pouco a pouco os microsserviços. Mas como identificar os microsserviços possíveis?! Uma possibilidade interessante ocorre quando nosso monolito já está dividido em módulos, então podemos separar cada módulo em um microsserviço independente. Como nem sempre teremos essa divisão clara, acredito que uma boa forma de identificar os serviços da nossa aplicação é conhecer alguns exemplos de microsserviços.

1. Serviços de Negócios
    
    Processos internos do negócio estão sujeitos a se tornar serviços. A geração de boletos é um bom exemplo de um serviço que não precisaria estar acoplado a outras partes do sistema, poderíamos ter uma fila que salvasse os dados necessários para criar um boleto e um _cronjob_ que rodasse 2 vezes ao dia lendo a fila e criando os boletos necessários.
    
2. Serviços de Autenticação e Autorização
    
    Centralizar operações de autenticação e autorização pode ser uma boa ideia. Todo sistema utiliza maneiras de implementar mas via de regra são um módulo dentro do sistema já tendo sua implementação desacoplada do restante do código.
    
3. Serviços de Armazenamento de Dados
    
    Em alguns casos pode ser interessante isolar os serviços de armazenamento de dados, não somente banco de dados mas também sistemas de cache, manipulação de arquivos… Ao isolar este serviço poderíamos centralizar atividades de gerenciamento, recuperação de dados, criação de backups e outras funções relacionadas aos dados da nossa aplicação.
    
4. Serviços de Monitoramento e Registro
    
    Como vimos, monitorar e registrar é fundamental e com o intuito de padronizar nossos registros e insights, seria viável a criação de um serviço que ficasse responsável por gerir essa parte tão crítica ao nosso sistema.
    
5. Serviços de Gateway
    
    Em alguns casos podemos optar pela criação de um serviço centralizador de operações, que iria concentrar as requisições do cliente e teria a responsabilidade de rotear para o devido serviço. Esse gateway poderia centralizar solicitações de autenticação, autorização, e até mesmo o balanceamento de carga.
    

# Bônus

Agora que já entendemos o que são microsserviços e suas possibilidades, é hora de conversarmos sobre algumas ferramentas e conceitos que são utilizadas em muitos projetos quando se opta pelo uso de microsserviços.

## Contêineres

Garantir que o host do nosso serviço terá as configurações necessária de rede, DNS, versões de bibliotecas e SDK’s, de maneira simples e prática é fundamental para um bom aproveitamento da abordagem de microsserviços. Além disso, segundo as práticas de Devops e integração contínua, devemos buscar por ferramentas que nos permitam desenvolver, testar, homologar em ambientes que sejam o mais próximo possível do ambiente de produção, é nessa busca por ambiente iguais que os contêineres fazem sua mágica.

A ferramenta de contêiner mais comum e usada é o Docker mas existem outras opções no mercado como o Podman, no fim o que nos interessa aqui é o uso de contêineres para desenvolvimento e deploy, garantindo o máximo de uniformidade entre os ambientes.

Um contêiner possui aspectos interessantes para nosso propósito de criar serviços interdependentes como:

1. Isolamento
    
    Cada contêiner é uma unidade isolada no sistema, o que significa dizer que um aplicativo rodando em um container não será afetado por nenhuma alteração que ocorra em outra aplicação em outro container.
    
2. Empacotamento de aplicativos
    
    Ao criar um arquivo de configuração, um _dockerfile_ por exemplo, somos capazes de definir tudo o que será necessário para execução do nosso aplicativo, dependências como a versão do node necessária, ou a versão do mongo que queremos usar, podemos configurar ainda se iremos usar uma imagem Ubuntu para rodar a aplicação ou uma imagem Debian.
    
3. Portabilidade
    
    Uma vez que nosso contêiner está funcional, podemos facilmente migrá-lo para um serviço de cloud diferente ou ainda executá-lo na máquina local, com todas as suas funcionalidades preservadas.
    
4. Orquestração
    
    Parte da complexidade dos microsserviços é justamente garantir que todos os serviços estejam no ar, disponíveis e operando e fazer isso manualmente pode ser uma dor de cabeça e tanto. Para nossa sorte é possível utilizarmos um orquestrador de containers, que irá subir cada container necessário, numa determinada ordem lógica, garantindo o correto funcionamento de todo o nosso sistema.
    
    Uma das ferramenta utilizadas para orquestração é o Kubernetes, que dentre muitas coisas possui sistemas de auto recuperação, que em caso de falha pode reiniciar os contêineres, abstrai infraestruturas subjacentes e outros aspectos que merecem o estudo.
    

## Mensageria

A comunicação entre microsserviços é parte fundamental para um bom aproveitamento desta arquitetura. Com já dito há duas possibilidades de comunicação, assíncrona e síncrona, neste tópico vamos quero falar em especial da comunicação assíncrona e o uso de serviços de mensageria.

Mensageria é a prática de enviar mensagens entre componentes de software, nossos microsserviços, possibilitando a comunicação, facilitando a integração e a coordenação das operações do sistema. Okay, mas quais informações teremos nessas mensagens?!

Podemos montar uma mensagem com diversas informações, variando com as necessidades do projeto. A mensagem pode conter informações sobre eventos, solicitações, respostas, atualização de informações…

Vamos imaginar uma rede social, ao fazer a inscrição é criado uma mensagem contendo o nome, o _user_, e-mail. Então o serviço responsável por confirmar os dados leria a mensagem e dispararia o e-mail para o usuário realizar a confirmação da inscrição.

No mercado há algumas ferramentas que facilitam a implementação de mensageria, como Kafka e RabbitMQ que merecem um estudo aprofundado sobre.

## Testes Automatizados

Neste momento da leitura, imagino que já ficou claro que trabalhar com microsserviços pode ser complexo. Cada microsserviço precisa operar de maneira satisfatória para que todo o sistema realmente funcione, garantir o funcionamento de serviço manualmente pode ser uma grande dor de cabeça. Além da dificuldade, se a cada alteração em um microsserviço não tivermos a confiança de que ele se integrará corretamente aos demais serviços, nunca teremos confiança para realizar o deploy com independência e iremos perder mais um dos aspectos positivos desta abordagem.

Com tudo isso em mente o uso de testes automatizados pode ser uma excelente ideia. Ao criarmos testes unitários, testes de integração, aumentaremos a confiabilidade no que foi feito, permitindo agilidade ao realizar o deploy e quando alcançarmos a maturidade e a devida cobertura, poderemos estar realizando integração contínua bem como o deploy contínuo da nossa solução.

# Conclusão

Como tudo na nossa área, usar ou não a arquiteturas de software depende de muita avaliação e estudo. A abordagem “_**MonolithFirst**_” é uma grande aliada para não cometermos erros de _over engineering_ aumentando toda a complexidade do projeto antes que haja necessidade. Após a construção do nosso monolito, podemos começar a estrangula-lo, extraindo seus serviços em microsserviços, com eficácia e entregando valor ao nosso cliente. Para isso podemos lançar mão de várias tecnologias, ferramentas e abordagens que nos ajudarão a alcançar nossos objetivos.

# Continue seus estudos

Sabendo que se chegou até aqui é porque está estudando, deixo aqui alguns artigos que podem te ajudar (como me ajudaram) a entender melhor alguns temas que estão presentes nesse artigo.

* [Microservices](https://martinfowler.com/articles/microservices.html)
* [bliki: MonolithFirst](https://martinfowler.com/bliki/MonolithFirst.html)
* [EP62: Why Does Google Use Monorepo?](https://blog.bytebytego.com/p/ep62-why-does-google-use-monorepo)
* [Padrões essenciais de mensageria para integração de sistemas](https://pt.slideshare.net/helderdarocha/padres-essenciais-de-mensageria-para-integrao-de-sistemas) 
* [What is Continuous Delivery? - Continuous Delivery](https://continuousdelivery.com/) 
* [The Twelve-Factor App (traduzido)](https://12factor.net/pt_br/) 
* [Software Delivery Guide](https://martinfowler.com/delivery.html) 
* [Testes Automatizados – Hipsters #51](https://open.spotify.com/episode/1oCMLmcCtmH8tQz8S6xrHS?si=d9d0da1b0f934e7f) 
* [Integração Contínua, Deploy Contínuo e Github Actions – Hipsters #213](https://open.spotify.com/episode/4Z9Fyl6IHR7QX6VC2CNTlC?si=8990d07640414752)