Pular para o conteúdo

Arquitetura real · Pleno

Shopify: monólito modular (Deconstructing the Monolith)

Arquitetura real em produção. Pontos centrais: fronteiras de componente e checagem estática de dependências.

15 min de leitura · Fonte: Shopify · Conteúdo revisado em 23 de outubro de 2026

Resposta curta

Arquitetura real em produção. Pontos centrais: fronteiras de componente e checagem estática de dependências. O núcleo do Shopify é uma das maiores bases de código em Ruby on Rails e nasceu como um monólito: funcionalidades distintas no mesmo código, sem fronteiras entre elas.

01 · CONTEXTO

Um monólito Rails que cresceu demais

O núcleo do Shopify é uma das maiores bases de código em Ruby on Rails e nasceu como um monólito: funcionalidades distintas no mesmo código, sem fronteiras entre elas. Um balanço posterior do próprio time mostra o porte do resultado, com mais de 2,8 milhões de linhas de Ruby.

Enquanto o produto é jovem, o monólito tem vantagens reais: é a arquitetura mais fácil de implementar, concentra o trabalho num repositório e num pipeline de testes e deploy, e deixa os componentes se chamarem diretamente, sem passar por APIs de serviço.

O limite apareceu em 2016, quando ficou cada vez mais difícil construir e testar funcionalidades novas. Dois sintomas marcaram esse ponto: uma mudança aparentemente inocente podia causar uma cascata de falhas de teste sem relação aparente, e mudanças simples exigiam muito contexto.

  1. O código de frete convivia com o de checkout, e havia pouco que impedisse um de chamar o outro.

    Diagrama da arquitetura: Monólito sem fronteiras
    CPCheckout
    CPFrete
    CPImposto
    CPPedidos
    CPPagamentos
    DBBanco compartilhado
  2. O exemplo do artigo: o cálculo de frete chama o cálculo de imposto.

    Diagrama da arquitetura: Monólito sem fronteiras
    CPCheckout
    CPFrete
    CPImposto
    CPPedidos
    CPPagamentos
    DBBanco compartilhado
  3. Mudar o cálculo de imposto podia alterar o resultado do frete, sem que a causa fosse óbvia.

    Diagrama da arquitetura: Monólito sem fronteiras
    CPCheckout
    CPFreteresultado afetado
    CPImposto
    CPPedidos
    CPPagamentos
    DBBanco compartilhado
  4. Por causa desse entrelaçamento, quem entra no time de frete acabaria precisando entender também pedidos e pagamentos.

    Diagrama da arquitetura: Monólito sem fronteiras
    CPCheckout
    CPFrete
    CPImposto
    CPPedidos
    CPPagamentos
    DBBanco compartilhado

02 · ALTERNATIVAS

Monólito, microsserviços ou meio-termo

Uma alternativa conhecida eram os microsserviços, mas o time apontou o custo: vários pipelines e infraestrutura por serviço, sem garantia de acesso aos dados, e chamadas pela rede que somam latência e perdem confiabilidade. O Shopify escolheu manter o código numa base e definir e respeitar fronteiras entre os componentes.

Monólito sem fronteirasMicrosserviçosMonólito modular
Fronteiras entre domíniosNenhuma entre as funcionalidadesA rede separa os serviçosEstritamente impostas entre domínios
ComunicaçãoChamadas diretas entre componentes, sem API de serviçoAtravessa a rede, com mais latência e menos confiabilidadeDentro de uma só aplicação, com código num único lugar
ImplantaçãoUm repositório e um pipeline de testes e deployPipelines e infraestrutura por serviço, com deploys coordenados em refatorações grandesMais modularidade sem aumentar as unidades de implantação

03 · COMPONENTIZAÇÃO

Reorganizar por domínio e isolar dependências

O primeiro passo foi a organização do código. Ele seguia o padrão típico de Rails, por conceitos de software; a meta era reorganizá-lo por conceitos do mundo real, como pedidos, frete, estoque e cobrança, ou seja, por domínios de negócio.

A lista inicial de componentes veio de rotular manualmente cada classe Ruby numa planilha. A movimentação dos arquivos foi feita num único pull request gerado por scripts. O custo: parte do histórico no GitHub se perdeu, porque as movimentações apareceram como remoções e criações.

O segundo passo foi isolar dependências. Cada componente define uma interface pública e assume a posse exclusiva dos seus dados. Uma ferramenta interna, o Wedge, passou a destacar os acessos que violam essas fronteiras.

  1. Cada componente expõe uma interface pública e é dono dos seus dados; o acesso de fora deve passar por ela.

    Diagrama da arquitetura: Fronteiras checadas na CI
    CPFrete
    CPImposto
    CPPedidos
    CPCI com tracepoints
    NWWedge
  2. Durante a CI, uma ferramenta usa tracepoints do Ruby para obter o grafo de chamadas do código.

    Diagrama da arquitetura: Fronteiras checadas na CI
    CPFrete
    CPImposto
    CPPedidos
    CPCI com tracepoints
    NWWedge
  3. As chamadas entre componentes seguem para o Wedge, que decide quais são aceitáveis e quais violam a fronteira.

    Diagrama da arquitetura: Fronteiras checadas na CI
    CPFrete
    CPImposto
    CPPedidos
    CPCI com tracepoints
    NWWedge
  4. Pela regra do Wedge, chamadas só são aceitas para o que é explicitamente público; num acesso como este a um interno do outro componente, o Wedge apontaria violação.

    Diagrama da arquitetura: Fronteiras checadas na CI
    CPFreteviola a fronteira
    CPImposto
    CPPedidos
    CPCI com tracepoints
    NWWedge
  5. Com as dependências isoladas, o motor de imposto legado pôde ser trocado por um sistema novo de cálculo.

    Diagrama da arquitetura: Fronteiras checadas na CI
    CPFrete
    CPImpostomotor novo
    CPPedidos
    CPCI com tracepoints
    NWWedge

04 · CHECAGEM ESTÁTICA

Do grafo de chamadas ao Packwerk

No balanço seguinte, o time disse que manteve as ideias originais, mas que quase todos os detalhes mudaram. Na checagem de dependências, o time passou a usar uma ferramenta nova, o Packwerk, no lugar do Wedge.

WedgePackwerk
O que analisaChamadas registradas com a suíte de testes instrumentada na CIReferências estáticas a constantes
Qualidade do sinalResultados muitas vezes pouco úteis; às vezes nem ficava claro de qual componente vinha a chamadaMenos ambiguidade; referências explícitas são mais acionáveis
Tempo de feedbackMais de uma hora, por depender da suíte completaPoucos minutos no maior código, encaixado no fluxo de pull request
  1. Uma mudança em algum componente chega como pull request.

    Diagrama da arquitetura: Portão de dependências no pull request
    CLPessoa desenvolvedora
    CPPull request
    CPPackwerk
    CPBranch principal
  2. O Packwerk analisa as referências estáticas a constantes, que são explícitas e menos ambíguas.

    Diagrama da arquitetura: Portão de dependências no pull request
    CLPessoa desenvolvedora
    CPPull request
    CPPackwerk
    CPBranch principal
  3. Como a análise completa leva poucos minutos no maior código, ela cabe no fluxo do pull request.

    Diagrama da arquitetura: Portão de dependências no pull request
    CLPessoa desenvolvedora
    CPPull request
    CPPackwerk
    CPBranch principal
  4. Mudanças que quebram o grafo de dependências ou a encapsulação são rejeitadas antes de chegar à branch principal.

    Diagrama da arquitetura: Portão de dependências no pull request
    CLPessoa desenvolvedora
    CPPull requestrejeitada se quebra
    CPPackwerk
    CPBranch principal

05 · LIÇÕES

O que ainda não estava resolvido

O balanço posterior traz números de adoção: o monólito principal tinha 37 componentes com pontos de entrada públicos, e o Packwerk cobria cerca de um terço deles. A mudança de arquitetura em andamento é descrita como em grande parte um problema de pessoas.

Ao analisar o grafo, o time encontrou uma dependência muito densa, com cada componente dependendo de mais da metade dos demais, além de muitas dependências circulares. Isso, segundo o texto, impede raciocinar sobre os componentes e evoluí-los separadamente. Para desfazer ciclos, as saídas citadas foram mover responsabilidades ou aplicar inversão de controle.

A abordagem escolhida para o monólito principal seguiu a visão de Domain Driven Design para definir os componentes. A desvantagem reconhecida é que quase nenhum componente tem ainda uma fronteira completa e forte. Insistir em consistência de interface acrescentou regras, que sempre trazem atrito.

Perguntas frequentes

O que é Shopify: monólito modular (Deconstructing the Monolith)?

Arquitetura real em produção. Pontos centrais: fronteiras de componente e checagem estática de dependências.

O que o design de Shopify: monólito modular (Deconstructing the Monolith) cobre?

Ele está organizado nestas seções: Um monólito Rails que cresceu demais, Monólito, microsserviços ou meio-termo, Reorganizar por domínio e isolar dependências, Do grafo de chamadas ao Packwerk e O que ainda não estava resolvido.

Quanto tempo leva Shopify: monólito modular (Deconstructing the Monolith) e qual é o nível?

Leva cerca de 15 minutos para ler e tem nível Pleno.

Agora projete você mesmo

Rode este caso como uma entrevista na escola de System Design: você toma as decisões, o tutor as questiona e você vê a nota do seu desenho.