TL;DR
- Com 10 utilizadores, microserviços são quase sempre uma distracção cara. O problema normal ainda é produto, vendas, onboarding e dados, não escalabilidade.
- A alternativa correcta costuma ser um monólito modular com PostgreSQL 16, filas assíncronas e limites internos bem definidos.
- Microserviços só começam a fazer sentido cedo se houver isolamento regulatório, cargas muito diferentes, equipas independentes ou integrações externas com risco operacional alto.
- O custo real não é “ter mais repositórios”. É observabilidade, deploys, testes distribuídos, autenticação entre serviços, versionamento de APIs, incidentes e consistência de dados.
- Antes de migrar, mede: p95 e p99, throughput, tempo de deploy, taxa de erro, duração de jobs, custo por ambiente e tempo gasto a diagnosticar incidentes.
A resposta curta: não, salvo raras excepções
Se tens 10 utilizadores, a resposta prática é: não vale a pena migrar para microserviços.
Não porque microserviços sejam maus. São uma ferramenta útil quando a complexidade organizacional e operacional já justifica a separação. O problema é usá-los antes de existirem os sintomas que eles resolvem.
Com 10 utilizadores, o risco mais provável não é a base de dados não escalar. É o produto ainda não ter encaixe no mercado, a equipa ainda não saber quais são os fluxos críticos, o domínio ainda estar a mudar todas as semanas e os requisitos ainda não terem estabilizado. Nestes cenários, distribuir o sistema por vários serviços só torna cada mudança mais lenta.
Na Impact Origin, quando olhamos para projectos em fases iniciais, incluindo clientes activos recentes com cerca de dois meses e billing ainda por definir, a pergunta raramente é “como separamos isto em serviços?”. A pergunta certa é mais dura: “que parte do sistema já provou que merece complexidade própria?”. Muitas vezes, nenhuma.
Também há projectos onde a stack ainda nem está formalizada de forma estável. Isso não é mau. É normal em fases iniciais. Mas se ainda estás a decidir tecnologia, modelo de dados, fluxos de pagamento, integração com ERP ou lógica de permissões, partir para microserviços é saltar três degraus.
A opinião forte: se ainda não consegues explicar claramente os limites do teu domínio numa folha A4, não devias estar a criar microserviços. Devias estar a clarificar o produto e a modularizar o monólito.
O custo real dos microserviços
Muita gente pensa em microserviços como “dividir a aplicação em partes pequenas”. Na prática, significa trocar chamadas locais por chamadas de rede, transacções simples por consistência eventual e bugs previsíveis por falhas parciais.
Uma chamada dentro do mesmo processo pode demorar microssegundos. Uma chamada HTTP interna, mesmo dentro da mesma região cloud, pode facilmente ficar entre 5 ms e 50 ms. Com TLS, autenticação, retries e serialização JSON, o p99 pode chegar a 100 ms ou mais em momentos de carga. Se uma página precisa de 5 serviços para responder, acabaste de criar uma cascata de latência.
O custo também aparece nestas áreas:
| Área | Monólito modular | Microserviços |
|---|---|---|
| Deploy inicial | 1 pipeline | 3 a 10 pipelines |
| Debug local | Arrancar uma app e uma base de dados | Orquestrar vários serviços, filas, mocks e dependências |
| Testes | Integração directa | Contract testing, testes end-to-end frágeis, ambientes partilhados |
| Dados | Transacções ACID simples | Eventos, idempotência, reconciliação, consistência eventual |
| Observabilidade | Logs e métricas por app | Tracing distribuído, correlação de logs, métricas por serviço |
| Segurança | Sessão e permissões num ponto | Autenticação serviço a serviço, scopes, rotação de segredos |
Se usas Kubernetes, lê a própria documentação oficial antes de o meteres num produto pequeno: https://kubernetes.io/docs/home/. Kubernetes resolve problemas reais, mas cria uma superfície operacional grande. Namespaces, ingress, probes, autoscaling, secrets, network policies, RBAC e upgrades do cluster não são gratuitos em tempo.
Com 10 utilizadores, muitas equipas ficariam melhor com uma VM bem configurada, Docker Compose para ambientes simples, PostgreSQL gerido e uma pipeline CI/CD decente. Por exemplo: GitHub Actions, Render, Fly.io, Heroku, Railway ou AWS App Runner podem ser mais que suficientes, dependendo dos requisitos de compliance e rede.
O ponto não é “nunca uses cloud complexa”. O ponto é: não compres complexidade operacional antes de teres carga, receita ou risco que a pague.
O que deves construir em vez disso
A arquitectura que recomendo na maioria dos SaaS B2B pequenos é um monólito modular.
Isto não significa uma bola de lama. Significa uma aplicação única, com fronteiras internas claras. Por exemplo:
- módulo de contas e organizações
- módulo de billing
- módulo de permissões
- módulo de integrações
- módulo de notificações
- módulo de reporting
- módulo de tarefas assíncronas
A base pode ser Node.js 22 LTS com Fastify ou NestJS, Ruby on Rails 8, Django 5, Laravel 11.NET 8 ou Phoenix 1.7. A tecnologia interessa menos do que a disciplina nas fronteiras.
Para dados, PostgreSQL 16 chega muito longe. Tens transacções, índices parciais, JSONB quando necessário, Row Level Security, materialized views e extensões úteis. A documentação oficial é excelente: https://www.postgresql.org/docs/16/.
Para jobs, podes começar com uma fila simples. BullMQ com Redis é comum em Node.js. pgmq é interessante quando queres reduzir infra e usar PostgreSQL como fila. Se o volume é baixo, por exemplo 1.000 a 50.000 jobs por dia, não precisas de Kafka. Kafka é óptimo quando tens streams sérios, múltiplos consumidores e retenção de eventos como requisito. Para enviar emails, gerar PDFs, sincronizar com um ERP ou processar webhooks, uma fila normal resolve.
Uma regra que funciona bem: mantém o deploy único, mas impede acoplamento interno descontrolado.
Podes fazer isto com convenções simples:
- cada módulo tem a sua pasta, os seus serviços e os seus repositórios de dados
- módulos não acedem directamente às tabelas uns dos outros sem passar por uma interface interna
- eventos internos são explícitos, mesmo dentro do monólito
- jobs são idempotentes desde o início
- permissões são centralizadas, não espalhadas por controllers
Isto dá-te uma vantagem enorme: quando um módulo provar que merece existir como serviço separado, já tens uma fronteira conceptual. A extracção passa a ser uma decisão técnica, não uma cirurgia de emergência.
Quando microserviços podem fazer sentido mesmo cedo
Há excepções. Poucas, mas reais.
A primeira é isolamento regulatório ou de dados. Se tens um componente que trata dados clínicos sensíveis, dados financeiros críticos ou informação com requisitos legais diferentes, pode fazer sentido isolá-lo. Em healthtech e fintech, esta conversa aparece cedo. Não por performance, mas por risco, auditoria e acesso mínimo necessário.
A segunda é carga muito assimétrica. Imagina uma aplicação com 10 utilizadores humanos, mas que recepciona 2 milhões de webhooks por mês de uma plataforma externa. A contagem de utilizadores engana. O sistema que processa eventos pode precisar de escala, retries, dead letter queues e limitação de taxa muito antes da interface administrativa precisar.
A terceira é ciclo de vida diferente. Se tens um motor de cálculo, processamento de imagem, ingestão de ficheiros grandes ou sincronização com ERP que muda e escala de forma independente, talvez faça sentido separá-lo. Mesmo assim, muitas vezes começa como worker separado no mesmo repositório, não como ecossistema de microserviços.
A quarta é equipa. Microserviços têm mais a ver com equipas do que com computadores. Se tens uma equipa de 20 engenheiros distribuída por domínios diferentes, a separação pode reduzir conflitos. Se tens 2 ou 3 pessoas, normalmente aumenta a coordenação.
A quinta é dependência externa perigosa. Integrações com ERPs, CRMs, gateways de pagamento e plataformas eCommerce podem falhar de formas desagradáveis. Nesses casos, isolar um conector pode ser útil. Ainda assim, isolamento não exige sempre microserviço. Pode ser uma queue, uma tabela de outbox e um worker bem desenhado.
A armadilha comum: partir a base de dados cedo demais
A pior migração para microserviços é aquela que começa pela base de dados.
Já vi este padrão em produção: a equipa separa “users service”, “billing service” e “notifications service”, mas todos continuam a precisar dos mesmos dados. Resultado: ou partilham a mesma base de dados, violando a independência dos serviços, ou duplicam dados sem uma estratégia de sincronização decente.
As duas opções doem.
Base de dados partilhada entre microserviços parece prática no início. Mas se o serviço A lê tabelas do serviço B, não tens microserviços. Tens um monólito distribuído, que é pior do que um monólito normal. Agora tens os custos de rede e deploys independentes sem independência real.
Bases de dados separadas exigem eventos, contratos, idempotência e reconciliação. Por exemplo, se o billing precisa de saber o email do utilizador, vais copiar esse dado? Vais consultar o serviço de utilizadores em runtime? Vais reagir a um evento UserEmailChanged? O que acontece se o evento falhar? Como corriges divergências?
O padrão outbox é uma resposta séria para este problema. Em vez de gravar dados e publicar evento em duas operações separadas, guardas o evento na mesma transacção da alteração principal. Depois, um worker publica o evento. Martin Fowler descreve bem padrões relacionados em https://martinfowler.com/articles/201701-event-driven.html, e a ideia também aparece em arquitecturas event-driven usadas com Kafka, RabbitMQ ou filas geridas.
Mas repara: se já estás a falar de outbox, retries, dead letters, consumidores idempotentes e reconciliação, tens de perguntar se esses mecanismos são justificados para 10 utilizadores.
Em muitos casos, a decisão mais madura é manter uma base de dados única, com schemas ou convenções por domínio, e preparar o terreno. PostgreSQL aguenta volumes muito maiores do que a maioria das startups atinge nos primeiros anos. Com índices correctos, queries medidas e connection pooling, 300 requests por segundo não é ficção num monólito bem escrito. O teu gargalo com 10 utilizadores não será esse.
Como decidir: uma grelha simples e brutal
Antes de migrar, responde a estas perguntas com dados, não com ansiedade.
| Pergunta | Se a resposta for “não” |
|---|---|
| Tens p95 acima de 300 ms em endpoints críticos por causa de um módulo específico? | Não migres. Optimiza queries, cache e jobs. |
| Tens p99 acima de 1 s por chamadas internas bloqueantes? | Primeiro remove chamadas desnecessárias e mede. |
| Tens mais de 5 deploys por dia bloqueados por conflitos entre equipas? | Com equipa pequena, o problema pode ser processo, não arquitectura. |
| Tens módulos com necessidades de escala 10x diferentes? | Se não, um processo separado pode chegar. |
| Tens requisitos legais que obrigam a isolamento? | Se não, evita fragmentar dados cedo. |
| Tens observabilidade mínima com logs estruturados, métricas e tracing? | Sem isto, microserviços vão piorar incidentes. |
Métricas mínimas antes de considerar microserviços:
- p50, p95 e p99 por endpoint
- taxa de erro 4xx e 5xx
- tempo médio e máximo dos jobs
- tamanho da base de dados, por exemplo 10 GB, 100 GB ou 1 TB
- número de conexões activas no PostgreSQL
- custo mensal por ambiente
- tempo médio para diagnosticar um incidente
- tempo de deploy e rollback
Se não tens estes números, estás a decidir arquitectura por sensação. Isso é caro.
Para observabilidade, OpenTelemetry é hoje uma boa base. A documentação oficial está em https://opentelemetry.io/docs/. Não precisas de uma plataforma caríssima no primeiro mês, mas precisas de logs com correlation IDs, métricas úteis e traces nos fluxos críticos.
Também deves olhar para contratos de API. Se começares a separar serviços, define OpenAPI 3.1 para HTTP ou Protobuf para gRPC. Sem contrato, cada deploy vira uma aposta. A especificação OpenAPI está em https://spec.openapis.org/oas/latest.html.
Um caminho de migração sensato
A boa migração para microserviços começa muito antes de criares o primeiro serviço.
Primeiro, limpa o monólito. Separa módulos, remove dependências circulares, centraliza permissões e cria interfaces internas. Se isto for impossível, microserviços não vão resolver. Vão apenas distribuir a confusão.
Segundo, move trabalho lento para background jobs. Um endpoint que gera relatórios, sincroniza stock ou chama APIs externas não deve bloquear o pedido do utilizador. Com 10 utilizadores, esta alteração costuma dar mais ganhos do que uma reescrita arquitectural.
Terceiro, cria eventos internos. Não precisam de sair do processo no primeiro dia. O objectivo é tornar explícito que “pagamento confirmado” dispara “actualizar subscrição”, “emitir recibo” e “enviar email”. Quando isto está claro, podes trocar o mecanismo interno por uma fila real.
Quarto, mede. Se um módulo específico consome 80% do CPU, 90% do tempo de resposta ou exige deploys independentes constantes, tens um candidato. Caso contrário, tens apenas vontade de mexer em arquitectura.
Quinto, extrai um serviço pequeno e com fronteira óbvia. Bons candidatos: processamento de ficheiros, notificações, webhooks, motor de pesquisa, geração de PDFs. Maus candidatos iniciais: utilizadores, permissões e billing. Estes tendem a estar ligados a tudo.
Sexto, assume o custo completo. Um serviço novo precisa de pipeline, health checks, logs, métricas, alertas, documentação, testes de contrato, gestão de segredos e plano de rollback. Se não tens apetite para isto, não tens apetite para microserviços.
Uma regra prática: se não consegues operar dois serviços com confiança às 03:00, não cries dez.
Conclusão
Com 10 utilizadores, microserviços raramente são a decisão certa. Um monólito modular, bem medido e com jobs assíncronos dá mais velocidade e menos risco. Migra apenas quando houver dados, fronteiras claras e uma razão operacional forte.
Se estás a enfrentar um problema parecido, marca uma conversa em https://impact-origin.com/agendamento.