Como Estruturar seus Módulos

01 de maio de 2026

arquitetura modulararquitetura de softwaremodularizaçãodesign de softwarecomplexidade

EAE, bora tomar um cafezinho? ☕

Até aqui, eu construí a conversa em três movimentos.

Primeiro, eu quis deixar claro que arquitetura modular não é simplesmente dividir código em pastas, criar projetos separados ou trocar um monólito por microserviços. Depois, aprofundei os princípios que sustentam uma boa modularidade: responsabilidade clara, coesão, baixo acoplamento, encapsulamento, independência relativa e contratos. Em seguida, olhei para os objetivos mais profundos dessa abordagem: reduzir complexidade e permitir uma evolução mais segura.

Agora a conversa precisa encostar em um ponto mais prático.

Se modularidade importa, se ela depende de bons princípios e se seu valor está em tornar o sistema mais compreensível e mais seguro para evoluir, então a pergunta natural é: como eu estruturo meus módulos?

Essa pergunta parece simples, mas não é.

Na verdade, ela talvez seja uma das perguntas mais difíceis de toda a discussão sobre arquitetura modular. Porque dividir um sistema em módulos não é apenas escolher nomes bonitos, agrupar arquivos parecidos ou desenhar caixas em um diagrama. Estruturar módulos é tomar decisões sobre onde a responsabilidade começa, onde ela termina, o que deve ficar junto, o que deve ficar separado e quais partes do sistema merecem uma fronteira mais explícita.

E é aqui que muita arquitetura se complica.

Porque quase todo mundo concorda, em tese, que módulos devem ser coesos e pouco acoplados. O problema aparece quando precisamos transformar essa ideia em recortes concretos. Onde termina o módulo de pedidos? O pagamento pertence ao pedido ou é uma responsabilidade própria? Relatórios são um módulo separado ou apenas uma funcionalidade espalhada por outros módulos? Autenticação é parte do usuário ou uma capacidade independente? Uma regra que envolve cliente, cobrança e entrega deve morar onde?

Percebe o tipo de problema?

A modularidade deixa de ser uma definição bonita e vira uma decisão arquitetural real. E decisão real quase nunca cabe em fórmula pronta.

Por isso, neste capítulo, eu não quero vender um método mágico para encontrar o recorte perfeito. Eu não acredito muito nesse tipo de promessa. O que eu quero fazer é algo mais útil: construir uma forma de pensar. Uma espécie de lente para avaliar módulos, identificar bons recortes, reconhecer sinais de excesso ou fragmentação e evitar que a modularização vire apenas uma decoração estrutural.

Porque, no fim das contas, estruturar módulos é menos sobre aplicar uma receita e mais sobre fazer boas perguntas.

E a pergunta mais importante talvez seja esta:

o que muda junto deve ficar junto?

Essa frase não resolve tudo, mas abre uma porta excelente.

Um bom módulo não é apenas uma parte separada

Antes de falar sobre critérios de divisão, eu gosto de começar por uma distinção básica: um módulo não é bom apenas porque está separado.

Isso parece óbvio, mas na prática não é.

É muito comum encontrar sistemas que parecem modulares por fora, mas continuam profundamente confusos por dentro. Há pastas separadas, nomes de módulos, talvez até projetos diferentes, dependências formalmente divididas, mas a lógica continua espalhada, as responsabilidades se sobrepõem, as regras vazam de um lado para outro e qualquer mudança relevante ainda exige entender metade da aplicação.

Nesse caso, a separação existe visualmente, mas não estruturalmente.

Um bom módulo precisa ter identidade.

Ele precisa representar uma parte do sistema que faz sentido como unidade de raciocínio. Quando eu olho para ele, devo conseguir entender por que ele existe, qual responsabilidade concentra, que tipo de decisão deveria ficar dentro dele e que tipo de decisão deveria ficar fora.

Essa identidade não precisa ser perfeita, definitiva ou imutável. Sistemas mudam. Domínios amadurecem. O entendimento melhora. Mas, ainda assim, um módulo precisa ter um centro de gravidade. Ele precisa ser mais do que uma gaveta onde coloquei coisas que pareciam parecidas.

Um módulo começa a fazer sentido quando ele ajuda a responder perguntas como:

que responsabilidade este módulo protege?

que tipo de mudança deveria acontecer aqui dentro?

que conhecimento este módulo concentra?

que decisões externas não deveriam conhecer seus detalhes internos?

que parte do sistema fica mais fácil de entender porque este módulo existe?

Essas perguntas importam porque a modularidade não é uma questão de quantidade de partes. É uma questão de qualidade das divisões.

Um sistema com poucos módulos bem desenhados pode ser mais modular do que um sistema com dezenas de módulos artificiais. Da mesma forma, um sistema com vários módulos pequenos pode ser saudável quando esses módulos representam recortes claros, e pode ser caótico quando cada separação cria apenas mais dependência, mais passagem de dados e mais confusão.

Então, antes de perguntar “quantos módulos eu devo ter?”, eu prefiro perguntar outra coisa:

quais unidades realmente melhoram meu entendimento do sistema?

Essa pergunta é mais honesta.

Ela tira a modularidade do campo estético e coloca onde ela deveria estar: no campo da inteligibilidade, da responsabilidade e da evolução.

Responsabilidade como eixo principal

Se eu tivesse que escolher o primeiro critério para estruturar módulos, eu escolheria responsabilidade.

Não porque os outros critérios não importem, mas porque responsabilidade é o eixo que dá sentido aos demais. Um módulo pode se alinhar a um domínio, a uma funcionalidade, a uma capacidade de negócio ou a um fluxo, mas se ele não concentra uma responsabilidade clara, o recorte começa fraco.

Responsabilidade, aqui, não significa apenas “o que o módulo faz”. Essa definição é pequena demais.

Quando eu falo de responsabilidade em arquitetura modular, estou falando do conjunto de decisões que aquele módulo deve assumir. Estou falando da parte do sistema pela qual ele responde conceitualmente. Estou falando do tipo de conhecimento que pertence a ele.

Um módulo de pagamentos, por exemplo, não deveria existir apenas porque “faz pagamento”. Essa frase é vaga. A pergunta mais relevante é: que decisões relacionadas a pagamento ele concentra?

Ele valida meios de pagamento? Ele calcula condições? Ele registra tentativas? Ele conversa com provedores externos? Ele conhece políticas de captura, cancelamento e estorno? Ele apenas orquestra uma chamada externa? Ele contém regra de negócio ou apenas adaptação técnica?

Veja que, dependendo das respostas, o módulo muda completamente de natureza.

É por isso que responsabilidade precisa ser pensada com mais cuidado. Quando ela é vaga, o módulo vira um recipiente elástico demais. Tudo parece caber nele. E, quando tudo parece caber, a fronteira começa a perder valor.

Um bom módulo tem uma responsabilidade que orienta inclusão e exclusão.

Ele ajuda a decidir não apenas o que deve entrar, mas também o que não deve entrar. Esse segundo ponto é essencial. Muita modularização falha não porque as pessoas não sabem colocar coisas dentro dos módulos, mas porque não sabem dizer “isso não pertence aqui”.

E arquitetura, muitas vezes, amadurece exatamente nesse gesto.

Dizer “não pertence aqui” é uma forma de proteger a clareza do sistema.

Quando um módulo aceita responsabilidades demais, ele cresce como uma miniatura do sistema inteiro. Ele começa coeso, depois absorve exceções, depois ganha regras laterais, depois passa a conhecer detalhes de outros módulos e, quando percebemos, ele se tornou um pequeno monólito interno.

Esse é um risco comum.

A modularidade não impede que um módulo vire uma bagunça. Ela apenas cria uma oportunidade de organização. Se a responsabilidade não for preservada, o módulo se degrada do mesmo jeito que qualquer outra estrutura.

Por isso, eu gosto de pensar em responsabilidade como uma espécie de pergunta recorrente:

essa decisão pertence mesmo a este módulo?

Não “este módulo consegue fazer isso?”. Não “é mais rápido colocar aqui?”. Não “já tem algo parecido aqui?”.

A pergunta é mais exigente: isso pertence aqui?

Essa diferença muda muita coisa.

Porque software aceita quase qualquer organização. Eu posso colocar uma regra em um lugar inadequado e ainda assim fazer o sistema funcionar. Posso chamar um módulo de outro diretamente. Posso reaproveitar uma classe interna porque estava à mão. Posso resolver uma urgência com uma dependência atravessada. O compilador talvez não reclame. Os testes talvez passem. O usuário talvez nem perceba.

Mas a arquitetura percebe.

E ela cobra depois.

O que muda junto deve ficar junto?

Uma das melhores heurísticas para pensar módulos é observar mudança.

Não apenas o estado atual do código, mas o modo como o sistema muda ao longo do tempo.

Eu gosto muito da pergunta: o que muda junto deve ficar junto? Ela é simples, mas carrega uma profundidade enorme. Porque módulo não é apenas uma fotografia da organização atual; ele também é uma aposta sobre evolução futura.

Se duas partes do sistema mudam quase sempre pelos mesmos motivos, talvez elas pertençam à mesma unidade modular. Se uma alteração em regra de pedido quase sempre exige alteração em cálculo de frete, talvez exista uma relação mais profunda ali que precisa ser entendida. Se um conjunto de classes sempre é alterado junto em toda demanda de catálogo, talvez o sistema esteja dizendo onde há uma responsabilidade comum.

Por outro lado, se duas partes estão juntas, mas mudam por motivos completamente diferentes, talvez o módulo esteja amplo demais. Se uma mudança em relatório exige mexer no mesmo módulo que concentra regras transacionais críticas, talvez responsabilidades distintas estejam misturadas. Se ajustes de interface, regra de negócio, persistência, integração externa e política operacional se atropelam dentro da mesma unidade, talvez o recorte esteja escondendo complexidade em vez de organizá-la.

Mudança revela arquitetura.

Às vezes, mais do que qualquer diagrama.

O histórico de alterações mostra onde as fronteiras fazem sentido e onde elas estão mal posicionadas. Mostra que partes do sistema têm afinidade real e quais estão apenas próximas por acidente. Mostra onde o acoplamento é natural e onde ele é resultado de conveniência.

Claro, essa heurística também precisa de cuidado. Nem tudo que muda junto deve obrigatoriamente virar o mesmo módulo. Há mudanças coordenadas por processo, por falta de abstração, por decisões ruins anteriores ou por acoplamentos indevidos. Se eu apenas olhar para o histórico sem interpretar o motivo da mudança, posso reforçar exatamente a estrutura que deveria corrigir.

Por isso, a pergunta completa deveria ser mais ou menos assim:

essas partes mudam juntas porque representam a mesma responsabilidade ou porque foram acopladas de forma ruim?

Essa diferença é decisiva.

Se elas mudam juntas porque fazem parte do mesmo conceito, da mesma capacidade ou da mesma regra, talvez faça sentido aproximá-las. Se mudam juntas porque uma conhece detalhes internos da outra, talvez o problema não seja falta de agrupamento, mas falta de fronteira.

É aqui que modularidade exige julgamento.

Não basta observar sintomas. É preciso interpretar causas.

Um sistema pode mostrar que pedido e pagamento mudam juntos frequentemente. Mas isso pode significar duas coisas diferentes. Pode significar que o domínio realmente trata pedido e pagamento como parte de uma mesma capacidade naquele contexto. Ou pode significar que a implementação misturou responsabilidades que deveriam ser separadas.

A arquitetura modular nasce justamente dessa investigação.

Ela não pergunta apenas “o que está junto?”. Ela pergunta “por que está junto?”. E também pergunta “deveria continuar junto?”.

Recorte por domínio

Um dos caminhos mais fortes para estruturar módulos é olhar para o domínio do problema.

Quando um sistema representa uma operação de negócio, é comum que certas áreas conceituais apareçam naturalmente. Em um e-commerce, por exemplo, posso enxergar catálogo, carrinho, pedidos, pagamentos, entrega, clientes, promoções, estoque, atendimento. Em um sistema financeiro, talvez apareçam contas, transações, limites, propostas, contratos, cobranças, conciliação. Em uma plataforma de conteúdo, talvez existam publicações, autores, comentários, moderação, assinatura, recomendação.

Esses nomes não são apenas nomes técnicos. Eles representam regiões de significado.

E módulos costumam ser mais fortes quando respeitam regiões de significado.

Isso acontece porque o software não muda no vazio. Ele muda porque o negócio muda, porque regras mudam, porque processos mudam, porque pessoas passam a enxergar o problema de outro jeito. Quando a estrutura do sistema acompanha minimamente essas regiões conceituais, a mudança tende a encontrar lugares mais naturais para acontecer.

Um módulo alinhado ao domínio ajuda o time a conversar melhor sobre o sistema. Ajuda a localizar regras. Ajuda a evitar que conceitos importantes fiquem espalhados. Ajuda a reduzir aquela sensação de que tudo é apenas “service”, “repository”, “controller” e “util”, sem uma organização que represente o problema real.

Mas aqui eu preciso fazer uma pausa importante.

Recortar por domínio não significa transformar qualquer substantivo do negócio em módulo.

Esse é um erro tentador.

Nem todo conceito merece uma fronteira modular própria. Alguns conceitos são pequenos demais. Outros são apenas atributos de algo maior. Outros ainda não têm autonomia suficiente para justificar um módulo. Se eu transformar cada palavra do domínio em uma caixa separada, posso criar uma arquitetura fragmentada, burocrática e difícil de navegar.

O domínio ajuda, mas não decide sozinho.

Ele precisa ser interpretado junto com responsabilidade, mudança, coesão e impacto. O fato de “cupom” existir como conceito no negócio não significa automaticamente que ele precise ser um módulo independente. Talvez cupom pertença a promoções. Talvez promoções pertença a comercial. Talvez, em outro contexto, cupom seja tão relevante, complexo e mutável que mereça um módulo próprio.

Depende.

E esse “depende” não é fuga. É parte da arquitetura.

A maturidade está em entender o peso real de cada conceito dentro daquele sistema específico.

Um bom recorte por domínio não busca representar o organograma inteiro do negócio nem criar uma taxonomia perfeita do mundo real. Ele busca encontrar fronteiras que ajudem o software a lidar melhor com regras, mudanças e entendimento.

Quando isso acontece, o módulo deixa de ser apenas um agrupamento técnico e passa a ser uma unidade conceitual útil.

Recorte por capacidade de negócio

Próximo do recorte por domínio, existe outro olhar que eu considero muito útil: pensar em capacidades de negócio.

Uma capacidade de negócio é algo que o sistema precisa ser capaz de realizar de forma reconhecível para gerar valor. Não é apenas uma entidade, nem apenas uma tela, nem apenas uma tabela. É uma capacidade operacional.

“Gerenciar pedidos” pode ser uma capacidade. “Processar pagamentos” pode ser uma capacidade. “Calcular elegibilidade de crédito” pode ser uma capacidade. “Publicar conteúdo” pode ser uma capacidade. “Moderar comentários” pode ser uma capacidade. “Emitir cobranças” pode ser uma capacidade.

Esse olhar é poderoso porque evita uma modularização excessivamente orientada a objetos isolados ou estruturas técnicas. Em vez de perguntar apenas “quais entidades existem?”, eu passo a perguntar “quais capacidades este sistema precisa sustentar?”.

Essa pergunta aproxima arquitetura de produto.

Ela ajuda a enxergar módulos como unidades que entregam comportamento relevante, e não apenas como agrupamentos de dados. Um sistema não existe para armazenar entidades. Ele existe para executar capacidades, sustentar processos, aplicar regras e permitir que o negócio opere.

Quando um módulo se alinha a uma capacidade, ele tende a concentrar regras e fluxos que fazem sentido juntos. Isso pode facilitar evolução, ownership, testes e compreensão. Também pode ajudar times a trabalharem de forma mais autônoma, porque a fronteira modular acompanha uma região de valor mais clara.

Mas, novamente, cuidado.

Capacidade de negócio não significa tela. Também não significa endpoint. Muito menos significa história de usuário isolada.

Uma tela pode usar várias capacidades. Uma capacidade pode atravessar várias telas. Uma história de usuário pode tocar várias partes do sistema. Um endpoint pode ser apenas uma porta de entrada para algo mais profundo.

Se eu modularizo apenas olhando para interface de usuário ou rotas externas, corro o risco de criar módulos que refletem a superfície do sistema, não sua estrutura real. E superfície muda muito. Telas mudam. APIs mudam. Fluxos de entrada mudam. O que eu quero proteger com modularidade costuma estar mais fundo: regras, responsabilidades, conceitos, decisões.

Por isso, recortar por capacidade exige olhar para o comportamento essencial, não apenas para a forma como ele aparece para o usuário.

A pergunta boa aqui é:

qual capacidade este módulo sustenta de ponta a ponta, e quais decisões precisam estar próximas para que essa capacidade seja compreendida e evoluída?

Quando essa resposta é clara, o módulo ganha força.

Recorte por fluxo

Outra forma de pensar módulos é observar fluxos.

Existem sistemas em que determinados processos atravessam várias etapas bem definidas. Aprovação de crédito. Onboarding de cliente. Fechamento de pedido. Liquidação financeira. Publicação de artigo. Análise de risco. Atendimento de chamado. Processamento de contrato.

Nesses casos, o fluxo pode revelar uma unidade importante de organização.

Um módulo orientado a fluxo pode fazer sentido quando o valor do sistema está na coordenação de etapas que pertencem a uma mesma jornada operacional. Em vez de espalhar a lógica do processo por várias partes desconectadas, o módulo concentra a compreensão daquele caminho.

Isso pode ser útil, especialmente quando o fluxo possui regras próprias, estados próprios, transições importantes, validações e decisões de negócio que precisam ser preservadas de forma coesa.

Mas aqui existe uma armadilha.

Nem todo fluxo deve virar módulo.

Às vezes, um fluxo é apenas uma composição temporária de capacidades de outros módulos. Às vezes, ele é uma orquestração de caso de uso, não uma responsabilidade estrutural própria. Às vezes, criar um módulo para cada fluxo gera duplicação, acoplamento e confusão, porque vários fluxos passam a reproduzir pedaços das mesmas regras.

Então, de novo, a pergunta não é “existe um fluxo?”. A pergunta é: esse fluxo representa uma responsabilidade durável do sistema?

Se representa, pode fazer sentido estruturar um módulo ao redor dele. Se não representa, talvez ele deva ser apenas uma coordenação entre módulos existentes.

Essa diferença é sutil, mas importante.

Um fluxo de checkout, por exemplo, pode tocar carrinho, pedido, pagamento, estoque e entrega. Isso não significa automaticamente que tudo deva ficar dentro de um módulo chamado checkout. Talvez checkout seja apenas uma orquestração de capacidades distintas. Mas, em outro sistema, o checkout pode ter tanta regra própria, tanta variação e tanta importância operacional que merece uma fronteira mais explícita.

Não existe resposta universal.

Existe análise de responsabilidade.

E, para mim, esse é o ponto que precisa voltar sempre: módulo bom não nasce porque encontrei uma palavra bonita. Ele nasce porque encontrei uma responsabilidade que merece ser protegida.

Compartilhar publicação

Interação social

Verificando sua sessão...

0 aplauso(s)

Carregando reações...

Comentários (0)

0/2000

Carregando comentários...