Groovy Power: Flexibilidade, Simplicidade e Código Legível
Eu um post anterior comentei sobre a importância de se escrever um código mais fluente, ligível e auto-explicativo. Muitas vezes são com pequenas ações que podemos melhorar este aspecto sobre o código que escrevemos. Estas pequenas ações são caracterizadas com um bom disgn coeso e pouco acoplado, bons nomes de classes e métodos, variáveis com nomes significativos e código fluente e claro.
Criar código fluente e claro pode ser especialemte desafiador. É facto que certas linguagens facilitam ou dificultam esta tarefa, Java não é a linguagem mais fluente do mundo mas existem alternativas. No post anterior eu ensinei a criar uma DSL com Java sem nenhum framework e com batsante fluencia.
Neste post quero comentar sobre a linguagem dinamica Groovy que é a referência padrão de linguagens dinamicas para a JVM. Existem outras bem funcionais e interessantes como JRuby, BeanShell, Jython, Scala e tantas outras. Em especial hoje vou falar de Groovy, por que?
Por que como desenvolvedor Java este foi o primeiro contato com linguagens dinamicas sobre a JVM. Vejo de uma forma muito natual que o desenvolver nos dias de hoje busque outras soluções que não sejam unicamente dentro da linguagem Java. Mas de certa forma é muito claro para mim que utilizar a JVM é um ótima idéia, usar linguagens dinamicas que rodam em cima da JVM e tem integração com Java e os principais Frameworks existentes em Java com Spring e Hibernate é melhor ainda, este é o caso do Groovy.
Groovy é um linguagem que roda em cima da JVM, então é claro e obvio que ela não é a linguagem mais performatica do mundo, mas muitas vezes o problema esta em outro lugar, na persitência, no servidor, enfim... não é o fato da linguagem ser interpretada que deixa o uso da mesma inviável.
Por sinal o Groovy pode ser usando tanto interpretado como um script ou pode ser compilada pelo groovyc e rodar como uma class Java normal. Java é OO e Groovy também. Porem o Groovy é hibrido e você pode programar de forma procedural, o que de facto é muito útil para construção de scripts e na própria produtividade.
Groovy possui várias vantagens entre elas:
Este código a cima mostra um exemplos simples de Closure em Groovy. Se você executar este código no groovyConsole por exemplo vai aparecer 3 no console como resultado.
DRY:Don't Repeat Yourself é um conceito bem interessante que as novas soluções vem implementado. Este conceito se baseia em elimitar a duplicação em todos os sentidos. Em java sofremos muito com isso quando usamos diversos frameworks baseados em XML(ex: clássico Spring, Hibernate, Struts, web.xml, etc..). Mas este conceito não se aplica apenas a parte de configuração. Este conceito aparece no The Pragmatic Programmer. Bom se você não leu este livro ainda não perca tempo e compre agora e leia o quanto antes. Neste caso foco em DRY por que isto leva a um código mais legível também e isso também foi incorporado ao Groovy.
Este é um tipico código que escrevemos em Java. Não vou entrar em discussões mais DDD, modelo anemico e tudo mais, isso é assunto para outros posts, mas. Mesmo com DDD ainda existe a possibilidade de não existirem validações e código de negocio nesta classe. Muitas vezes fazemos métodos getters and setters mas sem código dentro.
Este código acima é Java, mas funciona perfeitamente em Groovy. Porem em Groovy poderiamos fazer algo assim por exemplo:
Ok. Mas cade os getters e setters? Isto compila? Roda sem levantar Exceptions? Sim compila e roda sem exceptions, funciona exetamente igual ao código acima, porém não precisamos escrever os códigos de getters e setters, já que não temos regras nem validações lá. Isso pode ficar ainda melhor veja o outro código Groovy a baixo:
Cade o código dos construtores? Como que isso funciona? O Groovy resolve estas questões para nos, tirando algumas coisinhas chatas da linguagem Java e nos dando mais produtividade e legibilidade. Mas vamos melhorar mais? É possível?
Cade o return? E outra coisa onde estão as concatenações de Strings usando o operador "+"? Bom quanto ao return ele é opcional, o Groovy assume que a ultima coisa que você escreveu é o retorno. Quanto as Strings talvez que tenha sido programador PHP como eu pode entender melhor. Este é o recurso chamado de GStrings. Que tal um pouco mais em ? Vamos lá então.
Agora a classe Pessoa só tem atributos, desta vez estou adicionado um método a uma classe existente(Pessoa) em tempo de execução. Eu estou implementado o método toString e acreditem funciona. Como é possível? Este é o Duck Typing em ação. Vamos ver mais...
Agora eu peguei o mesmo código que estava em uma classe e simplifiquei mais ainda. Como ? Colocando todo o código em uma Closure. Outra coisa legal é que o ";" e os "(" e ")" são opcionais pode colocar ou não que vai funcionar.
Duck Typing: Na programação fortemente tipada como é no caso do Delphi, C e Java. Ganhamos com algumas coisas mas perdemos em flexibilidade e muitas vezes o código é mais massivo e menos legível, você costuma ter que escrever mais para dizer as suas intenções a linguagem. Com tipagem forte os métodos de um objeto são definidos pelas sua classe superior(herança) e suas interfaces(além dos próprios métodos) e isto é fixo de certa forma. Com o Duck type isto depende do estado corrente do objeto. Isso mesmo pode ser que hora um objeto Pessoa tenha 10 métodos e pode ser que em outra hora ele tenha 15.
GStrings: É outro recurso fantastico do Groovy que da muita produtividade e simplicidade ao nosso código. Este é o recurso de ter String no stilo PHP. Você usa o operador "$" com "{}" e pode colocar uma váriavel ou expressão complexa dentro das chaves e ele resolve isso tudo dentro da mesma String. Vamos ver mais um exemplo de código:
Como você pode ver neste código estou usando uma classe do Java no meio da GString e também resolvendo uma variável Groovy. Neste caso a ligibilidade do código fica muito maior também, mais simples e mais divertido. :)
Suporte nativo a Mapas e Listas: Mais um grande recurso do Groovy. Acredito que o próprio sub-titulo ja explique por si só o que isso significa, mas vamos ver alguns códigos em Groovy para sentir na prática do que eu estou falando.
Neste código a cima estamos criando uma lista sem ter que instancia uma classe diretamente, isso é feito pelo Groovy. Depois estou usando o método each que a lista tem e passo um closure para que ele execute a cada item que existe na lista. A viariável implicita *it* representa a variável corrente neste caso o elemento da lista que esta sendo iterado.
Neste código estou aidionando e removendo itens a lista, no final faço um código para procurar na lista um elemento chamado "Diego" e percorendo este resultado e imprimindo na tela no final. Vamos ver o suporte a mapas agora.
Neste código criei um mapa e adicionei as chaves 1, 2 e 3 com os valores Diego, Bruna e Pog. Depois usei a função each e percorri todo o mapa mostrando as chaves e valores. Vamos ver mais algumas coisas de mapas de forma diferetne agora:
Estou adicionando um item ao mapa de maneira muito fácil e igual a da lista e desta vez estou percorrendo o mapa com o *it* implicito do Groovy.
Novas funcionalidades na API do Java: Bom algumas coias vocês já viram como os métodos *each*, *findAll*. Existem outros métodos bem úteis como por exemplo: Quando você trabalha com File existe o método eachFile para percorrer todos os Files de um File pai. Confira também as seguintes formas de loop:
Outra coisa legal é o Switch para Strings, confira o código Groovy a baixo:
Sobrecarga de operadores: É um dos recursos mais fantasticos do Groovy. Com isso a legibilidade e fluencia ficam em alta mesmo. Isso pode ser feito não apenas com numeros mas com qualquer classe. Veja o código a baixo:
Operações Null-safe: Quem gosta de ver um bom NPE(Null Pointer Exception) na tela? A solução para isso é fazer diversos ifs para testar o estado dos objetos antes de acessar métodos e própriedades do mesmo. Porem com Groovy isto não é necessário por que existe um operador para isso, basta colocar o "?" na frente que tudo se resolve.
Bom pessoal e existe muito mas mauito mais. O Legal do Groovy é isso estas novas funcionalidades, facilidades, integração com Java. Basta colocar um jar na sua aplicação e pronto você já pode aproveitar tudo isso.
Fiz uma apresentação sobre este assunto, confira no meu slide-share:
Se você quizer saber mais sobre Groovy pode conferir estes posts aqui:
Abraços e até a Próxima.
Criar código fluente e claro pode ser especialemte desafiador. É facto que certas linguagens facilitam ou dificultam esta tarefa, Java não é a linguagem mais fluente do mundo mas existem alternativas. No post anterior eu ensinei a criar uma DSL com Java sem nenhum framework e com batsante fluencia.
Neste post quero comentar sobre a linguagem dinamica Groovy que é a referência padrão de linguagens dinamicas para a JVM. Existem outras bem funcionais e interessantes como JRuby, BeanShell, Jython, Scala e tantas outras. Em especial hoje vou falar de Groovy, por que?
Por que como desenvolvedor Java este foi o primeiro contato com linguagens dinamicas sobre a JVM. Vejo de uma forma muito natual que o desenvolver nos dias de hoje busque outras soluções que não sejam unicamente dentro da linguagem Java. Mas de certa forma é muito claro para mim que utilizar a JVM é um ótima idéia, usar linguagens dinamicas que rodam em cima da JVM e tem integração com Java e os principais Frameworks existentes em Java com Spring e Hibernate é melhor ainda, este é o caso do Groovy.
Groovy é um linguagem que roda em cima da JVM, então é claro e obvio que ela não é a linguagem mais performatica do mundo, mas muitas vezes o problema esta em outro lugar, na persitência, no servidor, enfim... não é o fato da linguagem ser interpretada que deixa o uso da mesma inviável.
Por sinal o Groovy pode ser usando tanto interpretado como um script ou pode ser compilada pelo groovyc e rodar como uma class Java normal. Java é OO e Groovy também. Porem o Groovy é hibrido e você pode programar de forma procedural, o que de facto é muito útil para construção de scripts e na própria produtividade.
Groovy possui várias vantagens entre elas:
- Suporte nativo a Closures
- DRY
- Duck Typing
- GStrings
- Suporte nativo a Mapas e Listas
- Novas funcionalidades na API do Java
- Sobrecarga de operadores
- Operações Null-safe
<br /> def somar = { va , vb -> <br /> println va + vb <br /> } <br /> <br /> somar 1, 2<br />
Este código a cima mostra um exemplos simples de Closure em Groovy. Se você executar este código no groovyConsole por exemplo vai aparecer 3 no console como resultado.
DRY:Don't Repeat Yourself é um conceito bem interessante que as novas soluções vem implementado. Este conceito se baseia em elimitar a duplicação em todos os sentidos. Em java sofremos muito com isso quando usamos diversos frameworks baseados em XML(ex: clássico Spring, Hibernate, Struts, web.xml, etc..). Mas este conceito não se aplica apenas a parte de configuração. Este conceito aparece no The Pragmatic Programmer. Bom se você não leu este livro ainda não perca tempo e compre agora e leia o quanto antes. Neste caso foco em DRY por que isto leva a um código mais legível também e isso também foi incorporado ao Groovy.
<br>package com.blogspot.diegopacheco.javapain;<br><br>public class Pessoa{<br> <br> private String nome;<br> private Integer idade;<br> <br> public Pessoa(){<br> <br> }<br> <br> public Pessoa(String nome,Integer idade){<br> this.nome = nome;<br> this.idade = idade;<br> }<br> <br> public String getNome(){<br> return nome;<br> }<br> <br> public void setNome(String nome){<br> this.nome = nome;<br> }<br> <br> <br> public Integer getIdade(){<br> return idade;<br> }<br> <br> public void setIdade(Integer idade){<br> this.idade = idade;<br> }<br> <br> public String toString(){<br> return "Nome:" + nome + ", idade: " + idade;<br> }<br> <br> }<br>
Este é um tipico código que escrevemos em Java. Não vou entrar em discussões mais DDD, modelo anemico e tudo mais, isso é assunto para outros posts, mas. Mesmo com DDD ainda existe a possibilidade de não existirem validações e código de negocio nesta classe. Muitas vezes fazemos métodos getters and setters mas sem código dentro.
Este código acima é Java, mas funciona perfeitamente em Groovy. Porem em Groovy poderiamos fazer algo assim por exemplo:
<br>public class Pessoa{<br> <br> def String nome;<br> def Integer idade;<br> <br> public Pessoa(){<br> <br> }<br> <br> public Pessoa(String nome,Integer idade){<br> this.nome = nome;<br> this.idade = idade;<br> }<br> <br> public String toString(){<br> return "Nome:" + nome + ", idade: " + idade;<br> }<br> <br>}<br><br>Pessoa p = new Pessoa();<br>p.setNome("Diego Pacheco");<br>p.setIdade(25);<br>System.out.println(p);<br>
Ok. Mas cade os getters e setters? Isto compila? Roda sem levantar Exceptions? Sim compila e roda sem exceptions, funciona exetamente igual ao código acima, porém não precisamos escrever os códigos de getters e setters, já que não temos regras nem validações lá. Isso pode ficar ainda melhor veja o outro código Groovy a baixo:
<br>public class Pessoa{<br> <br> def nome, idade;<br><br> public String toString(){<br> return "Nome:" + nome + ", idade: " + idade;<br> }<br> <br>}<br><br>p = new Pessoa(nome: "Diego", idade: 25);<br>println p<br>
Cade o código dos construtores? Como que isso funciona? O Groovy resolve estas questões para nos, tirando algumas coisinhas chatas da linguagem Java e nos dando mais produtividade e legibilidade. Mas vamos melhorar mais? É possível?
<br>public class Pessoa{<br> <br> def nome, idade;<br><br> String toString(){<br> "Nome: ${nome} idade: ${idade}"<br> }<br> <br>}<br><br>p = new Pessoa(nome: "Diego", idade: 25)<br>println p<br>
Cade o return? E outra coisa onde estão as concatenações de Strings usando o operador "+"? Bom quanto ao return ele é opcional, o Groovy assume que a ultima coisa que você escreveu é o retorno. Quanto as Strings talvez que tenha sido programador PHP como eu pode entender melhor. Este é o recurso chamado de GStrings. Que tal um pouco mais em ? Vamos lá então.
<br>class Pessoa {<br> def nome, idade;<br>}<br><br>Pessoa.metaClass.toString = {<br> return "Nome: ${nome} idade: ${idade} . executou"<br>}<br><br>println new Pessoa(nome: "Diego", idade: 25).toString()<br>
Agora a classe Pessoa só tem atributos, desta vez estou adicionado um método a uma classe existente(Pessoa) em tempo de execução. Eu estou implementado o método toString e acreditem funciona. Como é possível? Este é o Duck Typing em ação. Vamos ver mais...
<br>def toString = { nome, idade -><br> println "${nome} - ${idade}"<br>}<br><br>toString "Diego", 25<br>
Agora eu peguei o mesmo código que estava em uma classe e simplifiquei mais ainda. Como ? Colocando todo o código em uma Closure. Outra coisa legal é que o ";" e os "(" e ")" são opcionais pode colocar ou não que vai funcionar.
Duck Typing: Na programação fortemente tipada como é no caso do Delphi, C e Java. Ganhamos com algumas coisas mas perdemos em flexibilidade e muitas vezes o código é mais massivo e menos legível, você costuma ter que escrever mais para dizer as suas intenções a linguagem. Com tipagem forte os métodos de um objeto são definidos pelas sua classe superior(herança) e suas interfaces(além dos próprios métodos) e isto é fixo de certa forma. Com o Duck type isto depende do estado corrente do objeto. Isso mesmo pode ser que hora um objeto Pessoa tenha 10 métodos e pode ser que em outra hora ele tenha 15.
GStrings: É outro recurso fantastico do Groovy que da muita produtividade e simplicidade ao nosso código. Este é o recurso de ter String no stilo PHP. Você usa o operador "$" com "{}" e pode colocar uma váriavel ou expressão complexa dentro das chaves e ele resolve isso tudo dentro da mesma String. Vamos ver mais um exemplo de código:
<br>def x = 10;<br>println "Hoje eh: ${new java.util.Date().toString()} - ${x}"<br>
Como você pode ver neste código estou usando uma classe do Java no meio da GString e também resolvendo uma variável Groovy. Neste caso a ligibilidade do código fica muito maior também, mais simples e mais divertido. :)
Suporte nativo a Mapas e Listas: Mais um grande recurso do Groovy. Acredito que o próprio sub-titulo ja explique por si só o que isso significa, mas vamos ver alguns códigos em Groovy para sentir na prática do que eu estou falando.
<br>def lista = [1,2,3,4,5,"Diego",'D',true,new Object(),{}]<br>lista.each {<br> println it<br>}<br>
Neste código a cima estamos criando uma lista sem ter que instancia uma classe diretamente, isso é feito pelo Groovy. Depois estou usando o método each que a lista tem e passo um closure para que ele execute a cada item que existe na lista. A viariável implicita *it* representa a variável corrente neste caso o elemento da lista que esta sendo iterado.
<br>def lista = [1,2,3,4,5,"Diego",'D',true,new Object(),{}]<br><br>lista += 6 // adiciona o item 6 a lista<br>lista -= 1 // remove o item 1 da lista <br>lista << 7 // adiciona o item 7 a lista<br></p><p><br>lista.findAll { it == "Diego" }.each {<br> println it<br>}<br>
Neste código estou aidionando e removendo itens a lista, no final faço um código para procurar na lista um elemento chamado "Diego" e percorendo este resultado e imprimindo na tela no final. Vamos ver o suporte a mapas agora.
<br>def mapa = [1: "Diego", 2: "Bruna", 3: "Pog"]<br>mapa.each{ k, v -><br> println "Chave: ${k} - valor: ${v}"<br>}<br>
Neste código criei um mapa e adicionei as chaves 1, 2 e 3 com os valores Diego, Bruna e Pog. Depois usei a função each e percorri todo o mapa mostrando as chaves e valores. Vamos ver mais algumas coisas de mapas de forma diferetne agora:
<br>def mapa = [1: "Diego", 2: "Bruna", 3: "Pog"]<br><br>mapa += [4: "teste"]<br><br>mapa.each{<br> println "Chave: ${it.key} - valor: ${it.value}"<br>}<br>
Estou adicionando um item ao mapa de maneira muito fácil e igual a da lista e desta vez estou percorrendo o mapa com o *it* implicito do Groovy.
Novas funcionalidades na API do Java: Bom algumas coias vocês já viram como os métodos *each*, *findAll*. Existem outros métodos bem úteis como por exemplo: Quando você trabalha com File existe o método eachFile para percorrer todos os Files de um File pai. Confira também as seguintes formas de loop:
<br /> array = (0..4).toArray()<br /> x = 0<br /> for ( i in array ) {<br /> x += i<br /> }<br /> <br /> x = 0<br /> for ( i in [0, 1, 2, 3, 4] ) {<br /> x += i<br /> }<br /> <br />
Outra coisa legal é o Switch para Strings, confira o código Groovy a baixo:
<br>String nome = "Diego"<br>switch(nome){<br> case "joao":<br> println "teste 1"<br> break<br> case "Diego":<br> println "teste 2" <br> break<br>}<br>
Sobrecarga de operadores: É um dos recursos mais fantasticos do Groovy. Com isso a legibilidade e fluencia ficam em alta mesmo. Isso pode ser feito não apenas com numeros mas com qualquer classe. Veja o código a baixo:
<br>class Pessoa{<br> def nome, namorado<br> <br> def leftShift(n){<br> namorado = n<br> }<br> <br> def mostrarDados(){<br> println "Nome: ${nome} Namora: ${namorado.nome}"<br> }<br>}<br><br>def p1 = new Pessoa(nome: "Diego")<br>def p2 = new Pessoa(nome: "Bruna")<br><br>p1 << p2<br>p1.mostrarDados()<br>
Operações Null-safe: Quem gosta de ver um bom NPE(Null Pointer Exception) na tela? A solução para isso é fazer diversos ifs para testar o estado dos objetos antes de acessar métodos e própriedades do mesmo. Porem com Groovy isto não é necessário por que existe um operador para isso, basta colocar o "?" na frente que tudo se resolve.
<br>class Pessoa{<br> def show = {<br> println "groovy show"<br> }<br>}<br><br>def p = new Pessoa()<br>def x = null<br><br>p.show()<br>x?.show()<br>
Bom pessoal e existe muito mas mauito mais. O Legal do Groovy é isso estas novas funcionalidades, facilidades, integração com Java. Basta colocar um jar na sua aplicação e pronto você já pode aproveitar tudo isso.
Fiz uma apresentação sobre este assunto, confira no meu slide-share:
Se você quizer saber mais sobre Groovy pode conferir estes posts aqui:
- Consumindo Webservices em Groovy com GroovyWS
- Scripts Groovy
- Atualizando o Twitter com Groovy
- Proxy/Interceptor à la carte com Groovy
- Swing Fácil com Groovy: Como criar seus próprios componentes
- Backup fácil no Ubuntu com Groovy e Groosh
- Threads e Closures em Groovy
Abraços e até a Próxima.