Microsserviços: quando resolvem um problema — e quando criam outro
Dois sistemas reais com a mesma arquitetura e resultados opostos: os critérios que fazem microsserviços valerem seu custo operacional, e os que não.
Microsserviços não são um nível de maturidade. São uma resposta a restrições específicas. Quando essas restrições existem, o custo da arquitetura se paga. Quando não existem, você paga o preço da resposta sem receber o benefício.
Trabalhei com microsserviços em dois sistemas. Num deles a arquitetura estava certa. No outro, não.
A diferença entre os dois casos não foi a qualidade da execução. Foi o problema que cada sistema precisava resolver.
Essa distinção é fácil de enunciar e difícil de aplicar, porque o argumento a favor dos microsserviços costuma ser apresentado em abstrato: acoplamento menor, times autônomos, deploy independente, escala granular. Tudo isso é verdade. Nada disso informa se o seu projeto está diante do problema que essas propriedades resolvem.
Quando os microsserviços resolveram um problema real
Trabalhei no sistema de gestão do Porto de Santos. Iniciei e construí alguns dos microsserviços que o compõem.
Um porto não é um domínio. É um conjunto de domínios que operam em paralelo, cada um com sua própria autoridade, seu próprio ritmo e suas próprias regras.
A atracação e a desatracação de navios eram controladas por um serviço. O controle de tráfego nos arredores do porto era outro. O credenciamento era outro.
Esses domínios não eram independentes entre si. Eles dependiam uns dos outros o tempo todo: um navio que atraca movimenta veículos no entorno, e quem opera nesse entorno precisa estar credenciado. A dependência era real e constante.
É aqui que a intuição costuma falhar. A existência de dependência entre domínios é frequentemente usada como argumento contra a separação — se eles conversam tanto, por que separar?
No Porto de Santos, a resposta não vinha do acoplamento. Vinha da consequência de uma parada.
Ali não se admite que o sistema pare. Uma interrupção não gera um chamado de suporte; gera prejuízo na casa dos milhões de reais, porque a operação física do porto não para junto com o software. Navios continuam chegando, veículos continuam se aproximando, cargas continuam sendo movimentadas.
Essa restrição muda o cálculo inteiro.
Num sistema único, uma falha no credenciamento é uma falha do sistema. Todo mundo para. Com os domínios separados em serviços próprios, uma falha no credenciamento é uma falha no credenciamento: a atracação continua operando, o controle de tráfego continua operando, e o dano fica contido no domínio que quebrou.
Isolamento, ali, não era elegância arquitetural. Era o requisito.
Vale separar duas coisas que costumam ser confundidas. Dependência de negócio significa que dois domínios precisam trocar informação. Não significa que precisam compartilhar processo, banco de dados e ciclo de vida.
No porto, os domínios dependiam uns dos outros e, precisamente por isso, precisavam ser isolados e atomizados. Quanto mais operações atravessam domínios, mais cara fica a decisão de deixar que todos caiam juntos. A dependência entre eles era o argumento a favor da separação, não contra ela.
O efeito prático foi uma distribuição descentralizada: se um serviço caísse, os demais continuavam operando. É a diferença entre um sistema que degrada e um sistema que para — e, naquele contexto, essa diferença tinha valor mensurável em reais.
E havia o tamanho. Um monólito que abarcasse toda a operação portuária seria colossal, e o custo de compreendê-lo, testá-lo e alterá-lo cresceria no mesmo ritmo. A separação não estava sendo usada para deixar o desenho bonito. Estava sendo usada porque cada domínio já era, sozinho, um sistema.
Quando os microsserviços criaram um problema novo
O segundo caso é um projeto meu. Já contei essa história em Como usar IA para programar sem terceirizar seu raciocínio, sob a ótica da decisão. O que interessa aqui é a arquitetura.
Adotei microsserviços porque queria entender o modelo por dentro: a comunicação entre os serviços, o isolamento, o uso de chamadas diretas ou eventos, a separação dos bancos de dados. Não queria ficar na teoria, então construí uma aplicação que eu pudesse executar e questionar.
O sistema funciona. E a arquitetura está errada para ele.
O deploy e a manutenção ficaram muito mais complexos do que o projeto justificava. A aplicação passou a exigir mais infraestrutura e mais capacidade computacional. A consistência dos dados, que num sistema único seria uma transação, virou um problema de desenho a ser resolvido continuamente.
Hoje estou refatorando esse sistema para um monólito modular, mantido num monorepo.
O detalhe incômodo é que as decisões técnicas dos dois casos se parecem. Serviços separados, bancos separados, comunicação explícita entre domínios. O que mudou foi que, no primeiro caso, existia uma restrição que pagava a conta — e no segundo, não existia nenhuma.
O que separava os dois casos
Quando comparo os dois sistemas, o que distingue um do outro não é uma preferência técnica. São condições verificáveis, e cada uma tem um teste concreto.
A fronteira de domínio existe fora do código. O teste: você consegue descrever o que aquele serviço decide sozinho, sem citar outro serviço? Atracação decide sobre atracação. Credenciamento decide quem pode operar. Se a fronteira só existe no diagrama, e toda operação real atravessa três serviços para se completar, você não separou domínios — distribuiu um domínio único.
O isolamento de falha é exigido pelo negócio, não desejado pela equipe. O teste: o que acontece se o sistema inteiro ficar indisponível por meia hora? Se a resposta é um chamado de suporte e usuários irritados, isolamento é uma qualidade desejável. Se a resposta é uma perda que a operação não absorve, isolamento é requisito — e requisito justifica custo.
Os domínios mudam em ritmos diferentes. O teste: nas últimas dez entregas, quantas tocaram um único domínio? Se toda entrega exige três serviços subindo numa ordem específica, você tem o custo do deploy independente e nenhuma das suas vantagens.
A carga é assimétrica. O teste: existe parte do sistema cuja demanda é desproporcional ao resto? Se o sistema inteiro escala junto, uma instância maior resolve o mesmo problema por uma fração do custo operacional.
No Porto de Santos, os dois primeiros critérios estavam presentes de forma inequívoca, e foram eles que sustentaram a decisão. No meu projeto, nenhum dos quatro estava.
Vale dizer o que esses critérios não são. Eles não formam uma pontuação, e não existe um número mínimo que autoriza a separação. Um único critério presente com força suficiente — como a exigência de continuidade no porto — pode bastar sozinho. Quatro critérios presentes de forma fraca provavelmente não bastam.
A conta que vem junto
Separar um sistema em serviços não remove complexidade. Move complexidade do código para a operação, onde ela é mais cara de observar e mais difícil de reverter.
O que entra na conta:
- chamadas de função viram chamadas de rede, e falha parcial deixa de ser exceção para virar caso normal;
- consistência forte dá lugar a consistência eventual, com todo o desenho que isso exige;
- observabilidade precisa atravessar processos para que uma requisição continue sendo legível de ponta a ponta;
- mudanças de contrato exigem deploys coordenados, exatamente o que a arquitetura prometia evitar;
- testes de comportamento real precisam de mais de um serviço no ar;
- a infraestrutura cresce, e com ela o custo fixo;
- alguém precisa saber o que fazer quando um serviço específico está fora.
Essa lista é a mesma nos dois casos. O que muda é o outro lado da conta.
No porto, o custo operacional era menor do que o custo de uma parada geral — e a comparação nem era próxima. No meu projeto, não havia nada do outro lado. Eu paguei a conta inteira em troca de aprendizado, que foi real, mas não é o que sustenta uma arquitetura em produção.
O que fazer quando nenhum critério aparece
Se nenhum critério aparece, a alternativa não é um monólito descuidado. Essa é a falsa oposição que empurra muito projeto para os microsserviços: de um lado, serviços independentes; do outro, um bloco único onde tudo acessa tudo. Existe uma terceira posição, e é ela que atende a maior parte dos casos.
Um monólito modular mantém a separação de domínios onde ela é barata — no código — e recusa a separação onde ela é cara: no processo, no banco de dados e no deploy.
Na prática, isso significa fronteiras internas explícitas. Cada módulo expõe uma interface e esconde o restante. Um módulo não alcança a tabela de outro; ele chama o que o outro oferece. As dependências entre módulos são declaradas e verificáveis — de preferência por uma regra que o build consiga reprovar, não por combinação verbal que a primeira urgência desfaz.
O que se ganha é quase tudo o que o discurso dos microsserviços promete no nível do desenho: limites claros, responsabilidades separadas, código que cabe na cabeça de quem mantém. O que não se paga é a conta operacional. A chamada continua sendo uma chamada de função, a transação continua sendo uma transação, e o deploy continua sendo um artefato só.
Há ainda um ganho que só aparece depois. Um sistema com fronteiras internas reais é o único que pode ser separado de verdade no dia em que uma restrição concreta aparecer. A extração vira uma operação delimitada: o módulo já tem interface, já tem dados próprios, já não é alcançado por atalhos.
Um monólito sem fronteiras não oferece esse caminho. É por isso que a separação tardia costuma ser descrita como impossível quando, na verdade, ela apenas foi deixada de fora do desenho desde o começo.
As perguntas antes de decidir
Antes de adotar microsserviços, ou antes de aceitar a recomendação de alguém — inclusive de uma IA:
- Quais são os domínios, e cada um decide alguma coisa sozinho?
- O que acontece com o negócio quando o sistema inteiro para?
- Esse problema existe hoje, ou é uma projeção de um futuro que talvez não chegue?
- Qual é a alternativa mais simples que atende o requisito?
- Quem vai operar isso, e essa pessoa consegue?
- Como a consistência dos dados será garantida entre os serviços?
- O benefício justifica a complexidade, medido em operação e não em diagrama?
Se as respostas não vêm com clareza, a decisão ainda não está madura. Isso não significa que microsserviços estão descartados — significa que ainda não há informação suficiente para escolher.
Vale lembrar que a decisão não é permanente nos dois sentidos. Separar um monólito bem modularizado depois é trabalhoso, mas possível. Reunir microsserviços que já espalharam estado por bancos independentes é consideravelmente mais difícil, e é o caminho que estou percorrendo agora.
A pergunta que importa
Microsserviços continuam sendo a resposta certa para uma classe específica de problema. O Porto de Santos é um desses casos: domínios genuinamente distintos, dependência de negócio entre eles e uma operação que não pode parar.
A pergunta que separa um caso do outro nunca foi se a arquitetura funciona. Quase toda arquitetura funciona quando bem executada — foi exatamente isso que aconteceu no meu projeto.
A pergunta é qual restrição do seu sistema justifica pagar por ela.
Se você não consegue nomear essa restrição, provavelmente ela não existe. E resolver um problema que você não tem é a forma mais cara de errar.