Nos últimos anos, a arquitetura de software tem visto uma variedade de abordagens para lidar com a crescente complexidade e escalabilidade das aplicações. Entre monolitos e microsserviços e macrosserviços, uma nova abordagem, o monolito modular, se apresenta como uma solução poderosa para manter a simplicidade, modularidade e manutenibilidade de um sistema enquanto permite um futuro crescimento mais estruturado.
Neste artigo, vamos explorar o que são monolitos modulares, suas vantagens, quando devem ser usados, e como a técnica de estrangulamento de monolitos pode ser uma ferramenta valiosa para evoluir sistemas antigos para uma arquitetura moderna.
O que é um Monolito Modular?
Um monolito modular é uma arquitetura onde a aplicação é desenvolvida em uma única base de código, mas dividida em módulos bem definidos e isolados logicamente. Embora a aplicação ainda funcione como um único artefato de deploy, esses módulos encapsulam responsabilidades específicas, o que torna o código mais organizado, fácil de manter e preparar para uma possível migração futura para microsserviços, se necessário.
Diferente de um monolito tradicional, onde as partes da aplicação estão altamente acopladas e frequentemente difíceis de separar, o monolito modular tem uma arquitetura mais organizada, o que facilita a manutenção, teste e até a escalabilidade.
Principais Características de um Monolito Modular
- Modularidade Interna: Cada módulo é responsável por uma parte específica da aplicação, como “usuários”, “pagamentos” ou “relatórios”, com interfaces bem definidas para comunicação entre eles. Isso permite um isolamento lógico dentro do monolito.
- Deploy Unificado: Apesar da separação em módulos, o monolito modular é implementado como uma unidade única. Isso significa que todas as mudanças são feitas em um único artefato de deploy, o que simplifica o processo em termos de pipelines de integração contínua.
- Facilidade de Manutenção e Desenvolvimento: A modularidade interna facilita a organização do código e a distribuição de tarefas entre os times de desenvolvimento, reduzindo a complexidade de alterar ou estender funcionalidades.
- Preparação para Escalabilidade: Embora ainda seja um monolito, a separação lógica em módulos permite uma transição gradual para uma arquitetura de microsserviços, se e quando o sistema exigir uma escalabilidade maior.
Quando usar um Monolito Modular?
O monolito modular é ideal para projetos que ainda não necessitam de toda a complexidade e custos de operação de uma arquitetura de microsserviços, mas que, ao mesmo tempo, precisam de uma organização de código mais robusta do que um monolito tradicional. Alguns cenários comuns em que o monolito modular se destaca são:
- Equipes pequenas ou médias: Para times que precisam manter a simplicidade de deploy e operação, mas querem evitar os desafios de escalar e manter um grande monolito tradicional.
- Projetos em estágio inicial: No início, quando a aplicação ainda está crescendo e a equipe está iterando rapidamente, um monolito modular oferece flexibilidade para evoluir sem a complexidade dos microsserviços.
- Organização de código: Se a base de código começar a crescer descontroladamente, modularizar o monolito pode trazer ordem e clareza, tornando-o mais fácil de manter.
Como funciona a persistencia a dados de um Monolito Modular?
Geralmente um monolito modular utiliza um único banco de dados compartilhado por todos os módulos da aplicação. No entanto, o acesso ao banco de dados é organizado de forma a refletir a separação lógica dos módulos. Cada módulo tem suas próprias tabelas e, idealmente, não acessa diretamente as tabelas dos outros módulos, o que ajuda a manter a coesão e a evitar o acoplamento indesejado. Existem alguns motivos na qual a centralização de dados em um único banco de dados acontece:
- Simplicidade Operacional: Manter um único banco de dados é mais simples em termos de configuração, backup, e gerenciamento. Em uma arquitetura monolítica, essa abordagem reduz a complexidade da infraestrutura.
- Consistência Transacional: Com um banco de dados único, a aplicação pode gerenciar transações complexas que envolvem múltiplos módulos de maneira mais simples e direta, sem precisar lidar com coordenação distribuída.
- Facilidade de Escalabilidade Horizontal: Em um monolito modular, pode-se optar por escalar o banco de dados e a aplicação juntos, o que é mais direto do que configurar múltiplos bancos de dados independentes para cada módulo.
Alternativas e Considerações
Alguns monolitos modulares podem adotar uma estratégia de dividir o banco de dados logicamente, criando esquemas separados para cada módulo ou definindo permissões para restringir o acesso direto entre módulos. Essa divisão lógica é benéfica para manter a organização dos dados e pode facilitar uma futura migração para uma arquitetura distribuída. No entanto, a maioria dos monolitos modulares, na prática, ainda centraliza o armazenamento em um único banco de dados, o que simplifica a administração e manutenção no curto e médio prazo.
Em que ele é diferente do Monolito convencional?
A principal distinção entre o monolito convencional e o monolito modular é que o último é feito de módulos bem definidos, independentes e extraíveis, cada um dos quais possui um certo limite de capacidade de negócios. Quando os módulos crescem em tamanho e complexidade, exigindo diferentes recursos e implantação, fica mais fácil migrar para a arquitetura de microsserviços porque:
- Ele já especifica o limite ideal de um microsserviço do ponto de vista de design orientado a domínio
- Cada módulo pode ser um candidato independente de microsserviços no futuro
- As interfaces podem evoluir posteriormente como contratos entre microsserviços implantados de forma independente
O problema do Crescimento: Quando o Monolito Modular Encontra Limites
Embora os monolitos modulares sejam eficientes em muitos cenários, há momentos em que uma aplicação começa a crescer além dos limites da arquitetura monolítica, mesmo modular. Isso pode acontecer quando:
- A escalabilidade de um único módulo se torna um gargalo. Por exemplo, a parte de “pagamentos” de um e-commerce pode ter uma demanda muito maior do que o restante do sistema, mas a arquitetura monolítica obriga o sistema inteiro a ser escalado junto.
- A equipe de desenvolvimento cresce, e diferentes times precisam trabalhar de forma mais independente, tornando mais difícil coordenar mudanças em uma base de código unificada.
- Necessidade de deploy contínuo de partes específicas do sistema sem afetar outras. Em um monolito, qualquer mudança em um módulo exige o redeploy de toda a aplicação, o que pode levar a interrupções.
É nesse ponto que a estratégia de estrangulamento de monolitos entra em cena.
Se tomarmos o exemplo de um sistema de e-commerce típico ilustrado acima, cada hexágono representa um módulo. Cada módulo poderá funcionar de maneira independente depois, de maneira temporária ou definitiva.
Estrangulamento de Monolitos: Uma abordagem para a Evolução
O estrangulamento de monolitos é uma técnica que permite migrar gradualmente de um monolito para uma arquitetura de serviços, sem precisar reescrever toda a aplicação de uma vez. O termo vem de uma metáfora usada por Martin Fowler, onde ele descreve o processo como “estrangular” o monolito aos poucos, extraindo funcionalidades críticas para serviços independentes até que o monolito original seja gradualmente desativado.
Como funciona o estrangulamento de monolitos em um monolito modular?
- Identificação de Módulos Críticos: O primeiro passo é identificar quais módulos dentro do monolito modular estão criando gargalos ou necessitam de maior independência. Esses módulos podem estar sobrecarregando o sistema ou precisando de uma escalabilidade específica, como a funcionalidade de pagamentos em um e-commerce.
- Extração Gradual: Depois de identificar os módulos críticos, eles são extraídos do monolito para se tornarem serviços independentes (geralmente microsserviços ou macroservices). Isso é feito de forma gradual, mantendo o restante da aplicação no monolito.
- Redirecionamento de Tráfego: Assim que o módulo é extraído e funcionando como um serviço separado, o tráfego de requisições que anteriormente era gerenciado pelo monolito passa a ser redirecionado para o novo serviço. Isso pode ser feito por meio de proxies ou outros métodos de roteamento.
- Desativação do Monolito: Conforme mais módulos são extraídos e estrangulados, o monolito vai sendo desativado aos poucos. Ao final do processo, todo o monolito pode ser desmontado, transformando-se em uma arquitetura de serviços mais distribuída.
Vantagens do Estrangulamento de Monolitos
- Transição Gradual: Não há necessidade de uma reescrita completa da aplicação, o que minimiza os riscos e o tempo de inatividade.
- Foco nos Problemas Críticos: A extração de módulos pode ser focada nas áreas do sistema que realmente precisam de maior escalabilidade ou independência, evitando sobrecarga desnecessária em partes menos críticas.
- Redução de Riscos: Como o processo é incremental, qualquer problema ou erro durante a extração de um módulo pode ser identificado rapidamente e corrigido, sem comprometer a estabilidade de toda a aplicação.
Quando migrar para microsserviços?
Quando a escalabilidade é um fator crítico
Se os diferentes módulos precisarem ser escalonados de forma diferente, microsserviços podem ser uma escolha melhor. Com microsserviços, é mais fácil escalonar serviços individuais de forma independente, permitindo um controle mais granular sobre o aplicativo.
Quando a equipe cresce
Se a equipe de desenvolvimento for grande, levando a uma complexidade crescente, é hora de fazer a mudança. Com microsserviços, cada serviço pode ser desenvolvido e testado de forma independente, permitindo melhor colaboração entre as equipes.
Quando você precisa de tecnologia diversificada
Se houver uma situação em que diferentes partes do aplicativo exijam diferentes tecnologias/linguagens, microsserviços são o caminho a seguir. Com microsserviços, cada serviço pode usar sua própria pilha de tecnologia, permitindo maior flexibilidade no processo de desenvolvimento.
Quando você tem uma compreensão firme do domínio complexo
Quando você tiver alcançado um bom entendimento do domínio, incluindo seus múltiplos subsistemas, a arquitetura de microsserviços pode ajudar a encapsular e gerenciar a complexidade. Ao dividir o sistema em serviços menores e especializados, o aplicativo será mais fácil de manter e evoluir ao longo do tempo.
Conclusão
O monolito modular é uma solução poderosa para manter a simplicidade, modularidade e eficiência em sistemas de médio porte. Ele oferece uma excelente organização do código, facilita a manutenção e reduz a complexidade inicial que normalmente seria associada a microsserviços. No entanto, conforme o sistema cresce, pode ser necessário evoluir para uma arquitetura mais escalável, e é aí que a técnica de estrangulamento de monolitos se torna fundamental.
Ao migrar gradualmente partes do sistema para serviços independentes, você pode garantir uma transição suave para uma arquitetura mais moderna e escalável, evitando os riscos de uma reescrita completa. Com isso, você obtém o melhor dos dois mundos: a simplicidade de um monolito modular e a flexibilidade de uma arquitetura de serviços distribuídos.