Cursos que formaram meu caráter: Utilizando Gradle ao invés de Maven
Tags: gradle, groovy, maven, quarkus
Published: 2022-12-12 20:01:24

---
title: Cursos que formaram meu caráter: Utilizando Gradle ao invés de Maven
published: true
description: O que aprendi com cursos realizados e como apliquei outras técnicas conhecidas para evoluí-los
tags: gradle, groovy, maven, quarkus
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m8uazy3rfnxc4ha6mn6r.jpg
# published_at: 2022-12-12 14:00 +0000
---

> "Pois as coisas que temos de aprender antes de podermos fazê-las, aprendemos fazendo-as." Aristóteles

Nesse segundo posts falaremos sobre o [Gradle](https://gradle.org/), uma ferramenta de automação que ajuda no gerenciamento de ciclo de vida de projetos. Vantagens, desvantagens e motivos que me fizeram mudar o projeto de [Maven](https://maven.apache.org/) para Gradle.

Esse artigo faz parte de uma série, abaixo é possível encontrar a [lista completa de artigos](#serie_completa).

Estamos nos baseando no curso [Desenvolvimento web com Quarkus](https://www.udemy.com/course/des-web-quarkus) do @viniciusfcf.

O repositório em que estamos nos baseando é:

{% embed https://gitlab.com/arthurfnsc-udemy/desenvolvimento-web-quarkus/ifood/ %}

---

## Gradle 101 — History so far…

Como a maioria dos desenvolvedores Java que conheço, iniciei minha vida utilizando o **Maven**. Eu ficava maravilhado com todo aquele **XML** que eu poderia utilizar para gerenciar meu projeto.

![Sarcasm](https://dev-to-uploads.s3.amazonaws.com/i/7q4qb7nwicymex0yb764.jpg)

Foi então que em 11 de Novembro de 2016, um commit simples foi um marco fundamental na minha carreira:

> “Atualização de arquitetura de projeto para Gradle”

Naquela época eu trabalhava em um instituto de pesquisas, o [IBTI](https://www.ibti.org.br/), e @felipebelluco uma vez veio me perguntar se eu estava a fim de conhecer "umas coisas diferenciadas".

Ele trabalhava com Android, mas me falou que era possível utilizar **Gradle** em projetos de backend. Em um instituto de pesquisas o que você tem que fazer é experimentar coisas, e lá fui eu; algo semelhante ao que escrevi em um post sobre [Paul Arden e experimentar coisas novas](https://dev.to/arthurfnsc/paul-arden-pensando-ao-contrario-parte-2-experimentando-coisas-novas-mesmo-nao-gostando-inicialmente-35kc).

Parti da seguinte premissa: se isso vai "substituir" o **Maven**, precisa fazer o que ele faz; então, de posse de um projeto **Maven** criei um **build.gradle** e tentei a compilação do projeto até que ele funcionasse como funcionava o meu **pom.xml**.

Na real, para a galera não vir aqui falando que eu sou “modinha”, meu ponto é basicamente o seguinte: é mais que obrigação de alguém que chega depois e, estuda os problemas que um dado player resolve, analisar os gaps e se propor a fazer melhor.

A timeline de ferramentas de gerenciamento de ciclo de vida de projetos no mundo Java foi mais do que uma troca entre **Maven** e **Gradle**, e pode ser detalhada como:

* 2000 — **Another Neat Tool** (sim… a formiguinha ([ANT](https://ant.apache.org/)) é só um acrônimo… obrigado, de nada)
* 2002 — Maven
* 2005 — [Ivy](https://ant.apache.org/ivy/)
* 2007 — [Gant](https://github.com/codehaus/gant) (Sim… tentaram reviver o ANT)
* 2007 — Gradle

![Influência Gradle](https://dev-to-uploads.s3.amazonaws.com/i/kjvh6eb71rmlrtw4ul1g.png)

Não consegui achar de onde peguei a imagem, mas creio que foi do próprio **Gradle** em uns treinamentos gratuitos deles que eu fiz, que **são muito bons, diga-se de passagem**.

{% embed https://gradle.com/training/ %}

É muito fácil olhar para o **Maven** hoje e pensar que existem outras formas de fazer as coisas. Para o problema que tínhamos, o **Maven** era e continua sendo uma excelente solução.

E que problema era esse? 

Como versionar dependências que usamos no projeto para não ficarmos com projetos grandes demais (imagina versionar os **JARs** de um projeto...)? Além disso, como criar nossos scripts para facilitar isso?

**XML** tinha a vantagem de manter uma estrutura baseada em um **XML Schema Definition** (**XSD**) para a gente. Com isso, aproveitamos da vantagem de padronização de estrutura proporcionada pelo nosso arquivo **pom.xml**

Para quem não sabe, aquelas primeiras linhas do **pom.xml** são muito importantes por definirem a estrutura do nosso arquivo.

```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
</project>
```

Já pensou em seguir o seguinte link [https://maven.apache.org/xsd/maven-4.0.0.xsd](https://maven.apache.org/xsd/maven-4.0.0.xsd) do **schemaLocation**?

{% embed https://giphy.com/gifs/stress-i-need-a-drink-brain-explode-2rqEdFfkMzXmo %}

Nesse arquivo você consegue ver cada tag do **pom.xml**, bem como a quantidade mínima e máxima de repetições delas e que outras tags podem ser contidas dentro.

Nesse ponto, cheguei à conclusão que a discussão entre **Maven** e **Gradle** depende de uma série de fatores. Ainda que o **Gradle** tenha uma página dedicada apenas a essa comparação, outros fatores também são importantes para a decisão: profissionais que trabalham com cada uma das frentes, como definir uma arquitetura corporativa, quantidade de plugins, dentre outras.

{% embed https://gradle.org/maven-vs-gradle/ %}

Já conversei com arquitetos que não viam vantagem de poder programar em ferramentas de build, com o **Gradle**. Hoje é possível ter essa parte em **Groovy** ou **Kotlin**.

Enfim… creio que fica muito mais como uma escolha de cada um… nesse post a ideia é mostrar as vantagens de se aplicar **Gradle** no nosso projeto, e como pensei para fazê-lo.

E para quem acha que o **Gradle** está restrito à **JVM**, segue a seguinte informação do [próprio site deles](https://gradle.org/):

> Write in Java, C++, Python or your language of choice. Package for deployment on any platform. Go monorepo or multi-repo. And rely on Gradle’s unparalleled versatility to build it all.


---

## Gradle ao invés de Maven, o que muda?

### Wrapper

**gradlew** e **gradlew.bat**, esses são dois caras que muitas pessoas têm em seus projetos e não sabem para que servem. Para quem usa **Maven** temos o **mvnw** e o **mvnw.cmd** também.

O projeto foi concebido para que a instalação do **Gradle fosse opcional**, para tanto, é possível rodar as configurações do projeto após instalação do Java pelos arquivos **gradle.bat** em sistemas **Windows** e **gradlew** em sistemas **Unix**, que interagem com o arquivo **gradle-wrapper.jar** contido na pasta **gradle/wrapper** na raiz do projeto.

No arquivo **build.gradle** na raiz do projeto é possível encontrar o seguinte bloco de código:

```groovy
wrapper {
    gradleVersion = "$gradleWrapperVersion"
}
```

**$gradleWrapperVersion** refere-se a uma variável do projeto escrita no arquivo **gradle.properties**, neste caso, a versão que estamos usando é a **7.6**. Caso haja uma alteração de versão no **Gradle** é possível alterar a variável **$gradleWrapperVersion** e executar o seguinte comando:

```sh
foo@bar:~$ ./gradlew wrapper
```

Isso atualizará o **gradle-wrapper.jar** contido na pasta **gradle/wrapper**.

### Variáveis de projeto

A utilização de variáveis de projeto vão estar presentes em todo o projeto, desde plugins:

```groovy
plugins {
    id "com.diffplug.spotless" version "$spotlessVersion" apply false
    id "com.github.ben-manes.versions" version "$versionsVersion" apply false
    id "java"
    id "org.openapi.generator" version "$openApiGenVersion" apply false
    id "org.owasp.dependencycheck" version "$dependencyCheckVersion" apply false
}
```

Até dependências:

```groovy
dependencies {
    implementation enforcedPlatform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}")
    annotationProcessor "org.mapstruct:mapstruct-processor:$mapstructVersion"
    implementation libs.mapstruct
    implementation libs.quarkus
    testImplementation libs.test
}
```

### Agrupando dependências

O **Gradle** possui um mecanismo bem interessante de reaproveitamento de código, como por baixo possuímos uma linguagem de programação, no nosso caso, usei o [Groovy](https://groovy-lang.org/), mas já é possível usar o [Kotlin](https://kotlinlang.org/) (apesar de eu ainda não ter visto grande vantagem em mudar de Groovy para Kotlin, mas isso vai ser tema para outro post, quando eu experimentar substituir o Groovy por Kotlin em um novo projeto).

```groovy
ext.libs = [
    quarkus  : [
        "io.quarkus:quarkus-arc",
        "io.quarkus:quarkus-config-yaml",
        "io.quarkus:quarkus-flyway",
        "io.quarkus:quarkus-jdbc-postgresql",
        "io.quarkus:quarkus-smallrye-openapi"
    ],
    mapstruct: [
        "org.mapstruct:mapstruct:$mapstructVersion"
    ],
    test     : [
       "com.approvaltests:approvaltests:$approvalTestsVersion",
        "com.google.code.gson:gson",
        "io.quarkus:quarkus-junit5",
        "io.rest-assured:rest-assured",
        "org.testcontainers:postgresql:$testcontainersVersion",
        "stax:stax:$staxVersion"
    ]
]
```

Desta forma é possível fazer o import de bibliotes da seguinte forma:

```groovy
dependencies {
    ...
    implementation libs.mapstruct
    implementation libs.quarkus
    testImplementation libs.test
}
```

Sabe aqueles imports que você precisava escrever linhas e linhas com o mesmo **groupId** e **version**? Pois bem, essa acho uma solução bem elegante para o problema; ela é uma evolução de uma outra abordagem que eu usava antes:

```groovy

ext {
    kotlinVersion = '1.3.31'
    kotlinArtifacts = [
        'kotlin-allopen',
        'kotlin-noarg',
        'kotlin-gradle-plugin'
    ]
}

dependencies {
    kotlinArtifacts.each {
        a-> implementation "org.jetbrains.kotlin:$a:$kotlinVersion"
    }
}
```

No exemplo acima estamos fazendo um **forEach** para cada artefato contido no **Array kotlinArtifacts** e utilizando o **implementation** com o mesmo **groupId org.jetbrains.kotlin** (vantagens de se utilizar uma linguagem de programação).

Nesse segundo exemplo é possível ver uma coisa bem interessante, a diferença entre **aspas simples** e **aspas duplas** para o **Groovy**. Resumindo, com aspas duplas é possível fazer interpolação de String, e com isso fazer a substituição da variável **$kotlinVersion** quando da implementation de um artefato. Teríamos algo como o seguinte ao final do nosso **forEach**:

```groovy
implementation "org.jetbrains.kotlin:kotlin-allopen:1.3.31"
implementation "org.jetbrains.kotlin:kotlin-noarg:1.3.31"
implementation "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.31"
```

### Definições externas

Uma das coisas que acho mais fera no **Gradle** é a possibilidade de separar configurações em mais de um lugar, utilizando o princípio de [Separation of Concerns](https://en.wikipedia.org/wiki/Separation_of_concerns) e o [Simple Responsability Principle](https://en.wikipedia.org/wiki/Single-responsibility_principle).

```groovy
subprojects {
    if (it.name != 'applications') {
        apply plugin: "java"
        apply from: "$rootDir/plugins/java.gradle"
        apply from: "$rootDir/plugins/docs.gradle"
        apply from: "$rootDir/plugins/lint.gradle"
        apply from: "$rootDir/plugins/mapstruct.gradle"
        apply from: "$rootDir/plugins/security.gradle"
        ...
    }
}
```

Dentro da raiz do projeto é possível perceber a pasta **plugins**, lá estão definidas as configurações que estou usando referentes a Java, documentação de projeto, Lint, MapStruct e segurança. Em postagens futuras falaremos sobre cada um deles.

O **build.gradle** fica muito mais limpo.

### Multi project Gradle

Como no **Maven**, é possível trabalhar com multi-projetos no **Gradle**. Particularmente nesse ponto acho o **Maven** um pouco melhor, bem como na parte de definição de **Parent-Project**.

O grande pulo do gato para o **Gradle** vai estar no arquivo **settings.gradle**.

```groovy
rootProject.name = "ifood"

include "applications:cadastro"
include "applications:marketplace"
include "applications:pedido"
```

Preferi agrupar todos os projetos dentro de uma pasta chamada **applications**. Como utilizo outras pastas para configurações (configs) e plugins, achei melhor agrupar uma pasta com os códigos em Java.

Essa configuração já é o suficiente para termos os subprojetos vinculados.

### subprojects

Com o **Gradle** é possível definir de uma forma global configurações que serão utilizadas para todo o projeto e/ou para os subprojetos.

```groovy
subprojects {
    if (it.name != 'applications') {
        apply plugin: "java"
        apply from: "$rootDir/plugins/java.gradle"
        apply from: "$rootDir/plugins/docs.gradle"
        apply from: "$rootDir/plugins/lint.gradle"
        apply from: "$rootDir/plugins/mapstruct.gradle"
        apply from: "$rootDir/plugins/security.gradle"

        repositories {
            mavenCentral()
            mavenLocal()
        }

        dependencies {
            implementation enforcedPlatform("${quarkusPlatformGroupId}:${quarkusPlatformArtifactId}:${quarkusPlatformVersion}")
            annotationProcessor "org.mapstruct:mapstruct-processor:$mapstructVersion"
            implementation libs.mapstruct
            implementation libs.quarkus
            testImplementation libs.test
        }

        test {
            useJUnitPlatform()
            maxParallelForks = 2
            testLogging {
                displayGranularity = 2
                events("FAILED", "SKIPPED")
            }
            systemProperty "java.util.logging.manager", "org.jboss.logmanager.LogManager"
        }
    }
}
```

E caso precisemos de configurações específicas em um subprojeto é possível utilizar a seguinte estratégia contida em **applications/cadastro/build.gradle**

```groovy
plugins {
    id "io.quarkus"
}

group "com.gitlab.arthurfnsc.ifood"
version "1.0.0-SNAPSHOT"

apply from: "$rootDir/plugins/openapigen_cadastro.gradle"

dependencies {
    implementation "io.opentracing.contrib:opentracing-jdbc"
    implementation "io.quarkus:quarkus-hibernate-orm-panache"
    implementation "io.quarkus:quarkus-hibernate-validator"
    implementation "io.quarkus:quarkus-resteasy-jsonb"
    implementation "io.quarkus:quarkus-smallrye-jwt"
    implementation "io.quarkus:quarkus-smallrye-metrics"
    implementation "io.quarkus:quarkus-smallrye-opentracing"
    testImplementation "com.github.database-rider:rider-cdi:$dbRiderVersion"
    testImplementation "com.github.database-rider:rider-core:$dbRiderVersion"
}
```

Nesse caso, além das dependências definidas no bloco **subprojects** adicionamos dependências e um plugin específico.

---

## Conclusão

A utilização de **Gradle** foi uma escolha minha e em nada impacta no curso criado pelo @viniciusfcf.

Apesar de uma série de vantagens propostas, sempre é importante analisar o contexto do projeto a ser desenvolvido, bem como a expertise da equipe para a definição de uma ou outra opção.

---

<a name="serie_completa"></a>

Esse post faz parte de uma série sobre **Cursos que formaram meu caráter: Desenvolvimento web com Quarkus**.

A série completa é:

* [Talk is cheap show me the code](https://dev.to/arthurfnsc/cursos-que-formaram-meu-carater-desenvolvimento-web-com-quarkus-talk-is-cheap-show-me-the-code-2k91)
* Utilizando Gradle ao invés de Maven
* [Plugins do Gradle: Gerenciador de versões de bibliotecas com Versions](https://dev.to/arthurfnsc/cursos-que-formaram-meu-carater-desenvolvimento-web-com-quarkus-gerenciador-de-versoes-de-bibliotecas-com-versions-9na)
* [Plugins do Gradle: Saudades do  Maven, relatórios com Project-report](https://dev.to/arthurfnsc/cursos-que-formaram-meu-carater-desenvolvimento-web-com-quarkus-saudades-do-maven-relatorios-com-project-report-51d6)
* [Plugins do Gradle: API First com o OpenAPI Generator](https://dev.to/arthurfnsc/cursos-que-formaram-meu-carater-desenvolvimento-web-com-quarkus-api-first-com-o-openapi-generator-42pm)
* [Plugins do Gradle: API First com o OpenAPI Generator para APIs reativas](https://dev.to/arthurfnsc/cursos-que-formaram-meu-carater-desenvolvimento-web-com-quarkus-api-first-com-o-openapi-generator-para-apis-reativas-3o9b)
* [Plugins do Gradle: Validação de vulnerabilidades de dependências com OWASP Dependency Check](https://dev.to/arthurfnsc/cursos-que-formaram-meu-carater-desenvolvimento-web-com-quarkus-validacao-de-vulnerabilidades-com-owasp-dependency-check-2a2l)
* Plugins do Gradle: Lint com Spotless [não publicado]
* GitLab: Motivação para a escolha [não publicado]
* GitLab: Considerações sobre o Prettier em pipelines [não publicado]
* Gitmoji [não publicado]
* SDK Man [não publicado]
* Pré commit hook [não publicado]
* application.yml: Utilizando YML em propriedades de aplicação [não publicado]
* application.yml: Utilizando variáveis de ambiente [não publicado]
* application.yml: Sobrescrevendo opções em teste [não publicado]
* Mapstruct: Utilizando expressões para mapeamentos [não publicado]
* Microprofile SecurityScheme: Sobrescrevendo tokenUrl [não publicado]
* Prometheus: O problema simples que me custou algumas horas [não publicado]
* quarkus-hibernate-reactive-panache: Utilizando as vantagens do Hibernate em projetos reativos [não publicado]
* Testcontainers: Configuração para projetos reativos [não publicado]