DEV Community

Cover image for Estilos arquiteturais: Monólito modular
Renan de Andrade
Renan de Andrade

Posted on

Estilos arquiteturais: Monólito modular

Por um bom tempo a palavra "monólito" pareceu ser sinônimo de algo velho, ultrapassado e que deveria acabar. O contrário era "microsserviços", que denotava algo que escala, moderno e altamente tecnológico.

Talvez eu esteja sendo dramático, mas essa onda de micro-serviços em tudo levou à utilização do padrão onde não era necessário, criando assim muita complexidade desnecessária e exigindo mais recursos humanos e monetários para lidar com as consequências dessa escolha.

O objetivo deste pequeno artigo é falar de um padrão não tão badalado, mas que é muito útil para se manter uma aplicação monolítica com a separação clara entre os contextos, sem virar uma big ball of mud. Esse padrão é o monolítico modular.

O padrão em si não tem muito segredo. Ele consiste em criar módulos coesos dentro da aplicação com um contrato claro entre os mesmos.

Separando os módulos

Por domínio

Via de regra, cada módulo representa um boundex context (lembra dele no DDD?), de forma que seus componentes internos sigam a linguagem ubíqua e as regras daquele contexto. Isso garante que cada módulo tenha o tamanho suficiente para ser autônomo e poder ser mantido por um time dedicado, se precisar.

Veja um exemplo na imagem a seguir:

Exemplo de aplicação com módulos separados por domínios

Por time/squad

Em alguns casos, embora não muito comum, pode-se refinar a separação dos módulos para refletir a organização das squads/times de trabalho.

Um ponto de atenção nesta abordagem é que em algumas empresas as squads se reorganizam de maneira dinâmica ou em um espaço curto de tempo. Em cenários assim não é interessante aplicar este refinamento.

Por fluxo de trabalho

Podem existir cenários também em que um determinado fluxo de trabalho de um dado módulo seja mais complexo, crítico ou necessite de mais atenção que os demais. Em casos assim é interessante extrair esse fluxo para um módulo separado. Isso facilita a criação de um serviço próprio para esse fluxo no futuro, se necessário.

Comunicação entre os módulos

Cada módulo expõe uma API pública que é utilizado pelos demais para chamar aquele contexto. Um módulo nunca deve acessar recursos internos de outro.

Isso garante que mudanças internas em um contexto não afete os demais. Apenas mudanças de contrato podem afetar, e devem ser feitas de forma controlada através de Breaking Changes e/ou versionamento - da mesma forma como se faz para clientes externos.

Casos de dependências cíclicas são um sinal de que talvez os módulos não tenham sido bem dimensionados.

Exemplo de comunicação entre os módulos

Eventos

São comuns situações em que um módulo "precisa saber" quando outro finalizou o processamento, ou precisa notificar vários outros módulos.

Para esses casos, um barramento interno de eventos pode ser extremamente útil. Geralmente casa-se esse barramento com o padrão outbox utilizando o próprio banco de dados da aplicação.

Barramento de eventos entre os módulos

Código comum

Ao implementar um monólito modular notamos que boa parte do código acaba sendo compartilhada pelos módulos, como libs de logger, gerador de IDs, libs de conexão com o banco e etc.

Para comportar esse código - que não implementa uma regra de negócio e não referencia nenhum domínio em específico - podemos ter um módulo compartilhado chamado plaftorm. Todos os módulos podem utilizar o código que ele expõe, mas ele não deve depender de nenhum módulo.

Exemplo de monólito com o platform

Separação em diferentes serviços

Existe uma ideia um pouco equivocada de que esse estilo arquitetural é apenas um modelo de transição para um modelo de microsserviços, por exemplo. Mas na verdade o recomendado é manter uma aplicação perfeitamente funcional e gerando valor como um monólito modular até surgir a necessidade de quebrá-la em serviços.

Quando essa necessidade aparece, a divisão ocorre de forma natural e quase "indolor", dado que já existe fronteiras bem definidas entre os módulos da aplicação.

Monólito modular separado em serviços

Conclusão

Este foi um post rápido com os conceitos-chave deste estilo arquitetural. Em breve pretendo trazer um artigo mostrando como implementar na prática uma aplicação seguindo esse padrão.

tmj!

Top comments (0)