Artigos de Tecnologia e Negócios > Programação

Transformando um Monólito em um Monólito Modular

João Victor
João Victor

Quando se desenvolve em Java, Um dos problemas mais famosos está relacionado ao Classpath, que nada mais é do que uma coleção das classes compiladas que são disponibilizadas nos JARs utilizados pela aplicação. Em tempo de execução, a JVM irá carregar essas classes de maneira dinâmica, ou seja, apenas quando forem solicitadas.

O problema é que não temos garantia que existe apenas uma versão de uma classe nos JARs disponíveis no Classpath ou ainda que a classe carregada é exatamente a que nós precisamos. Isso pode ocasionar uma série de erros, comumente conhecidos como JAR Hell.

A solução veio na JDK 9 com o JPMS (Java Platform Module System). Com o novo sistema de módulos, temos melhoras significativas, pois ao trabalhar com o Module-Path, classes, interfaces, arquivos e dependências ficam vinculadas a um módulo, evitando assim falhas que tínhamos com o Classpath.

Além dessa vantagem, temos uma melhora significativa no encapsulamento das APIs, pois agora tem-se a opção de exportar apenas o que o usuário poderá acessar de cada módulo.

A ideia desse artigo é mostrar, de forma prática, o passo a passo da transformação do Monólito Caelum Eats para um Monólito Modular e deixar claro as vantagens citadas acima.

Antes de iniciar a modularização do projeto, vamos à apresentação do nosso Monólito. O Caelum Eats é uma aplicação de entrega de comida nos moldes de soluções conhecidas no mercado. Basicamente trabalha com 3 perfis de usuários: o cliente, o dono do restaurante e o administrador do sistema. O backend é implementado usando as seguintes tecnologias:

O Monólito já está componentizado com módulos Maven, como podemos ver a seguir no pom.xml:

<modules>
    <module>eats-administrativo</module>
    <module>eats-pagamento</module>
    <module>eats-restaurante</module>
    <module>eats-pedido</module>
    <module>eats-distancia</module>
    <module>eats-seguranca</module>
    <module>eats-application</module>
</modules>

Você pode estar se perguntando o porquê de usarmos o JPMS quando já estamos utilizando os módulos Maven. Bom, o módulo Maven não vai resolver o problema do encapsulamento do nosso código. Por exemplo, qualquer outro módulo pode acessar qualquer uma das classes do módulo eats-administrativo, mesmo as de uso interno.

Começando com JPMS

Agora que conhecemos a estrutura do nosso Monólito, vamos colocar a mão na massa e modularizar o nosso projeto. É importante ressaltar que existem várias maneiras de se definir a estratégia dos módulos da aplicação. Uns preferem dividir por camadas, outros por regras de negócio, mas a realidade é que isso vai depender do projeto. Vamos continuar usando a divisão por regras de negócio, que já estava definida no pom.xml raiz.

Vamos criar o arquivo module-info.java para cada módulo Maven, pois é nele que estarão todas as informações referentes ao módulo JPMS. A IDE facilita esse trabalho para nós. No Eclipse, clicando com o botão direito em cima do subprojeto eats-administrativo, pode-se usar o seguinte caminho: Configure - Create module.info.java. O arquivo virá com algumas informações, mas não necessariamente com todas que precisamos.


module br.com.caelum.eats.administrativo { 
        exports br.com.caelum.eats.administrativo.dto;
exports br.com.caelum.eats.administrativo.controller;
    exports br.com.caelum.eats.administrativo.entidade;

    requires java.persistence;
    requires java.validation;
    requires spring.data.commons;
    requires spring.data.jpa;
    requires spring.web;
}

Neste arquivo, existem novas palavras reservadas. Vamos analisar cada uma delas:

A criação do module-info.java deve ser feita para os módulos eats-pagamento, eats-restaurante, eats-pedido, eats-distancia, eats-seguranca e eats-application. O conteúdo do arquivo será semelhante.

E agora? Finalizamos?

Modularizar uma aplicação não é uma atividade trivial, ainda mais quando se usa uma quantidade considerável de frameworks. Um detalhe que não foi falado é que quando usamos módulos, automaticamente estamos fechados para reflection e o Spring usa bastante este recurso. Para o nosso sistema funcionar, teremos que fazer mais algumas configurações nos arquivo module-info de cada módulo:

module br.com.caelum.eats.administrativo {
        //resto do código oculto
    opens br.com.caelum.eats.administrativo.entidade to 
org.hibernate.orm.core, spring.core,
org.hibernate.validator;
    opens br.com.caelum.eats.administrativo.controller to 
        spring.context, spring.core, spring.beans;
}

E aqui vemos mais duas novas palavras reservadas. Vamos lá:

De maneira semelhante, nos arquivos module-info de outros módulos, devemos abrir os pacotes relevantes para os módulos dos frameworks que os utilizam.

Um module-info interessante é o do módulo br.com.caelum.eats:

**open** module br.com.caelum.eats {
        //resto do código oculto
} 

Se vocês perceberem, ao invés de usar o opens por pacote, como no exemplo anterior, é utilizado o open no módulo. Com este recurso, estou abrindo todos os pacotes do módulo para reflexão e sem definição de quais outros módulos poderão fazer tal ação.

Devemos fazer isso porque, ao utilizarmos o Flyway, uma ferramenta de migração de Bancos de Dados, disponibilizamos as migrations no diretório de recursos (src/resources/migration), e não é possível fazer um opens nesse diretório para que o Flyway ache as migrations. Logo a opção foi deixar todo o módulo aberto. Obs: aqui aceito uma sugestão de como fazer para abrir o diretório de migrations para o Flyway.

eats-application
└── src
        └── resources
            ├── application.properties
            └── db
                └── migration
                    ├── V0001__cria-tabelas-user-e-role.sql
                    ├── V0002__cria-tabela-tipo-de-cozinha.sql
                    ├── V0003__cria-tabela-forma-de-pagamento.sql
                    └── V0004__cria-tabela-restaurante.sql

A partir de agora, nossa aplicação está pronta para uso, porém ainda podemos realizar algumas melhorias para tirar proveito de todas as vantagens do JPMS. No momento de fazer os exports também podemos usar o to e informar que apenas alguns módulos específicos poderão usar as classes do pacote exposto. O module-info do módulo Administrativo ficaria assim:

module br.com.caelum.eats.administrativo { 
        exports br.com.caelum.eats.administrativo.dto to
            br.com.caelum.eats.distancia,
            br.com.caelum.eats.pagamento, 
            br.com.caelum.eats.restaurante;
//resto do código oculto
}

Prontos(as) para ver a aplicação funcionando?

Bom, agora que configuramos todos os nossos módulos, precisamos realizar as últimas configurações para executarmos a aplicação. No pom.xml do módulo eats-application, que contém a classe com o método main. É necessário incluir alguns plugins do Maven.

O maven-jar-plugin informa que as classes compiladas estarão disponíveis no diretório /modules:

<plugin>
    <artifactId>maven-jar-plugin</artifactId>
        <configuration>
            <outputDirectory>
    ${project.build.directory}/modules
</outputDirectory>
        </configuration>
</plugin>

O `maven-dependency-plugin`` informa que, no momento do empacotamento, as dependências dos projetos irão ser copiadas, também, para o diretório /modules, pois serão utilizadas em tempo de execução.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>
            <configuration> 
<outputDirectory>
    ${project.build.directory}/modules
</outputDirectory>
                <includeScope>runtime</includeScope>
            </configuration>
        </execution>
    </executions>
</plugin>

Feitos estes passos, estamos prontos para ver a aplicação funcionando.

Na raiz do projeto vamos executar o comando:

mvn install

Se não tivermos nenhum problema, o resultado será o apresentado abaixo:

imagem do código desenvolvido pelo autor

Agora, no diretório /eats-application, vamos executar o comando:

java --add-modules java.instrument
--module-path=target/modules
--module br.com.caelum.eats/br.com.caelum.eats.EatsApplication

As opções do comando anterior:

Se tudo deu certo, vamos ver a aplicação iniciada:

Started EatsApplication in 14.332 seconds (JVM running for 15.51)

Neste artigo, a ideia era mostrar o passo a passo de como fizemos para modularizar a nossa aplicação. O resultado final vocês podem ver em: https://github.com/joao0212/caelum-eats-modular.

Obviamente aplicações diferentes exigem estratégias diferentes, mas o conhecimento adquirido aqui servirá de base para aplicá-los em outros cenários. Aqui na Alura nós temos o curso Novidades do Java: Produtividade com novos recursos que tem uma aula sobre Java modular.

Bom, chegamos ao fim do nosso artigo e espero que vocês tenham gostado do resultado. Se quiserem expor suas críticas e sugestões, podem me chamar twitter ou no linkedin que ficarei feliz em respondê-los. Até a próxima!

Artigos de Tecnologia e Negócios > Programação

Cursos profissionais de Programação é na Alura, comece agora!

  • 1184 cursos

    Cursos de programação, UX, agilidade, data science, transformação digital, mobile, front-end, marketing e infra.

  • Certificado de participação

    Certificado de que assistiu o curso e finalizou as atividades

  • App para Android e iPhone/iPad

    Estude até mesmo offline através das nossas apps Android e iOS em smartphones e tablets

  • Projeto avaliado pelos instrutores

    Projeto práticos para entrega e avaliação dos professores da Alura com certificado de aprovação diferenciado

  • Acesso à Alura Start

    Cursos de introdução a tecnologia através de games, apps e ciência

  • Acesso à Alura Língua

    Reforço online de inglês e espanhol para aprimorar seu conhecimento

Premium

  • 1184 cursos

    Cursos de programação, UX, agilidade, data science, transformação digital, mobile, front-end, marketing e infra.

  • Certificado de participação

    Certificado de que assistiu o curso e finalizou as atividades

  • App para Android e iPhone/iPad

    Estude até mesmo offline através das nossas apps Android e iOS em smartphones e tablets

  • Projeto avaliado pelos instrutores

    Projeto práticos para entrega e avaliação dos professores da Alura com certificado de aprovação diferenciado

  • Acesso à Alura Start

    Cursos de introdução a tecnologia através de games, apps e ciência

  • Acesso à Alura Língua

    Reforço online de inglês e espanhol para aprimorar seu conhecimento

12X
R$75
à vista R$900
Matricule-se

Premium Plus

  • 1184 cursos

    Cursos de programação, UX, agilidade, data science, transformação digital, mobile, front-end, marketing e infra.

  • Certificado de participação

    Certificado de que assistiu o curso e finalizou as atividades

  • App para Android e iPhone/iPad

    Estude até mesmo offline através das nossas apps Android e iOS em smartphones e tablets

  • Projeto avaliado pelos instrutores

    Projeto práticos para entrega e avaliação dos professores da Alura com certificado de aprovação diferenciado

  • Acesso à Alura Start

    Cursos de introdução a tecnologia através de games, apps e ciência

  • Acesso à Alura Língua

    Reforço online de inglês e espanhol para aprimorar seu conhecimento

12X
R$100
à vista R$1.200
Matricule-se

Max

  • 1184 cursos

    Cursos de programação, UX, agilidade, data science, transformação digital, mobile, front-end, marketing e infra.

  • Certificado de participação

    Certificado de que assistiu o curso e finalizou as atividades

  • App para Android e iPhone/iPad

    Estude até mesmo offline através das nossas apps Android e iOS em smartphones e tablets

  • Projeto avaliado pelos instrutores

    Projeto práticos para entrega e avaliação dos professores da Alura com certificado de aprovação diferenciado

  • Acesso à Alura Start

    Cursos de introdução a tecnologia através de games, apps e ciência

  • Acesso à Alura Língua

    Reforço online de inglês e espanhol para aprimorar seu conhecimento

12X
R$120
à vista R$1.440
Matricule-se
Procurando planos para empresas?
Acesso por 1 ano
Estude 24h/dia onde e quando quiser
Novos cursos toda semana