Depois de adotar uma arquitetura de microserviços, é comum perceber que alguns aspectos precisam ser unificados ou “centralizados” de alguma forma, para garantir coerência, reuso e facilidade de manutenção. Neste primeiro artigo de uma nova série, analisaremos por que e como podemos retomar certa “coesão” no ecossistema de microserviços sem abrir mão dos benefícios da divisão. Falaremos de um panorama geral de quatro possíveis estratégias:
- Replicação de Código
- Biblioteca Compartilhada
- Serviço Compartilhado
- Sidecars e Malhas de Serviços
Nos artigos subsequentes, cada estratégia será aprofundada em um post específico, detalhando vantagens, desvantagens e melhores práticas de implementação.
1. O Contexto: Microserviços e Fragmentação
1.1 Por que Microserviços?
- Escalabilidade e independência de deploy: cada serviço pode evoluir e ser escalado separadamente.
- Equipes autônomas: times podem trabalhar em serviços distintos de forma independente.
- Resiliência: falha em um serviço não derruba todo o sistema.
1.2 O Problema da “Fragmentação Demais”
Com o tempo, pode-se perceber:
- Funcionalidades ou lógicas repetidas em vários serviços.
- Padrões de segurança, validação ou logging duplicados.
- APIs que precisam se comunicar intensamente ou que têm muita sobreposição, resultando em complexidade adicional.
É quando se vê a necessidade de “reunir” certos elementos, sem retornar a um monólito. Surge então a pergunta: “Como ganhar coesão novamente?”
2. Estratégias para Reunir o Essencial sem Voltarmos ao Monólito
2.1 Replicação de Código
Ideia: Copiar e colar código (classes, módulos) em cada microserviço, de forma deliberada. Esse código replicado pode ser um conjunto de utilitários ou lógica de negócio comum.
- Prós: Simples (não depende de repositório único ou bibliotecas); cada serviço retém total autonomia.
- Contras: Se precisar corrigir um bug ou evoluir a lógica compartilhada, é preciso atualizar cada serviço manualmente.
2.2 Biblioteca Compartilhada
Ideia: Extrair lógicas comuns em uma biblioteca (jar, npm package, gem, etc.) que cada serviço importa como dependência.
- Prós: Centraliza a manutenção do código comum; qualquer atualização na biblioteca pode ser versionada e distribuída.
- Contras: Exige pipeline de publicação e versionamento adequados, e ainda assim, cada serviço precisa atualizar a dependência para receber correções.
2.3 Serviço Compartilhado
Ideia: Criar um microserviço “base” que concentra determinadas funcionalidades e é consumido pelos demais via API.
- Prós: Se algo precisa ser corrigido/evoluído, faz-se centralmente; evita duplicação de código.
- Contras: Pode se tornar um “macro-serviço” ou “God service”, aumentando acoplamento e criando dependência forte dos demais.
2.4 Sidecars e Malhas de Serviços (Service Mesh)
Ideia: Usar sidecars (containers “auxiliares” acoplados a cada microserviço) e/ou uma service mesh (ex.: Istio, Linkerd) que forneça funcionalidades de forma unificada (observabilidade, segurança, roteamento).
- Prós: Garante padronização de logging, tracing, segurança, sem duplicar lógica na aplicação.
- Contras: A complexidade de orquestrar sidecars e configurar a mesh pode ser grande; necessidade de estudar e operar infraestrutura mais avançada.
3. Quando Escolher Cada Estratégia?
3.1 Replicação de Código
- Indicada quando a lógica comum é relativamente pequena e estável, e a equipe não quer ou não pode manter dependências oficiais.
- Cuidado para não gerar problemas de divergência ao longo do tempo.
3.2 Biblioteca Compartilhada
- Boa quando queremos reusar código de forma coesa e controlada, atualizando via versionamento sem copiar e colar.
- Exige pipeline de CI/CD e versionamento claro, além de um repositório (Nexus, Artifactory, npm registry privado, etc.).
3.3 Serviço Compartilhado
- Útil quando existe uma API ou funcionalidade significativa que todos precisam e que pode ser oferecida por um microserviço dedicado (ex.: serviço de login, serviço de notificações).
- Risco de se tornar um ponto central (risco de gargalo ou falhas em cascata) ou um “monólito interno”.
3.4 Sidecars e Malhas de Serviços
- Excelente para padronizar aspectos transversais (log, tracing, segurança mTLS, roteamento inteligente), sem duplicar na aplicação.
- Complexidade maior em setup e operação (Kubernetes, service mesh, observabilidade extra).
4. Considerações Finais
Essas estratégias não são excludentes. Um projeto pode:
- Usar bibliotecas compartilhadas para a maior parte da lógica de utilitários.
- Ter um serviço comum para funcionalidades mais robustas (ex.: relatório central).
- Adotar sidecar ou service mesh para padronizar autenticação, logs e métricas de rede.
- Replicar código em alguns casos menores, pela simplicidade de “copiar e colar”.
O importante é balancear a autonomia e os princípios dos microserviços (isolar responsabilidades, permitir evolução independente) com a necessidade de coesão e reuso. Ao longo desta série de artigos, discutiremos em maior detalhe cada estratégia:
- Replicação de Código
- Biblioteca Compartilhada
- Serviço Compartilhado
- Sidecars e Malhas de Serviços
para que você possa decidir como “reagrupar” certas partes da lógica ou infraestrutura sem romper a essência dos microserviços.
Próximos Passos
No próximo artigo, exploraremos a Replicação de Código em microserviços: quando é aceitável simplesmente duplicar trechos de lógica, quais os riscos e como gerenciar versões copiadas de forma minimamente controlada. Fique atento!
Notas Bibliográficas
- Arquitetura de Software: As Partes Difíceis. Editora Alta Books.