Microsserviços vs Monólito: A decisão que vai definir seus próximos anos
Toda semana alguém começa um novo projeto e pergunta: “devo usar microsserviços?” A resposta honesta é: provavelmente não, pelo menos não ainda.
O que os posts de hype não te contam
Microsserviços são a arquitetura de empresas como Netflix, Uber e Amazon depois de anos evoluindo um monólito. Eles resolvem problemas que surgem na escala desses sistemas. Se você não tem esses problemas, não precisa da solução.
Custos reais de microsserviços:
- Latência de rede entre serviços (o que era uma chamada de função vira uma requisição HTTP)
- Transações distribuídas são extremamente difíceis
- Observabilidade: você precisa de distributed tracing, log correlation, health checks por serviço
- Deploy: orquestração com Kubernetes ou ECS, service discovery, circuit breakers
- Equipe: cada serviço precisa de ownership claro
Quando o monólito é a resposta certa
Para a maioria dos projetos, o monólito é mais simples, mais rápido de desenvolver e mais fácil de operar:
Monólito bem estruturado
├── src/
│ ├── modules/
│ │ ├── usuarios/
│ │ │ ├── usuarios.controller.ts
│ │ │ ├── usuarios.service.ts
│ │ │ └── usuarios.repository.ts
│ │ ├── pedidos/
│ │ │ ├── pedidos.controller.ts
│ │ │ ├── pedidos.service.ts
│ │ │ └── pedidos.repository.ts
│ │ └── pagamentos/
│ └── shared/Um monólito modular com fronteiras bem definidas entre domínios é muito mais fácil de extrair em serviços quando necessário.
O critério real: fronteiras de equipe
Conway’s Law: “Qualquer organização que projeta um sistema irá produzir um design cuja estrutura é uma cópia da estrutura de comunicação da organização.”
Se você tem 3 desenvolvedores, um monólito. Se você tem 10 times independentes que precisam deployar de forma autônoma, microsserviços fazem sentido.
Microsserviços resolvem:
- Autonomia de times — cada time faz deploy sem coordenar com outros
- Escalabilidade granular — só o serviço de relatórios precisa de mais instâncias
- Isolamento de falhas — um serviço caindo não derruba o sistema todo
- Tecnologias heterogêneas — cada serviço pode usar a linguagem certa para o problema
A abordagem do “Monólito Modular” (o meio-termo inteligente)
// Fronteiras claras entre módulos sem deploy separado
// modulos/pedidos/pedidos.service.ts
import { UsuariosService } from '../usuarios/usuarios.service' // interface, não HTTP
import { PagamentosService } from '../pagamentos/pagamentos.service'
@Injectable()
export class PedidosService {
constructor(
private usuarios: UsuariosService,
private pagamentos: PagamentosService,
private pedidosRepo: PedidosRepository,
) {}
async criarPedido(dto: CriarPedidoDto) {
const usuario = await this.usuarios.buscarPorId(dto.usuarioId)
const pedido = await this.pedidosRepo.criar(dto)
await this.pagamentos.iniciarCobranca(pedido)
return pedido
}
}Quando você quiser extrair pagamentos como microsserviço, a interface já está definida — você só troca a chamada direta por uma chamada HTTP ou mensagem numa fila.
Quando extrair um serviço faz sentido
Sinais de que um módulo está pronto para virar microsserviço:
- Time dedicado — existe um time que cuida só daquele domínio
- Escalabilidade diferente — o módulo tem características de carga muito diferentes do resto
- Tecnologia diferente — o problema pede um runtime ou banco específico
- Isolamento de deploy — falhas naquele módulo não podem afetar o sistema todo
- Fronteira de dados limpa — o módulo tem suas próprias tabelas, sem joins com outros módulos
Se nenhum desses critérios se aplica, não extraia.
Comunicação entre serviços: síncrona vs assíncrona
Quando você tiver microsserviços, prefira comunicação assíncrona para operações que não precisam de resposta imediata:
// Síncrono (HTTP) — use para leituras e operações que precisam de resultado
const usuario = await http.get(`/usuarios/${id}`)
// Assíncrono (fila) — use para operações que podem ser processadas depois
await sqs.send('pedido-criado', { pedidoId, usuarioId })
// Consumidor separado
queue.on('pedido-criado', async ({ pedidoId, usuarioId }) => {
await enviarEmailConfirmacao(usuarioId, pedidoId)
await atualizarInventario(pedidoId)
})Checklist antes de adotar microsserviços
- Você tem times independentes que precisam deployar de forma autônoma?
- Você tem expertise em Kubernetes ou ECS para operar os serviços?
- Você tem observabilidade (traces, métricas, logs centralizados) configurada?
- Você entende como fazer transações distribuídas (Saga, eventual consistency)?
- O custo operacional adicional é justificável pelo problema que resolve?
Se respondeu “não” para a maioria: comece com o monólito. Você pode sempre extrair depois.