- Separar o código cedo demais em microsserviços em startups iniciais causa uma queda séria na produtividade da equipe e aumento da complexidade
- A arquitetura monolítica (única) oferece otimização para sobrevivência com deploy simples, lançamento rápido de novas funcionalidades e colaboração eficiente
- Microsserviços só trazem vantagem real da separação quando há necessidade de grande escalabilidade, cargas de trabalho diferentes ou requisitos de runtime separados
- Separação excessiva de serviços, proliferação de repositórios, ambiente local de desenvolvimento instável e desalinhamento da stack tecnológica levam a redução de velocidade e queda do moral da equipe
- Startups devem começar com um monólito e adotar uma abordagem cuidadosa, separando apenas quando surgirem gargalos claros
Introdução e contexto
- A sobrevivência de uma startup é determinada por iteração rápida, entrega de novas funcionalidades e criação de valor para o usuário
- A arquitetura base do projeto, a stack tecnológica e a escolha da linguagem de programação afetam a velocidade da equipe
- A adoção precoce de microsserviços parece sofisticada no papel, mas na prática causa queda de produtividade, serviços inacabados e excesso de complexidade
- Dados: surgem vários custos de desenvolvimento, como orquestração de serviços, problemas com Docker/scripts, CI/CD duplicado, acoplamento entre serviços, custo de observabilidade e testes dispersos
- Em vez de avançar sem critério para uma arquitetura complexa, o texto enfatiza a importância de uma arquitetura pragmática
Pontos fortes do monólito
- Seja um SaaS ou um simples wrapper de banco de dados, o app fica mais complexo com o tempo, mas a arquitetura monolítica tende a permanecer simples e flexível com mais facilidade
- O deploy é fácil, há suporte de frameworks populares (Django, ASP.Net, Nest.js etc.) e o benefício das comunidades open source é grande
- Caso real: em uma startup do setor imobiliário, um monólito em Laravel permitiu alcançar com facilidade inúmeras integrações com terceiros e expansão de funcionalidades
- Foi possível focar em atender as demandas e expectativas do negócio sem introduzir infraestrutura complexa nem separar tudo em microsserviços
- Lição: a simplicidade da arquitetura ajuda a equipe a se concentrar em entregar; desde que se evite falhar na modularização interna, a escala continua viável
Microsserviços são sempre a melhor opção?
- Muitos engenheiros acham que microsserviços são a resposta padrão, mas na prática eles só mostram seu valor quando existe um motivo especial, como escalabilidade
- Em equipes pequenas, com pouco volume e em fase de mudanças rápidas, o efeito pode ser o oposto: infra duplicada, desenvolvimento local lento e ciclos de iteração mais demorados
- Empresas como a Segment também passaram por mudanças motivadas por estruturas ineficientes
- Lição: microsserviços são uma ferramenta para resolver gargalos, não um template para o começo
Por que microsserviços falham especialmente no estágio inicial
1. Fronteiras de serviço arbitrárias
- Ao tentar dividir serviços por lógica de negócio com base em design orientado a domínio e teoria de clean architecture, a lógica real e as fronteiras dos serviços muitas vezes não se alinham direito
- Exemplo: separar usuário, autenticação e autorização aumenta a complexidade de deploy e a dificuldade de desenvolver APIs
- Separar nessa fase, antes de qualquer gargalo real aparecer, torna o sistema instável e lento
- Simular futuras separações com flags ou toggles internos e explorar fronteiras de forma orgânica pode ser mais eficaz do que correr para trabalhos urgentes de infraestrutura
- Lição: decisões de separação devem se basear em gargalos reais, não em teoria
2. Excesso de repositórios/infraestrutura
- Estilo de código, testes, configuração, documentação e CI/CD aumentam na mesma proporção do número de serviços
- Com uma estrutura de monorepo, é possível administrar tudo em um só lugar e melhorar a consistência do código e a eficiência da colaboração
- No caso de Node.js, ferramentas como
nx ou turborepo facilitam o gerenciamento de dependências e builds entre serviços internos
- Como desvantagens, há dependências complexas, necessidade de ajuste de performance no CI e demanda por ferramentas de build mais rápidas
- No ecossistema Go, também faz sentido começar com um workspace único e só depois, com o crescimento, considerar a separação em módulos
- Lição: equipes pequenas podem ganhar tempo com monorepo e infraestrutura compartilhada
3. Ambiente local de desenvolvimento instável
- Tempo excessivo para rodar localmente, scripts complexos e dependências específicas do sistema causam atraso no onboarding e perda de produtividade
- Falta de documentação, problemas de compatibilidade e hacks específicos de OS (ex.: scripts apenas para macOS) viram obstáculos
- Em um projeto, um proxy em Node.js reduziu a complexidade do Docker e encurtou o tempo de onboarding dos desenvolvedores
- Lição: se o app só roda em um único sistema operacional, a produtividade do time acaba dependendo da confiabilidade de um único laptop
4. Desalinhamento da stack tecnológica
- Node.js e Python são bons para iteração rápida, mas em ambientes de microsserviços surgem com frequência problemas de desalinhamento entre build e runtime
- Go tem vantagens em binários estáticos, builds rápidos e simplicidade operacional
- A escolha da stack no início deve ser cuidadosa e, se necessário, é possível misturar linguagens com protocolos como gRPC
- Sem exigências especiais como ML ou ETL, misturar stacks tende apenas a aumentar a complexidade
- Lição: escolha uma stack adequada à realidade da equipe, não ao cenário idealizado
5. Complexidade oculta: comunicação e monitoramento
- Em microsserviços, service discovery, versionamento de API, tracing distribuído e gestão centralizada de logs são itens obrigatórios
- Rastrear bugs e incidentes em um monólito pode exigir apenas um stack trace, mas em um ambiente distribuído isso fica muito mais complexo
- Para fazer direito, é preciso adotar ferramentas especializadas como OpenTelemetry e montar uma stack de observabilidade
- É preciso reconhecer que sistemas distribuídos exigem investimento obrigatório em desafios adicionais de engenharia
Quando microsserviços fazem sentido
- Isolamento de workload: separar tarefas assíncronas específicas, como processamento de imagem ou OCR, pode ser eficiente
- Desequilíbrio na necessidade de escala: quando Web API e workloads de ML têm exigências diferentes de hardware e operação, faz sentido separá-los
- Necessidade de outro runtime: componentes incompatíveis com o runtime do app principal, como código legado em C++, devem ser mantidos como serviços separados
- Como mostram casos de grandes organizações de engenharia (ex.: Uber), isso só é adequado quando há necessidade organizacional clara e capacidade operacional madura
- Mesmo em equipes pequenas, a separação pode ser prática em casos raros, como um serviço externo de analytics fácil de gerenciar
- Lição: adote apenas em workloads em que os benefícios práticos da separação sejam claros
Guia prático para startups
- Comece com um monólito e foque no trabalho usando frameworks já comprovados
- Um repositório único traz mais benefícios para equipes iniciais em eficiência operacional, gestão e segurança
- Simplificar o ambiente local de desenvolvimento é importante e, quando isso for difícil, é essencial fornecer documentação e vídeos detalhados
- Invista cedo em CI/CD para automatizar tarefas repetitivas e reduzir a carga mental da equipe
- Separe seletivamente apenas quando surgirem gargalos claros; fora isso, concentre-se em modularização e testes dentro do monólito
- O objetivo principal é preservar a velocidade de desenvolvimento
- Lição: comece pela simplicidade e escale de acordo com a necessidade real de separação
Se você realmente precisar usar microsserviços
- Avalie a stack tecnológica e invista em ferramentas de experiência do desenvolvedor: é necessário preparar automação por serviço, scripts claros e ferramentas integradas de gestão de deploy
- Padronize protocolos confiáveis de comunicação entre serviços: é preciso entender itens extras de implementação, como consistência de schemas de mensagens, documentação e tratamento de erros
- Estabilize a infraestrutura de testes: testes unitários, de integração e E2E precisam escalar de acordo com a separação dos serviços
- Considere bibliotecas compartilhadas: mantenha o código comum de observabilidade e comunicação no menor escopo possível para evitar rebuilds frequentes de todos os serviços
- Observabilidade deve entrar cedo: comece pelo básico, como logs JSON estruturados e correlation IDs
- Em resumo, se você vai aceitar a complexidade, é importante projetar um sistema gerenciável e tratá-lo com disciplina total
Conclusão
- Adotar microsserviços com pressa só deixa peso extra, então a simplicidade deve vir em primeiro lugar
- Não separe sem um ponto claro de dor; a perspectiva importante é adicionar apenas a complexidade mínima necessária para sobreviver e crescer
- Sobreviver vem primeiro; escalar fica para depois
10 comentários
Concordo com a essência do texto original de modo geral.
Acho que é uma questão de experiência da organização.
Pode ser útil imaginar alguém vendendo comida em um food truck e depois se transformando em um restaurante.
Desde o começo, falta absolutamente experiência aos envolvidos para considerar divisão de trabalho e especialização.
Acho que startups precisam escolher caminhos de menor custo para prolongar seu tempo de sobrevivência. Microsserviços definitivamente não são baratos. Quando aplicados de fato no ambiente real, acabam gerando custos consideráveis. Sempre que possível, acredito que projetar uma arquitetura adequada ao próprio serviço da empresa é a forma de obter efeitos semelhantes com menos custo.
Não estou dizendo que microsserviços são ruins. É um modelo que exige muitos recursos.
Acho que só dois já bastam: um monólito exclusivamente síncrono e um monólito exclusivamente assíncrono... Vejo a adoção de microsserviços, no fim das contas, até onde vai a escala das tabelas que precisam ser gerenciadas pelo banco de dados. Se o número de tabelas for absurdamente grande e complexo, aí vale pensar em MSA; se for simples, monólito é a escolha ideal.
Quando todas essas ondas tiverem passado, como as gerações futuras se lembrarão desta era?
Naquela época, também havia a onda daquela época...
Também acho que microsserviços têm muitas vantagens em startups. Antes de tudo, recomendo muito usar um monorepo.
Concordo que, na era do desenvolvimento voltado para IA, é essencial implementar em unidades pequenas, com responsabilidade única.
Isso apareceu de leve nos comentários também, mas a linha beam/otp parece bem flexível e boa. No caso do Gleam, a boa sintaxe tanto de Go quanto de Rust, somada à estabilidade do beam, fez dele uma linguagem bastante impressionante. Estou começando a querer usá-la em projetos pequenos.
Se você divide o time demais, até se reunir para trocar ideias vira um trabalho enorme.
Opinião no Hacker News
rule) em uma lei (law).