Conhecendo Gradle — Funcionalidades

Rodrigo Mendes
15 min readAug 8, 2018

--

Gradle é um sistema de construção pronto para empresas, alimentado por uma DSL Groovy declarativa e expressiva. Ele combina flexibilidade e extensibilidade sem esforço com a ideia de convenção sobre configuração e suporte para gerenciamento de dependência tradicional. Apoiado por uma empresa de serviços profissionais e forte envolvimento da comunidade, Gradle está se tornando a solução número um para a escolha de compilação para muitos projetos de código aberto e empresas.

Linguagem de build expressiva e a API

Ponto chave para utilizar todo o potencial das funcionalidades com os scripts de build em Gradle fica sobre o saber em entender seu modelo de domínio.

Funcionamento interno do Gradle aplicando o DSL e acessando a API

Como você pode ver na figura, um script de construção se mapeia diretamente para uma instância do tipo de projeto na API do Gradle. Por sua vez, o bloco de configuração de dependências no script de construção invoca o método dependencies() da instância da classe projeto. Como a maioria das APIs do mundo Java, ele está disponível como documentação Javadoc HTML no site da Gradle. Quem poderia imaginar? Você está realmente lidando com o código. Sem saber, você gera uma representação de objeto de sua construção lógica na memória.

Cada elemento em um script Gradle tem uma representação de um-para-um com uma classe Java; no entanto, alguns dos elementos tem uma pitada da sintaxe do Groovy revestidas de açúcar. Ter uma versão baseada em Groovy de uma classe em muitos casos, isso torna o código mais compacto do que o seu homólogo Java e permite a utilização de novos recursos de linguagem, como Closures.

Gradle não pode saber todos os requisitos específicos para a build da sua empresa. Ao expor os ganchos nas fases do ciclo de vida, Gradle permite o monitoramento e configuração de comportamento de execução do script de construção. Vamos supor que você tem a exigência muito original de enviar um e-mail para a equipe de desenvolvimento, sempre que uma falha de teste de unidade ocorre. A maneira como você deseja enviar um e-mail (por exemplo, através de SMTP ou um provedor de serviços de e-mail de terceiros) e a lista de destinatários são muito específicos para a sua construção. Outros Builds usando Gradle podem não estar interessados neste recurso em tudo. Ao escrever um ouvinte (listener) personalizado de teste que é notificado após o evento do ciclo de vida de execução de teste, você pode facilmente incorporar esse recurso para a sua construção.

Gradle estabelece um vocabulário para o seu modelo, expondo uma DSL implementada em Groovy. Ao lidar com um domínio de problema complexo, neste caso, a tarefa de construir software, sendo capaz de utilizar uma linguagem comum para expressar a sua lógica pode ser uma ferramenta poderosa. Vejamos alguns exemplos, o mais comum o de compilações é a notação de uma unidade de trabalho que você deseja obter executado. Gradle descreve esta unidade de trabalho como uma tarefa como o ANT. Parte do DSL padrão de Gradle é capaz de definir tarefas muito específicas para compilar e empacotar o código-fonte Java. É uma linguagem para a construção de projetos Java com o seu próprio vocabulário que não precisa ser relevante para outros contextos.

Outro exemplo é a forma como você pode expressar dependências de bibliotecas externas, um problema muito comum resolvido por ferramentas de compilação. Out-of-the-box Gradle lhe fornece a partir de dois blocos de configuração para o seu script de Build que permitem definir as dependências e repositórios que pretende recuperá-los. Se os elementos DSL padrão não atendem às suas necessidades, você pode até introduzir o seu próprio vocabulário através do mecanismo de extensão de Gradle.

Declaração de Dependencias

Gradle é Groovy

As ferramentas de compilação de destaque, como ANT e Maven definem sua lógica de construção através de XML. Como todos sabemos, XML é fácil de ler e escrever, mas pode se tornar um pesadelo para a manutenção se usado em grandes quantidades. XML não é muito expressivo. Isso torna mais difícil de definir lógica complexa personalizada. Gradle tem uma abordagem diferente. Por debaixo da DSL de Gradle é tudo Groovy fornecendo sintática simplificada sobre o Java. O resultado é uma linguagem de construção legível e expressivo. Todos os scripts são escritos em Groovy também. São capazes de usar uma linguagem de programação para expressar suas necessidades de construção é uma grande vantagem. Você não precisa ser um especialista em Groovy para começar. Porque Groovy está escrito em cima de Java, você pode migrar gradualmente para experimentar suas características linguísticas. Você pode até escrever sua lógica personalizada em Java simples — Gradle não se importa com isso. Veteranos em Groovy vão lhe garantir que o uso de Groovy em vez de Java irá aumentar a sua produtividade significativamente.

Linguagens usadas em gradle

Flexibilidade nas convenções

Uma das grandes ideias de Gradle é dar-lhe orientações e padrões sensíveis para os seus projetos. Cada projeto Java no Gradle sabe exatamente onde os arquivos fonte e de teste devem ficar, e como compilar o código, executar os testes de unidade, gerar Javadoc, e criar uma distribuição de seu código. Todas estas tarefas são totalmente integradas no ciclo de vida de criação. Se você ficar com a convenção, só há esforço configuração mínima de sua parte. Na verdade, o seu script de construção é uma linha única. Na figura abaixo ilustra como Gradle introduz convenções e tarefas do ciclo de vida em projetos Java.

Pode definir as convenções da minha empresa.

As tarefas padrão são fornecidas as que fazem sentido no contexto de um projeto Java. Por exemplo, você pode compilar o código fonte Java, executar testes, e montar um arquivo JAR. Cada projeto Java começa com um layout de diretório padrão. Ele define onde encontrar o código-fonte, arquivos de recursos e código de teste. Propriedades de convenções são usados ​​para alterar os padrões para cada empresa.

O mesmo conceito se aplica a outros arquétipos de projeto como Scala, Groovy, projetos web, e muitos mais. Gradle chama este conceito configuração por convenção. O desenvolvedor do script de construção não precisa saber como isso funciona internamente. Em vez disso, você pode se concentrar no que precisa ser configurado. As convenções de Gradle são semelhantes aquelas em Maven, mas eles não deixam você sentir limitado ao Maven é muito opinativa; propõe que um projeto contém apenas um diretório de origem Java e produz apenas um arquivo JAR. Isso não é necessariamente realidade para muitos projetos empresariais. Gradle permite que você facilmente rompa essas convenções. No extremo oposto do espectro, ANT não lhe dá um monte de orientação sobre como estruturar o seu script de construção, permitindo um nível máximo de flexibilidade. Gradle utiliza o meio-termo, oferecendo convenções combinados com a capacidade de mudá-las facilmente.

Gerenciador de Dependências poderoso

Os projetos de software geralmente não são autossuficientes. Com muita frequência, o código do aplicativo usa uma biblioteca de terceiros fornecendo funcionalidade existente para resolver um problema específico. Por que você iria querer reinventar a roda por meio da implementação de um framework de persistência Hibernate, se já existe? Dentro de uma organização, você pode ser o consumidor de um componente ou módulo implementado por uma equipe diferente. Essas dependências externas são acessíveis através de repositórios, e o tipo de repositório é altamente dependente do que a sua empresa prefere. As opções vão desde um sistema de arquivos simples a um repositório corporativo. As dependências externas podem ter uma referência para outras bibliotecas ou recursos. Chamamos essas dependências transitivas, conforme citado anteriormente.

Gradle fornece uma infraestrutura para gerenciar a complexidade de resolver, recuperar e armazenar dependências. Uma vez que são baixados e armazenadas em seu cache local, e ficam disponíveis para o seu projeto. Um requisito fundamental de builds empresariais é a reprodutibilidade. Você se lembra da última vez que um colega de trabalho disse: “Mas ele funciona na minha máquina”? Compilações tem que produzir o mesmo resultado em máquinas diferentes, independente do conteúdo de seu cache local. Os gerenciadores de dependência como Ivy e Maven na sua implementação atual não podem garantir plenamente a reprodutibilidade. Por que é que? Sempre que uma dependência é baixada e armazenada em cache local, ele não leva em conta a origem do artefato. Em situações em que o repositório é alterado para um projeto, a dependência em cache é considerado resolvido, mesmo que o conteúdo do artefato pode ser ligeiramente diferente. Na pior das hipóteses, isso resultará em uma falha no Build que é extremamente difícil para depurar. Outra queixa comum específica para o Ivy é o fato de que a dependência de versões SNAPSHOT, os artefatos que estão em desenvolvimento com o -snapshot convenção para a nomeação, não são atualizados corretamente no cache local, embora sejam alterados no repositório e são marcados como para mudar. Há muitos mais cenários em que as soluções atuais deixam a desejar. Gradle fornece sua própria solução de gerenciamento de dependência configurável, confiável e eficiente.

Os projetos de grandes empresas geralmente consistem de vários módulos para a funcionalidade em separado. No mundo Gradle, cada um dos sub-módulos é considerado um projeto que pode definir dependências de bibliotecas externas ou outros módulos. Além disso, cada subprojeto pode ser executado individualmente. Gradle descobre para você que as dependências do subprojeto precisam ser reconstruídas, sem ter que armazenar artefato de um subprojeto no cache local.

Builds escaláveis

Para algumas empresas, um grande projeto com centenas de módulos é uma realidade. Construir e testar pequenas mudanças de código pode consumir muito tempo. Você pode saber por experiência pessoal, que a exclusão de classes e recursos antigos, executando uma tarefa de limpeza é um reflexo natural. Muitas vezes, você se sente vendido por sua ferramenta de compilação não pega as mudanças e suas dependências. O que você precisa é uma ferramenta que é inteligente o suficiente para reconstruir apenas as partes do seu software que realmente mudaram. Gradle suporta compilações incrementais, especificando as entradas e saídas de tarefas. Ela aparece de forma confiável para você com quais tarefas que precisam ser ignoradas, construídas, ou parcialmente reconstruídas. O mesmo conceito se traduz em projetos multi-módulos, chamado Build parcial. Devido a sua construção define claramente as dependências entre os sub-módulos, Gradle cuida de reconstruir apenas as partes necessárias. Não mais ter que executar a limpeza do cache local por padrão.

Testes unitários, de integração e funcionais fazem parte do processo de construção. Faz sentido para separar teste de curta execução dos testes que requerem em sua constituição recursos ou dependências externas para ser executado. Gradle suporta a execução do teste em paralelo. Este recurso é totalmente configurável e assegura que você está tomando realmente vantagem de núcleos do seu processador. E não para por aqui. Gradle suporta a distribuição de execução de teste em várias máquinas virtuais separadas isoladas do processo principal.

Desenvolvedores executam build muitas vezes durante o desenvolvimento. Isso significa iniciar um novo processo de Gradle cada vez, carregar todas as suas dependências internas e executando a lógica de construção. Você vai notar que, geralmente, leva um par de segundos antes de seu script realmente começa a executar. Para melhorar o desempenho de inicialização, Gradle pode ser executado em modo daemon. Na prática, os comandos de bifurcação de um processo em daemon no Gradle, que não só executa a sua construção, mas também mantém funcionando no fundo. Invocações de compilação posteriores vão sobrepor sobre o processo de daemon existente para evitar os custos de arranque. Como resultado, você vai notar uma execução do build inicial muito mais demorada.

Extensibilidade sem muito esforço

A maioria dos builds não são iguais em cada empresa, nem resolvem os mesmos problemas. Uma vez que você já passou a fase inicial de criação de scripts básicos, você vai querer implementar lógica personalizada. Gradle não é opinativo sobre a maneira de implementar esse código. Em vez disso, te entrega várias opções para escolher, dependendo do seu caso de uso específico. A maneira mais fácil de implementar lógica personalizada é escrevendo uma tarefa. As tarefas podem ser definidas diretamente no seu script de construção, sem cerimônia especial. Se você se sentir que a complexidade é grande, você pode querer explorar a opção de uma tarefa personalizada que permite escrever sua lógica dentro de uma definição de classe, podendo estruturar o código de maneira fácil e melhorando a manutenção. Se você quiser compartilhar código reutilizável entre builds e projetos, plug-ins são a melhor escolha. Representando extensão mais poderosa do Gradle, plug-ins tem pleno acesso à API do Gradle e pode ser escrito, testado e distribuído como qualquer outro pedaço de software. Escrevendo um plugin é surpreendentemente fácil e não requer uma grande quantidade de descritores.

Implementação de um plugin básico:

¬class GreetingPlugin implements Plugin<Project> {
void apply(Project project) {
project.task('hello') {
doLast {
println 'Hello from the GreetingPlugin'
}
}
}
}
// Apply the plugin
apply plugin: GreetingPlugin

Execução do plugin:

¬> gradle -q hello
Hello from the GreetingPlugin

Integração com outras ferramentas de Build

Gradle se integra bem com seus predecessores ANT, Maven e Ivy. Conforme a figura abaixo:

Gradle fornece profunda integração com outras ferramentas de compilação e abre a porta para migrar gradualmente das ferramentas que já existente para fazer o Build como ANT ou Maven.

Se você está vindo do ANT, Gradle não irá forçá-lo a migrar sua infraestrutura de compilação completa. Em vez disso, ele permite que você importe sua lógica de construção existente e reutilize tarefas padrão do ANT. As compilações através do Gradle são 100% compatíveis com repositórios Maven e Ivy. Você pode recuperar as dependências e publicar seus próprios artefatos. Gradle fornece um conversor para builds existentes em Maven, onde se baseia na lógica descrita no pom.xml executando uma tradução da lógica para a construção de um script Gradle para executar o mesmo Build.

Existentes scripts ANT que podem ser importados para um build Gradle tranquilamente e usado como você usaria qualquer outro script Gradle externo. Tarefas ANT são mapeadas diretamente para tarefas Gradle em tempo de execução. Gradle embarca as bibliotecas do ANT e as expõe em forma de classe auxiliar para seus scripts chamado ANTBuilder, que combina plenamente em DSL do Gradle. Ele ainda olha e sente como XML do ANT, mas com um visual mais fácil. Os usuários de ANT vão se sentir em casa, porque eles não têm a transição para a sintaxe Gradle imediatamente. Migrando do ANT para Gradle também é necessário um grande esforço. Você pode dar passos de bebê, reutilizando a sua lógica ANT existente ao usar os benefícios do Gradle ao mesmo tempo.

Exemplo de código:

¬task hello {
doLast {
String greeting = 'hello from Ant'
ant.echo(message: greeting)
}
}

Execução:

¬> gradle hello> Task :hello
[ant:echo] hello from Ant
BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed

Com importação do script

build.gradle

¬ant.importBuild 'build.xml'

build.xml

¬<project>
<target name="hello">
<echo>Hello, from Ant</echo>
</target>
</project>

Saída de gradle hello:

¬> gradle hello> Task :hello
[ant:echo] Hello, from Ant
BUILD SUCCESSFUL in 0s
1 actionable task: 1 executed

Gradle visa atingir uma profundidade semelhante de integração com o Maven. No momento da escrita, este ainda não foi realizado. No longo prazo, POMs e plug-ins Maven serão tratados como recursos nativos Gradle. Repositórios Maven e Ivy tornaram-se uma parte importante da infraestrutura de construção de hoje. Imagine um mundo sem Maven Central para ajudar acesso a específicas versões de suas dependências em seus projetos. Recuperando as dependências de um repositório é apenas uma parte da história; publicá-las é tão importante quanto. Com um pouco de configuração, Gradle pode fazer upload de artefato de seu projeto para toda a empresa ou o consumo público.

Exemplo de utilização e POM.xml já existente:

¬apply plugin: 'java'repositories {
mavenCentral()
flatDir {
dirs 'lib'
}
}
dependencies {
def pomXml = new XmlSlurper().parse('pom.xml')
def pomDependencies = pomXml.dependencies.dependencypomDependencies.each { dependency ->def dependencySpec = "${dependency.groupId}:${dependency.artifactId}:${dependency.version}"if(dependency.scope == 'test') {
dependencies.add 'testCompile', dependencySpec
} else {
dependencies.add 'compile', dependencySpec
}
}
}

Funcionalidades adicionais muito uteis

Gradle é equipado com uma interface de linha de comando rica. Usando opções de linha de comando, você pode controlar tudo, desde especificando o nível de log, a exclusão dos testes, a exibição de mensagens de ajuda. Isso não é nada de especial; outras ferramentas de proveem isso também. Algumas das características destacam-se, apesar de tudo. Gradle permite a execução de comandos em uma forma abreviada, em forma camel-case. Na prática, um comando chamado runMyAwesomeTask poderia ser chamado com sua abreviação rMAT. Mesmo que eu apresentar a maioria dos exemplos da próxima semana por eles executar comandos em um shell, tenha em mente que Gradle fornece uma interface de usuário out-of-the-box gráfica.

Big Picture: Entrega Contínua

Ser capaz de construir o seu código-fonte é apenas um aspecto do processo de entrega de software. Mais importante, você deseja liberar o seu produto para um ambiente de produção para entregar valor de negócio. Ao longo do caminho, você deseja executar testes, construir a distribuição, analisar o código para fins de controle de qualidade, potencialmente fornecer um ambiente de destino e implantar nele.

muitos benefícios para a automatização de todo o processo. Em primeiro lugar, entregar software manualmente é lento, propenso a erros e estressante. Eu tenho certeza que cada um de nós odeia as longas noites devido a uma implantação errada. Com o surgimento de metodologias ágeis, as equipes de desenvolvimento são capazes de entregar software mais rápido. Ciclos de lançamento de duas ou três semanas tornaram-se uma norma. Muitas organizações agora ainda enviam o código para a produção várias vezes por dia! Idealmente, você quer ser capaz de liberar software, selecionando o ambiente de destino, simplesmente pressionando um botão. Práticas como testes automatizados, CI (Continuous Integration — integração Contínua), e alimentando a implantação é o conceito geral de entrega contínua.

Vejamos como Gradle pode ajudar a obter o seu projeto de construção para implantação. Ele pode permitir que você realize a automatização em muitas das tarefas necessárias para implementar a entrega contínua, sejam eles compilar seu código-fonte, a implantação de uma entrega, ou ligar ferramentas externas que ajudam na execução do processo.

Automatizando o seu projeto do Build até a Entrega

Entrega contínua introduz o conceito de um pipeline (tubulação) de implantação, também referido como o pipeline de construção. Um pipeline de implantação representa a implementação técnica do processo para obter software de controle de versão em seu ambiente de produção. O processo consiste em várias fases, conforme o desenho abaixo:

Exemplo simplificado dos estágios do pipeline de deployment
  • Commit: Relatórios sobre o nível de qualidade de técnica do seu projeto. A principal parte interessada desta fase é a equipe de desenvolvimento, uma vez que fornece feedback sobre o código quebrado e encontra possíveis bugs e erros. O trabalho desta fase é para compilar o código, executar testes, executar análise da execução do código, executar análise estática de código e preparar a distribuição.
  • Teste de aceitação automatizados: Confirma que os requisitos funcionais e não-funcionais são satisfeitos pela execução de testes automatizados.
  • Teste manual: Verifica se o sistema é utilizável na verdade, num ambiente de teste. Normalmente, esta fase envolve o pessoal de controle de qualidade para verificar os requisitos sobre o nível de histórias de usuários ou casos de uso.
  • Release: fornece o software para o usuário final como uma distribuição de pacote ou implanta no ambiente de produção.

Vamos ver em quais estágios do pipeline de implantação pode beneficiar da automação projeto. É óbvio que a fase de teste manual pode ser impedida de continuar a discussão, porque só envolve tarefas manuais. As tarefas concretas em que estamos interessados são:

  • Compilar o código
  • A execução de testes unitários e de integração
  • Execução de análise estática de código e geração de cobertura de teste
  • Criando a distribuição
  • Provisionamento do ambiente de destino
  • Implantando a entrega
  • Execução de smoke testes e automatização de testes funcionais

A próxima figura mostra a ordem de tarefas dentro de cada uma das fases. Embora não existam regras rígidas que impeçam pular tarefas específicas, é recomendado que você siga a ordem. Por exemplo, você pode decidir compilar o código, criar a distribuição e implantá-lo no ambiente de destino sem executar quaisquer testes ou análise de código estático. No entanto, isso aumenta o risco de defeitos de código não detectados e qualidade de código pobre.

Exemplo de tarefas executadas nos estágios do pipeline.

Os tópicos tais como infraestrutura de fornecimento, implantação automatizada, e smoke testes podem também ser aplicados à fase de libertação. Na prática, a aplicação destas técnicas a um ambiente de produção, é mais complexo do que num ambiente de teste controlado. Em um ambiente de produção, você pode ter que lidar com as infraestruturas em cluster e servidores distribuídos e reversões automatizadas para a versão anterior.

Arquitetura Técnica do Gradle

Diagrama de Arquitetura do Gradle

--

--