Seu sistema legado está impedindo a empresa de crescer? Veja os principais sinais
Lançamentos travados, dependência de poucas pessoas, falhas recorrentes e integrações frágeis. Os sinais de que o legado virou um freio, e o que fazer a respeito.
Novo: Eficify One em beta aberto. Crie seu primeiro ambiente sem cartão.Conhecer a plataforma →

Todo sistema começa elegante. Depois de 18 meses, vira uma bola de lama que ninguém quer tocar. A culpa não é da equipe original. É da ausência de uma estratégia de evolução. Arquitetura evolutiva não é sobre antecipar o futuro. É sobre deixar o presente mais barato de mudar.
Engenheiros adoram perfeição. Querem projetar o sistema ideal, com microsserviços, event sourcing, CQRS e tudo mais. O problema é que toda decisão de arquitetura tem um custo de reversão. Microsserviços são baratos de deploy, mas são fáceis de desfazer. Um domínio mal cortado gera acoplamento entre serviços que nenhuma quantidade de Docker Compose vai resolver.
Decisões reversíveis são o fundamento da arquitetura evolutiva. Isso significa escolher padrões que te permitem mudar de ideia. Exemplo prático: em vez de decidir agora se o módulo de pagamentos será um microsserviço, coloque a lógica de pagamento em um pacote interno com interface clara. Se amanhã precisar extrair, o custo será menor. Se não precisar, você não pagou o preço da infraestrutura distribuída.
Decisões reversíveis não são decisões preguiçosas. São decisões com custo de mudança calculado.
A maioria das discussões sobre arquitetura termina em duas opções: monólito ou microsserviços. Essa é uma falsa dicotomia. A questão real é: como você corta os domínios dentro do seu sistema?
Bons cortes respeitam três princípios:
Acoplamento (contextual coupling): dois módulos mudam juntos porque pertencem ao mesmo domínio de negócio? Se sim, devem ficar próximos. Se mudam juntos por coincidência técnica (ex.: ambos usam PostgreSQL), esse não é um bom motivo para acoplá-los.
Coesão funcional: cada módulo resolve um problema bem definido. Se você não consegue descrever o módulo em uma frase curta, ele provavelmente faz coisas demais.
Estabilidade temporal: módulos estáveis (regras de negócio centrais) devem depender de módulos instáveis (interfaces de usuário). O inverso causa propagação de mudanças desnecessária.
src/
├── checkout/ # Contexto delimitado: pedido
│ ├── application/ # Casos de uso, orchestrators
│ ├── domain/ # Entidades, value objects, regras
│ └── infrastructure/ # Repositórios, adaptadores externos
├── catalog/ # Contexto delimitado: produtos
│ ├── application/
│ ├── domain/
│ └── infrastructure/
└── shared/ # Apenas utilitários, sem domínio
Perceba que cada contexto tem as três camadas internas (application, domain, infrastructure). Isso não é sobre arquitetura em camadas clássica. É sobre garantir que a lógica de negócio nunca dependa diretamente de detalhes de implementação (banco de dados, APIs externas). Essa inversão de dependência é o que permite trocar o PostgreSQL por DynamoDB sem tocar no domínio.
Quando dois módulos se comunicam, o que importa é o contrato entre eles, não a implementação interna. Em código, contratos são interfaces explícitas. Em sistemas distribuídos, contratos são contratos.
Contratos explícitos resolvem um problema específico: refatoração silenciosa. Quando você muda a assinatura de uma função ou a estrutura de um payload de API sem versionamento, está quebrando módulos que dependem de você. Contratos versionados, com schemas validados (Protobuf, JSON Schema, OpenAPI), capturam essa informação e forçam discussão antes da quebra.
Além disso, contratos orientados a domínio significam que você não passa objetos de domínio entre módulos. Você passa DTOs que representam o que aquele módulo precisa, não o que o outro módulo tem. Isso desacopla o modelo, impede vazamento de detalhes internos e torna refatorações seguras.
Aqui está a pergunta que todo tech lead enfrenta aos 18 meses de projeto. Microsserviços resolvem três problemas específicos:
| Problema | Monólito resolve? | Microsserviço resolve? | Alternativa? |
|---|---|---|---|
| Equipes pisando umas nas outras no mesmo codebase | Parcialmente | Sim | Módulos com ownership por equipe |
| Escalabilidade independente de um componente | Não | Sim | Auto-scaling do monólito (se empacotado corretamente) |
| Isolamento de falhas | Não | Sim | Circuit breakers no monólito |
| Tecnologias diferentes por domínio | Não | Sim | Plugins ou módulos polyglot |
Se você tem apenas o primeiro problema, módulos com boundaries claros e ownership por equipe resolvem. Microsserviços são resposta desproporcional. Se você tem o segundo ou terceiro, aí sim vale pagar o preço da complexidade operacional.
A armadilha comum é extrair um serviço porque "está na moda" ou porque outra empresa fez isso. Cada serviço extraído adiciona latência de rede, complexidade de observabilidade, custo de infraestrutura e necessidade de gerenciamento de dados distribuídos (sagas, eventos, eventual consistency). Se o domínio não justifica esses custos, você criou um monólito distribuído, que é pior que ambos.
flowchart TD
A{É necessário escalar o módulo independentemente?}
A -->|Sim| B{Múltiplas equipes precisam trabalhar no mesmo módulo?}
A -->|Não| C{Módulo tem domínio de negócio independente?}
B -->|Sim| D[Extrair como serviço independente]
B -->|Não| E[Manter no monólito]
C -->|Sim| F{Dados próprios e isolados?}
C -->|Não| E
F -->|Sim| G{Tamanho menor que 30% do monólito?}
F -->|Não| H[Considerar strangler fig pattern]
G -->|Sim| I[Extrair via strangler fig]
G -->|Não| J[Refatorar primeiro antes de extrair]Use a árvore de decisão acima como filtro inicial. Se qualquer resposta for "não", o default é manter como módulo dentro do monólito. Somente prossiga se houver ganho concreto e mensurável.
Acoplamento por (infraestrutura): quando dois módulos compartilham o mesmo banco de dados, você tem acoplamento estrutural. Mesmo que sejam módulos separados no código, uma migration no banco compartilhado vai exigir coordenação entre equipes. Solução: cada módulo com seu próprio schema ou banco.
Vazamento de domínio: quando o módulo de checkout começa a importar entidades do módulo de catalog, você tem vazamento. A lógica de um domínio está sendo duplicada ou compartilhada de forma implícita. Solução: introduza um domínio compartilhado (ex.: SKU, que pertence a nenhum domínio específico) ou um serviço de domínio que ambos chamam.
Big bang de reescrita: começar um projeto do zero dizendo "da próxima vez vamos fazer certo" é receita para o mesmo resultado. Arquiteturas evolutivas crescem incrementalmente, com cada módulo sendo refatorado para satisfazer os critérios de boundary quando for tocado.
Falsa modularidade: diretórios separados não são módulos. Se você tem pastas mas toda alteração em uma exige mudanças em dez outras, não há fronteira de módulo. Use a métrica de impacto: quantos arquivos você precisa tocar para fazer uma alteração típica em cada módulo?
Antes de tomar qualquer decisão de arquitetura, responda a estas perguntas:
Se a primeira pergunta não tiver uma resposta específica, pause. Arquitetura existe para resolver problemas, não para antecipá-los. A melhor arquitetura é aquela que te permite mudar de ideia com o menor custo possível.
Arquitetura evolutiva não é sobre usar a tecnologia mais nova ou o padrão mais sofisticado. É sobre disciplina de boundaries, contratos explícitos e decisões reversíveis. O monólito bem modularizado de hoje é a base para os serviços certos de amanhã. O segredo é saber quando um módulo merece subir de status e quando merece ficar exatamente onde está. Essa disciplina é o que separa sistemas que crescem dos que precisam ser reescritos a cada release.
Se cada nova entrega está ficando mais cara e arriscada, e o sistema parece travar a cada release, vale uma conversa de 30 minutos. A gente avalia suas fronteiras de módulo e desenha um caminho de evolução sem a dor de reescrever tudo, sem compromisso.
CONTINUE LENDO
Lançamentos travados, dependência de poucas pessoas, falhas recorrentes e integrações frágeis. Os sinais de que o legado virou um freio, e o que fazer a respeito.
Ter um especialista que resolve tudo parece uma vantagem. Quase sempre é um passivo escondido. Os custos que não aparecem no balanço quando a empresa depende de poucas pessoas-chave, e como reduzi-los sem perder talento.
Reli o clássico de Richards e Ford com uma tese provocadora: IA não é ferramenta de produtividade, é sistema de julgamento. E os fundamentos de arquitetura, trade-offs, características, decisões reversíveis, são, no fim, os fundamentos da infraestrutura de julgamento que toda empresa vai precisar.
VAMOS CONVERSAR
Conte seu cenário e receba uma leitura externa da sua arquitetura e dos próximos passos.
Agendar um assessment