Pular para o conteúdo principal

Monolito Modular

Visão Geral

Um monolito modular é uma aplicação implantada como unidade única, com fronteiras internas explícitas e impostas entre módulos de capacidade.

É a resposta correta para a maioria dos sistemas, e a menos considerada — porque "monolito" carrega uma conotação negativa que confunde duas coisas diferentes: implantação única e ausência de estrutura.

Problema

A escolha é apresentada como binária: monolito ou microsserviços. Monolito significa código emaranhado; microsserviços significam times autônomos e escala independente.

A dicotomia é falsa. O que torna um monolito doloroso não é a implantação única — é a ausência de fronteiras. E o que microsserviços entregam de fato divide-se em duas coisas com custos muito diferentes:

Isolamento lógico — módulos que não se conhecem por dentro. Um monolito modular entrega isso integralmente, por uma fração do custo.

Isolamento operacional — implantação, escala e falha independentes. Só serviços separados entregam, e é aqui que o custo real está.

A pergunta útil não é "monolito ou microsserviços?". É "eu preciso de isolamento operacional, ou só de isolamento lógico?" — e a segunda resposta é a mais comum.

Conceitos Centrais

O que o torna modular

Três propriedades. Faltando qualquer uma, é apenas um monolito.

Módulos por capacidade de negócio, não por camada técnica. Ver design modular.

Contrato explícito entre módulos. Cada um publica uma interface estreita e esconde suas entidades, seu esquema e suas dependências.

Fronteiras impostas por mecanismo. Teste de arquitetura, módulo de linguagem ou análise estática. Sem isso, as fronteiras erodem — ver arquitetura vs. implementação.

Dados por módulo

O ponto que mais separa um monolito modular de um monolito comum: cada módulo é dono dos seus dados.

O banco pode ser um só. O acesso não. O módulo de cobrança não lê a tabela de catálogo; ele chama a API do módulo de catálogo ou consome um evento.

Impor isso é mais difícil que impor fronteira de código, e há mecanismos: esquemas separados no mesmo banco, permissões por módulo, ou verificação estática de quais tabelas cada módulo referencia.

Sem essa propriedade, extrair um serviço depois é praticamente impossível — porque a fronteira nunca existiu onde importava.

É o passo que informa a extração

Um monolito modular bem feito responde empiricamente a pergunta que ninguém consegue responder no papel: onde as fronteiras de serviço deveriam estar?

Depois de um ano, o histórico mostra quais módulos mudam juntos, quais são estáveis, e quais têm requisito de escala distinto. Extrair vira decisão informada em vez de aposta.

Quando Usar

  • Sistemas novos, em domínio ainda não plenamente entendido.
  • Times de até algumas dezenas de pessoas.
  • Quando não há requisito comprovado de escala ou implantação independente.
  • Quando a organização não tem maturidade operacional para sistemas distribuídos.
  • Como etapa antes de considerar extração de serviços.

Quando Não Usar

Quando há requisito real de escala independente. Um componente que precisa de dez vezes mais recursos que o resto desperdiça ao escalar junto.

Quando times precisam de autonomia de implantação. Se cinco times bloqueiam uns aos outros no release, a fronteira precisa ser de implantação.

Quando o isolamento de falha é requisito. Um módulo que não pode derrubar os outros precisa de processo separado.

Quando partes têm requisitos regulatórios ou de segurança incompatíveis.

Quando a base já é grande demais para um build e um teste viáveis. Se o ciclo de feedback passa de dezenas de minutos e não há como paralelizar, isso é um custo real.

Alternativas

  • Microsserviços — quando o isolamento operacional é necessário.
  • Monolito sem módulos — legítimo em sistemas pequenos e de vida curta.
  • Extração seletiva — monolito modular com um ou dois serviços extraídos por razão específica. É o arranjo mais comum em sistemas maduros e o menos nomeado.

Trade-offs

Monolito modularMicrosserviços
Um pipeline, um artefatoUm por serviço
Transação local entre módulosCoordenação distribuída
Refatorar fronteira é um commitÉ uma migração
Depuração num processoRastreamento distribuído
Escala em blocoEscala por serviço
Falha compartilhadaFalha isolável
Release acoplado entre timesAutônomo
Fronteira erode sem mecanismoImposta pela rede

As quatro primeiras linhas são vantagens do monolito que costumam ser esquecidas na comparação. As quatro últimas são o que microsserviços compram — e o preço está nas colunas de cima.

Modos de Falha

Fronteiras nominais. Diretórios sem imposição. Vira monolito comum em meses.

Banco compartilhado sem propriedade. Módulos lendo tabelas uns dos outros. É a falha que mais impede a extração futura.

Módulo shared crescente. Dependência universal.

Build que não escala. Ciclo de feedback longo demais, sem paralelização por módulo.

Modularidade que não corresponde ao negócio. Divisão por entidade ou por camada; toda mudança atravessa módulos.

Erros Comuns

Tratar "monolito" como falha de arquitetura. É uma decisão de implantação.

Não impor as fronteiras. Sem mecanismo, não há modularidade.

Compartilhar tabelas entre módulos.

Adotar microsserviços para obter isolamento lógico. Paga-se o custo operacional por algo que módulos entregam.

Não medir se as fronteiras estão certas. O histórico responde.

Onde ele aparece na prática

Shopify. Documentou publicamente a escolha por monolito modular em Ruby, com imposição de fronteiras por ferramenta própria, em vez de migrar para microsserviços.

Muitos sistemas que reverteram microsserviços. Vários relatos públicos de consolidação de serviços de volta em monolitos modulares, motivados por custo operacional e complexidade de depuração.

Aplicações empresariais com módulos de linguagem. Sistemas de módulo em Java e .NET permitem impor fronteiras em tempo de compilação.

O padrão nos relatos de reversão é consistente: os times mantiveram a modularidade e abandonaram a distribuição. Isso confirma que os dois eram separáveis — que é exatamente a tese deste documento.

Exemplo Real

Uma empresa de logística com dezoito engenheiros construiu a plataforma em nove microsserviços, seguindo o que era considerado boa prática.

Depois de dois anos: quatro dos nove eram sempre implantados juntos; nenhum escalava independentemente porque o gargalo era o banco compartilhado; e o tempo médio para diagnosticar um incidente era de quarenta minutos, quase todo gasto correlacionando registros entre serviços.

A consolidação juntou os quatro acoplados num monolito modular, mantendo as fronteiras como módulos com teste de arquitetura. Três serviços foram mantidos separados — os que tinham requisito real de escala ou de isolamento de falha. Dois foram descontinuados.

Resultado: de nove para quatro unidades implantáveis. Tempo de diagnóstico caiu para menos de dez minutos. Nenhuma fronteira lógica foi perdida.

O que a equipe registrou no ADR é a parte que interessa: a arquitetura original não estava errada em identificar as fronteiras — estava errada em concluir que toda fronteira lógica precisava ser uma fronteira de processo.

Conceitos Relacionados

Exercício Prático

Se seu sistema é distribuído, meça: quantos dos serviços são sempre implantados juntos? Quantos escalam de forma independente na prática?

Se seu sistema é um monolito, verifique: existem fronteiras internas? Elas são impostas por algum mecanismo? Módulos leem tabelas uns dos outros?

Perguntas de Entrevista

  • Qual a diferença entre isolamento lógico e operacional?
  • O que torna um monolito "modular"?
  • Por que a propriedade dos dados por módulo importa mais que a de código?

Para Aprofundar

  • Newman, Sam. Monolith to Microservices. O'Reilly, 2019 — o monolito modular como ponto de partida.
  • Fowler, Martin. MonolithFirst, 2015.
  • Documentação pública de Shopify sobre modularização de monolito.