Porque você deve trocar o Maven pelo Gradle?

Gradle

Qual ferramenta de build é a melhor?

Esse assunto é polêmico hein! Razão de inúmeros flamewars, brigas, mortes, guerras, protestos, atentados terroristas.

Não vou dizer que farei um análise imparcial aqui, porque não vou. Mas também não vou apenas ficar cuspindo no prato que comi – embora não sei porque isso é um problema, cuspir… em um prato vazio… qual problema… já comi mesmo…

Enfim! Minha ideia é apenas mostrar bons motivos para se usar o Gradle no lugar do Maven, assim como alguns anos atrás eu tive bons motivos para usar o Maven no lugar do Ant.

Muitos já se convenceram que o Gradle é uma alternativa mais interessante, inclusive o novo sistema de build do Android SDK é em Gradle.

Existe até uma teoria – bem justificada – do Neil Ford da Thoughtworks que eventualmente todo mundo vai ficar puto com o Maven e abandoná-lo.

Mas voltaremos nisso mais pra frente. Primeiro queria fazer um pequeno retrospecto autobiográfico…

Minha história com ferramentas de build

Meu background profissional é principalmente relacionado a Java e posso afirmar com bastante segurança que no mundo Java as ferramentas de build mais conhecidas e usadas são duas: o Ant e o Maven.

Tive a oportunidade de usar ambas na prática, em grandes e pequenos projetos, e essa foi minha experiência resumida com cada uma:

Experiências com Ant

– car***o, não tenho idéia do que esse build.xml de 32989 linhas faz…
– meu deus do céu, que target que eu rodo primeiro?

Experiências com Maven

– que maravilha, todos os 726362 projetos estão padronizados. É só fazer mvn install
\o/

– ah, agora eu sei que o source está em src/main/java e os resources em src/main/resources
\o/

– preciso implementar, buildar e distribuir um maldito plugin só pra fazer isso?!?!
<o>

– meu projeto precisa herdar desse mega-gigante pom.xml da empresa? Mas eu estou duplicando praticamente tudo novamente só para especializar meu build.
<o>

Explicando o que aconteceu:
Na época do Ant existia um grande problema de falta de padronização entre diferentes projetos. Cada um colocava o código fonte e os recursos onde julgava melhor, cada um colocava os artefatos gerados em uma pasta diferente, sem falar que muitos projetos não usavam nenhuma ferramenta para gerenciamento de dependências.

Além disso, os próprios arquivos descritores de build eram despadronizados. Se alguém trocava de projeto, a primeira coisa era descobrir qual target do Ant rodar primeiro.

Quando implantamos o Maven na empresa em que eu trabalho houve um ganho instantâneo em termos de padronização, adaptação de novas pessoas nas equipes e gerenciamento de dependências.

Claro que nem tudo é perfeito, no começo tivemos problemas com integração com IDEs, resistência e adaptação das pessoas, builds mais lentos. Mas os ganhos gerais compensaram essas dores de cabeça iniciais.

Mas depois de muitos anos usando o Maven, você começa a esbarrar em problemas muito inconvenientes a medida em que os builds se torna mais sofisticados e fora do comum, te obrigando a fazer vários malabarismos somente para contornar as imposições e limitações da ferramenta.

O Maven fez sua parte, mas já pode ir embora agora

Por ser uma ferramenta de opinião muito forte, a ponto de ser até considerada dogmática, ele conseguiu trazer uma padronização muito grande entre projetos da comunidade Java, criando praticamente uma nova cultura:

  • repositórios Maven
  • layout padrão de diretórios: src/main, src/test, target
  • build lifecycle

Mas se o Maven trouxe tantos benefícios, porque alguns estão trocando ele pelo Gradle?

Gosto de pensar no Maven como uma grande ditadura totalitária que veio instaurar a ordem quando tudo estava em um estado de total caos. Você tem que seguir o modelo rígido de build que ele impõe, seguir somente as fases que ele determina, ou então você terá muito trabalho subvertendo o sistema!

Imposition over Configuration

Assim o Maven funciona muito bem para 90% das coisas mais comuns de um build, mas complica muito para aqueles 10% de detalhes específicos do seu projeto (leia mais sobre a Dietzler’s Law no link do Neal Ford acima), já que a maneira como o Maven permite extensão é limitada e complicada demais.

Já está na hora dessa ditadura acabar e dar origem a um sistema mais flexível.

Gradle junta o melhor dos dois mundos e vai além

Enquanto o Ant oferece total flexibilidade para você definir as tarefas do seu build e como elas se sucedem umas as outras, o Maven vem com a proposta de um ciclo de vida rígido que todo build deve seguir.

A proposta do Gradle é continuar reforçando essa cultura e padronização do Maven através de convenção ao invés de imposição.

O Gradle incorporou o melhor dos dois lados:
Do Ant:

  • tasks altamente configuráveis
  • ciclo de vida de build flexível baseado em grafo aciclico direcionado.
  • gerenciamento de dependências com repositórios Ivy

Do Maven:

  • padronização do layout de diretórios
  • padronização do build lifecycle
  • builds multi-projeto
  • gerenciamento de dependências com repositórios Maven

Mas o Gradle vai muito além do Ant e do Maven: ele implementa uma verdadeira DSL em Groovy, permitindo a maior flexibilidade possível; no fim das contas, seu descritor de build é um script!

Enquanto no Maven e no Ant para criar uma coisinha diferente para seu build é preciso que você implemente e disponibilize um plugin, no Gradle você pode programar sua task ali mesmo, no build file.

Perai, o descritor de build é um script, então significa que vou voltar para o caos novamente?

Não, não vai, e o segredo está em seu sistema de plugins.

Conhecendo melhor o Gradle

No Gradle, a unidade de trabalho é a Task; equivalente ao Target do Ant ou ao Phase e o Goal do Maven.

Como no Ant, essas tasks podem ter dependência para outras tasks, criando um grafo direcionado acíclico. Dessa forma, quando você executa uma task, o Gradle executa antes todas as dependências dessa task.

No entanto, o Gradle conta com um sistema de plugin, e vários plugins nativos, que evitam que os builds voltem para o caos novamente, através da convenção.

Um plugin no Gradle é essencialmente um conjunto de tasks e configurações pré-definidas, que você pode importar em seu projeto. É como se um plugin no Gradle fosse uma Trait do Scala ou um Mixin do Ruby, ficando muito fácil estender um build através da composição e não da herança.

Portanto com o Gradle temos tanto a convenção, que nos permite ter a padronização e o inicio rápido de um novo projeto, como também a flexibilidade para customizar o build da maneira que for necessária, através de uma poderosa DSL Groovy.

Veja como é simples um build file para um projeto Java, com classes, resources e testes unitários.

Arquivo build.gradle:

apply plugin: 'java'

Sim, com uma linha você tem um projeto Java que compila, testa e empacota um JAR.

Outras vantagens do Gradle

Só uma listinha para te convencer a usar o Gradle:

  • Descritor de build em Groovy e não em XML
  • Suporte a repositórios Maven e Ivy
  • Build incremental que funciona de verdade
  • Composição ao invés de Herança
  • Suporte nativo a várias linguagens como Groovy e Scala
  • Integração com Eclipse, IntelliJ
  • Dezenas de plugins disponíveis
  • Android SDK e Hibernate já usam (vai ficar fora dessa?)

Estou convencido! E agora?

Shut up and take my money
Eu pretendo fazer outros posts sobre o funcionamento do Gradle, tentando destilar um pouco da documentação que tem por aí, mas para quem ficou entusiasmado com o Gradle, o guia dele é bem completo.

Também recomendo o livro Building and Testing with Gradle que é gratuito para leitura online.

Anúncios

Como usar o SBT (simple-build-tool) com JRebel

Prólogo

Não muito tempo atrás, em um lugar não muito distante, chamado Web, existiam dois tipos de programadores:

  • Aqueles que dominavam a arte da linguagem interpretada, como Ruby, PHP. Acostumados com o tempo de Turnaround zero, em troca de menos performance.
  • E aqueles que dominavam a disciplina da linguagem compilada e tipada, como o Java, Scala e C#, que em troca de mais performance e servidores de aplicações, submeteram-se ao sofrimento do tempo de Turnaround

Um certo dia, um grupo de sábios estonianos uniram seus poderes e inventaram um artefato chamado JRebel que miraculosamente diminuía o tempo de Turnaround para os desenvolvedores Java e Scala.

Nota de rodapé do autor: Tempo de Turnaround é usado para denominar, entre outras coisas, o intervalo de tempo entre o momento em que você salva seu código e vê as alterações na tela. Em PHP esse tempo é zero, você salva o arquivo, faz refresh no browser e as mudanças estão lá. Em Java, caso você esteja desenvolvendo para um servidor de aplicação como o Weblogic, você tem que salvar seu código, compilar, empacotar, baixar e subir o Weblogic, aí sim você vê suas alterações.

Também conhecido como o tempo em que você levanta para pegar um cafézinho enquanto o servidor está subindo.

E assim eles destruíram os programadores de Ruby on Rails e viveram felizes para sempre.

Brincadeira.

Eles só ficaram mais produtivos, e passaram a tomar menos café (ou não).

JRebel, a salvação

Chega de historinha, esse é um post sério.

JRebel é uma ferramenta criada para diminuir o tempo que você espera para ver seu código funcionando.

Como ele faz isso?

Ele é um Java Agent, que altera os Classloaders da sua aplicação quando ela é executada. Esses classloaders modificados ficam monitorando os arquivos .class de sua aplicação. Quando algum desses .class muda, por exemplo quando você faz uma modificação e compila, o classloader percebe a mudança e recarrega a classe, sem que haja necessidade de reiniciar a aplicação ou o servidor.

Enquanto isso, no mundo dos builds

SBT, ou o Simple-Build-Tool

Essa ferramenta, escrita em Scala, não foi feita pelo Silvio Santos não.

Ela é uma alternativa para o famigerado Maven. Enquanto o Maven vem perdendo adeptos, por ser considerada uma ferramenta engessada, lenta, burra, o SBT vem arrasando corações no submundo emergente de Scala.

O foco aqui não é fazer uma apresentação detalhada de SBT, mas posso elencar alguns pontos chave:

  • É rápido.
  • A configuração é feita em Scala.
  • Integra com Maven e Ivy.
  • Dá para abrir um console Scala com todo seu projeto no Classpath para ficar testando coisas.
  • Consegue monitorar seu código fonte, executando o build assim que algum arquivo muda.

Se você programa em Scala e nunca usou o SBT experimente.

SBT e JRebel, a combinação ágil

Essa combinação vem ficando cada vez mais famosa, especialmente entre os programadores Lift. E tenho que confessar, funciona muito bem. Meu tempo de turnaround está praticamente zero.

Como configurar?

Primeiro baixe o JRebel e em seguida peça uma licença gratuita de um ano para desenvolvedores Scala (ao lado direito da página).

Quando receber a licença siga as instruções (colocar o arquivo da licença no diretório do JRebel).

Em seguida baixe o JAR do SBT, coloque em uma pasta qualquer e crie um script que irá chamá-lo:

java -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=516m -Xmx512M -Xss2M -noverify -javaagent:[CAMINHO_DO_JREBEL.JAR] -jar `dirname $0`/[CAMINHO_DO_JAR_DO_SBT] "$@"

Note que estamos informando ao Java que o JRebel é um javaagent. Assim, quando o você executar o SBT usando esse Script, o JRebel vai subir junto.

Coloque esse Script no seu PATH.

Como usar?

Para tirar os proveitos do JRebel você precisa criar uma aplicação em SBT, usar uma aplicação em SBT, ou configurar o SBT em uma aplicação Maven:

Se você usa Maven, saiba que o SBT consegue ler as dependências do arquivo pom.xml caso você não especifique nenhuma dependência na classe de configuração do SBT. Isso é bastante útil se você precisa manter um projeto em Maven e ao mesmo tempo quiser tirar proveito do SBT.

Vejamos um exemplo. Vamos usar um projeto Lift de exemplo que coloquei no Github:


git clone git://github.com/felipekamakura/sbt_jrebel_lift_example.git myApp


> cd myApp
> sbt


#############################################################

JRebel 3.5 (201011151605)
(c) Copyright ZeroTurnaround OU, Estonia, Tartu.

Over the last 23 days JRebel prevented
at least 92 redeploys/restarts saving you about 3.7 hours.

This product is licensed to Personal
until April 3, 2011
for up to developer seats on site.

The following plugins are disabled at the moment:
* JBoss AOP Plugin (set -Drebel.jbossaop_plugin=true to enable)
Integration with jboss aop agent
* Jackson Plugin (set -Drebel.jackson_plugin=true to enable)
Supports reloading Jackson's JsonSerializer caches.
* Lift Plugin (set -Drebel.lift_plugin=true to enable)
Supports reloading singleton objects that extend LiftScreen or Wizard.
* Log4j plugin (set -Drebel.log4j-plugin=true to enable)
Reloads full configuration of log4j
* RESTEasy Plugin (set -Drebel.resteasy_plugin=true to enable)
Supports adding/changing methods with @Path annotation for RESTEasy application.
* Seam Wicket Plugin (set -Drebel.seam_wicket_plugin=true to enable)
Integration with load time weaving seam annotations to wicket classes
(-javaagent:)
* WebObjects Plugin (set -Drebel.webobjects_plugin=true to enable)
WebObjects JRebel Plugin

#############################################################

Getting Scala 2.7.7 ...
:: retrieving :: org.scala-tools.sbt#boot-scala
confs: [default]
2 artifacts copied, 0 already retrieved (9911kB/5097ms)
Getting org.scala-tools.sbt sbt_2.7.7 0.7.4 ...
:: retrieving :: org.scala-tools.sbt#boot-app
confs: [default]
15 artifacts copied, 0 already retrieved (4096kB/13414ms)
[info] Recompiling project definition...
[info] Source analysis: 1 new/modified, 0 indirectly invalidated, 0 removed.
Getting Scala 2.8.1 ...
:: retrieving :: org.scala-tools.sbt#boot-scala
confs: [default]
2 artifacts copied, 0 already retrieved (15118kB/805ms)
[info] Building project Lift SBT Template 0.1 against Scala 2.8.1
[info] using LiftProject with sbt 0.7.4 and Scala 2.7.7
>

Você está agora no console do SBT. Execute o comando update para baixar as dependências do projeto:

>update

Em seguida, compile e suba a aplicação exemplo com o comando jetty-run:

>jetty-run

Legal, se tudo deu certo, a aplicação Lift de exemplo está disponível em http://localhost:8080/. Entre lá para dar uma olhada, deve estar assim:
Aplicação Lift, JRebel e SBT

Vamos agora ver o poder do JRebel alterando uma classe, compilando-a e vendo a mudança na tela:

Execute o seguinte comando no SBT:

>~prepare-webapp

O prepare-webapp é um comando do SBT que compila e empacota a sua aplicação web. O ~ (til) antes do comando fala para o SBT – “rode o seguinte comando sempre que houve uma mudança no código fonte”.

Sempre que você usar o ~ (til) no SBT, ele vai ficar em um “estado de alerta”, e vai construir tudo sempre que houver mudança. Isso é essencial para conseguirmos baixar o tempo de Turnaround. E também o SBT é esperto o suficiente para compilar apenas as classes de seu projeto que foram alteradas.

Agora abra e altere o arquivo src/main/scala/code/snippet/HelloWorld.scala. Troque a frase de saudação para sua frase favorita.

class HelloWorld {
// Altere a linha abaixo para sua frase favorita
def howdy = "#greet *" #> "Cai fora curioso."
}

Então, quando você salvar a classe, o SBT vai começar a compilar tudo e o JRebel vai notar que houve mudança no .class dessa classe.

De um refresh no browser e note que a tela foi atualizada com suas modificações! Rápido, prático, indolor! Veja que a frase mudou:
Aplicação depois da alteração

É só isso pessoal! Nada de intervalo para o cafézinho durante o build, foi mal…