Archive

Archive for the ‘Groovy’ Category

Tipos de Scaffold com Grails

September 21st, 2011 No comments

No último sábado, dia 17/09/2011 fizemos um HandsOn do JUGMS com Groovy 1.8 e Grails 2.0.0.M2. Vimos desde o básico, começando com um overview de Groovy e depois vendo o basicão de Grails. Como muitas dessas coisas não é muito dificil de conseguir ver na net, vou focar em coisas que nesse momento agregam um pouco mais de valor. Aí sim, depois que postar as coisas menos fáceis de achar na net, posso postar um projeto desde o início. Mas até lá (se esse lá chegar) tem um monte de vídeo bacana na net com esse início.

Uma coisa bacana dessas ferramentas modernas como RoR, Grails, Roo, e mais um monte, é o scaffold. Mas apesar de ser meio carne de vaca, vou tentar falar disso mostrando umas coisinhas a mais.



Scaffold

Esse conceito foi copiado da engenharia civil, e quer dizer andaime. Eles servem para sustentar os trabalhadores enquanto a estrutura final não está pronta, ou seja, é algo temporário, um quebra galho.
Na programação é a mesma coisa… uma estrutura temporaria que serve para que possamos nos focar no mais importante em vez de ficar metade do tempo do projeto enfeitando CRUD. Ao mesmo tempo que os scaffolds são massa pra caramba numa primeira olhada, logo depois começamos a passar uma certa raiva com o código gerado, pois mais cedo ou mais tarde temos que mexer nesse código. Bom, para lidar melhor com isso vamos dar uma olhada em três formas de scaffold que podemos usar com o Grails.

Para mostrar um código mais próximo do real vou usar como exemplo o projeto jugmotors (criado no HandsOn) e suas respectivas classes de domínio.



1. Scaffold estático

Esseé o mais basicão de todos. É o que conseguimos ao executar

grails genereate-all jugmotors.Pedido

Isso gera o controlador PedidoController e as views correspondentes às operações de CRUD.
Ponto positivo: o código está ali, pronto para você customizar
Ponto negativo: se você mudar a domain class o CRUD vai ficar desatulizado, faltando campos, e aí vem erro ao salvar por campos requeridos não estarem na tela, etc.



2. Scaffold dinâmico

Em vez de gerar tudo, só crie um controlador assim:

class ModeloController {
    static scaffold = true
}

Nesse caso, como o controlador tem o mesmo nome (fora o sufixo) que a domain class Modelo, automaticamente será gerado todo o scaffold em tempo de execução. Se o controlador não tivesse o mesmo nome, você teria o mesmo efeito com:

class AlgumNomeController {
    static scaffold = Modelo
}

O legal é que a gente pode ir sobrescrevendo cada elemento do scaffold, como uma action do controlador ou então uma view do CRUD, ou só a show.gsp, ou só a list.gsp e assim sucessivamente.

Ponto positivo: você pode alterar livremente a classe de domínio que o scaffold se adapta automaticamente, pois não existe um código “físico” executando.
Ponto negativo: se não tivermos outro scaffold estatico gerado para ter noção do código que vai ser executado, acabamos ficando vendidos, pois não vemos o código. Pelo mesmo motivo, quando formos sobrescrever algum elemento do scaffold, podemos esquecer algum passo importante.



3. Install-templates

Tá certo que esse não chega a ser um tipo de scaffold, mas executando

grails install-templates

A gente ganha os pontos positivos do scaffold estatico e do dinâmico. Tanto o código gerado no scaffold estático, quanto o que executa no dinâmico (apesar de não vermos) veem dos templates. Esses templates ficam dentro da instalação do grails, mas quando executamos esse script copiamos ele para dentro do projeto. A partir de então, toda vez que mandarmos o grails fazer alguma coisa, como gerar um controlador, view ou mesmo um scaffold inteiro, ele vai usar o template do projeto, e não do grails. Obviamente ele primeiro olha no projeto e se não encontrar vai para o grails.

No projeto jugmotors, eu fiz um scaffold estático sem customização: pedido; e um customizado: modelo.

O CRUD de pedido eu deixei como foi gerado, mas o de modelo eu fiz umas mudanças simples só para exemplificar a customização dos templates. Na view list.gsp eu coloquei as mesmas opções presentes na view show (editar e deletar). Então em vez da listagem padrão que só tem um link para a visualização, agora temos um botão que manda direto para e edição e um que apaga.

Depois de ter customizado essa tela, eu voltei para o código do template list.gsp e coloqui o mesmo estilo nele (não que esteja bom ou bonito, a ideia é exemplificar).

Agora se executarmos o CRUD de opcional, que é dinâmico, vemos que fica bem parecido com o de modelo. Agora se eu executar

grails generate-all <domain class>

O código gerado já vai sair de acordo com o meu novo template. Isso é muito legal, pois não temos que ficar “reféns” do código gerado pelo framework, pois agora o código é meu.

Ponto positivo: Tanto o scaffold estático quanto o dinâmico respeitam o nosso template :)
Ponto negativo: A gente vai ter um pouco mais de trabalho para fazer um template do que para fazer um arquivo comum, seja um gsp ou um groovy. Isso porque temos que prestar atenção nas expressões que escrevem outas expressões… então temos que usar muito escape. Exemplo simples do template list.gsp:

<g:link class="edit" action="edit" id="\${${propertyName}.id}">Editar</g:link>

Aqui no caso a propertyName se refere ao nome da propriedade do g:each que itera todos os objetos. Supondo que em tempo de execução propertyName seja igual a “pedidoInstance”, o resultado seria:

<g:link class="edit" action="edit" id="${pedidoInstance.id}">Editar</g:link>

Espero que a partir de agora a gente use mais essa funcionalidade de instalar os templates e assim customizá-los. E apesar de eu ter colocado somente o exemplo de customização de template de uma view, navegando dentro da pasta src/templates do projeto podemos ver os templates usados para criar classes de domínio, controladores, filtros, testes, etc. Logo, templates não são apenas para scaffold.

Mas pessoal, lembre do conceito do scaffold. A idéia é te entregar algo resoável para trabalharmos no mais importante. Então a menos que seja um CRUD muito sem vergonha é bom que você substitua o código gerado (mesmo customizado via template) pelo teu, que provavelmente vai ser melhor que o gerado.

Categories: Grails, Groovy Tags: ,

Palestra Grails Javaneiros 2008

December 8th, 2010 No comments

Então, sei que já faz mais de 2 anos (mais precisamente em 08/11/2008), mas como acabei não publicando o conteúdo dessa palestra na época, estou agora, impulsionado pelos desenvolvimento do JMeetings fazendo isso. Além disso tem um outro motivo. Esses tempos meu HD deu pau e quase perdi um monte de palestras antigas que por algum motivo não publiquei. Então estou aproveitando o fim de ano para limpar meus rascunhos e ir postando essas palestras antigas :)

De lá para cá obviamente muitas coisas mudaram, como por exemplo a utilização do servidor tomcat em vez do jetty como padão. Além disso logo depois da apresentação (três dias depois) a SpringSource comprou o G2One, que mantinha a linguagem Groovy e o Grails. E menos de um ano depois disso a SpringSource foi adiquirida pela VMWare.

Estarei postando assim que possível um vídeo mostrando como é simples desenvolver usando Grails. Ou pelo menos tão simples como poderia ser desenvolver em outras plataformas como RoR.

Categories: Grails, Groovy Tags:

Será que o Java 7/8 faz falta mesmo?

December 2nd, 2010 8 comments

Antes de mais nada sei que um ou outro pode querer me xingar sem nem ler o post. Esse post não serve para dizer que eu não quero que o Java evolua, que saiam novas versões, etc. Óbvio que isso é importante e por isso não vou nem discutir isso. Mas o ponto é: tem motivos para eu ficar choramingando lamentando a falta de recursos da linguagem, sem olhar para o que é mais importante, que é a plataforma? Ficar pensando porque essas mudanças nunca saem em vez de usar o que já temos hoje? A minha resposta pessoal é não, e o intuito deste post é explicar o porquê.

E porque eu coloquei Java 7 e 8 numa tacada só? Bom, talvez você não tenha acompanhado a novela da estratégia da Oracle para o Java 7. Resumindo, em vez de fazer um Java 7 pela metade “agora” ou um Java 7 completo para sabe-se lá quando, optou-se por fazer um “Java 7″ em duas fazes. Uma primeira que será o 7 e não vai ter muitas das coisas complicadas de implementar, e a segunda será o 8 e aí sim vai ter tudo que era esperado para o 7. Bem melhor do que demorar tudo que já demorou até hoje e ainda fazer “de qualquer jeito”.

Mas o artigo não é sobre Java 7/8 (vou tratar como uma única versão mesmo), e sim sobre a gente precisar ou não desesperadamente da nova versão da linguagem, e não das evoluções na plataforma. O que vou mostrar é que praticamente tudo que esperamos da próxima versão do Java (linguagem) já temos pronto em outras duas das principais linguagens para a JVM: Groovy e Scala.

Para esse artigo não ficar muito longo vou assumir que você está familiarizado com o fato da plataforma Java ser mais do que a linguagem Java. Mas já deixo na gaveta um post sobre a plataforma para deixar isso mais claro depois.

Além disso meu objetivo aqui não é escrever um post que explique em detalhes cada uma das funcionalidades citadas em cada uma das linguagens, e sim mostrar rapidamente cada coisa. Sendo assim reservo-me o direito de citar referências externas em vez de criar código de exemplo próprio :D



Geral

Para as próximas versões do Java existe o projeto Coin que reúne diversas melhorias para as próximas versões da linguagem. Algumas dessas mudanças estão contempladas nos tópicos abaixo.

Mas o fato é que o objetivo do Java não é ser uma linguagem como Groovy ou Ruby que tem diversas facilidades como elvis operator, safe navigation, reflection super facilitado, invocação do método equals usando == entre dezenas de outras coisas.

Talvez o mais parecido com Java seja Scala. Não em sintaxe, pois nesse quisito Groovy é quase igual Java. Agora o que Scala tem de mais parecido é o fato de ser estaticamente tipada, mas com um sintaxe simplificada, com alto poder inferência de tipos, sem ponto e vírgula obrigatório e que você na maioria das vezes nem percebe que não está usando uma linguagem dita mais “flexível” ou “dinâmica”.

Na minha opinião a maioria não quer especificar tipos, mas isso não quer dizer que necessariamente quer uma linguagem sem tipos. Nos artigos que escrevi de Scala dá pra ver bem dessas facilidades.



Closures

Um dos principais pontos, ou pelo menos o “mais famoso” ponto do Java 7 é o suporte à closures. Suporte que esse que durante a novela Java 7 já foi cortado, reintroduzido “nas coxas” e por fim vai estar completo no Java 8. Mas e se olharmos para Groovy e Scala? O suporte à closures está lá.

Java 8

Referência

#int() fortyTwo = #()(42);
#int(int) doubler = #(int x)(x + x);
#int(int,int) multiplier = #(int x, int y)(x * y);

assert fortyTwo() == 42;
assert doubler(fortyTwo()) == 84;
assert multiplier(3, fortyTwo()) == 126;

Update: o Paulo Silveira, há um bom tempo já, postou um material bem bacana em português sobre isso no blog da Caelum.

Groovy

Referência

def printSum = { a, b -> print a+b }
printSum( 5, 7 )                       //prints "12"

Referência

def c = { arg1, arg2-> println "${arg1} ${arg2}" }
def d = c.curry("foo")
d("bar")

Referência

def x = 2

// define closure and assign it to variable 'c'
def c = { numberToSquare -> numberToSquare * numberToSquare }

// using 'c' as the identifer for the closure, make a call on that closure
def y = c(x)       // shorthand form for applying closure, y will equal 4
def z = c.call(x)  // longhand form, z will equal 4

Scala

Esse código de exemplo eu postei aqui (to meio sem criatividade hoje :D ). Nele temos um método chamado percorreLista e uma closure chamada imprimeElemento, que é passada como parâmetro para o primeiro.

object Main extends Application {
    def percorreLista[T](lista:List[T], funcao:(T) => Unit)= {
    for (elemento <- lista) {
      funcao(elemento)
    }
  }

  val imprimeElemento = (elemento: Any) => {
    println(elemento)
  }

  percorreLista(List(2,3,4,5), imprimeElemento)
}



Automatic Resource Management (ARM)

Uma coisa chata de fazer em Java é trabalhar com IO. Vamos pegar como exemplo…

Java 6

Referências um e dois

Aqui temos que tratar as possíveis exceções todas na mão.

Lendo um arquivo

try
{
    String teamMember;
    FileReader fr = new FileReader("arquivo.txt");
    BufferedReader br = new BufferedReader(fr);
    while ((teamMember = br.readLine()) != null)
    {
        System.out.println(teamMember);
    }
}
catch (FileNotFoundException e)
{
    e.printStackTrace();
}
catch (IOException e)
{
    e.printStackTrace();
}
finally
{
    if (br!= null)
    {
        br.close();
        if (fr != null)
        {
            fr.close();
        }
    }
}

Agora um código JDBC

String connectionURL = "jdbc:mysql://localhost:3306/myDB";
Connection connection = null;
Statement st = null;
ResultSet rs = null;
try
{
    connection = DriverManager.getConnection(connectionURL, "root", "admin");
    st = connection.createStatement();
    rs = st.executeQuery("Select * from EMPLOYEE_SALARIES");
    while (rs.next())
    {
        System.out.println("EMPLOYEE_NAME/EMPLOYEE_SALARY");
        System.out.println(rs.getString(1) + "/" + rs.getString(2));
    }
}
catch (ClassNotFoundException ex)
{
    ex.printStackTrace();
}
catch (SQLException ex)
{
    ex.printStackTrace();
}
catch (InstantiationException ex)
{
    ex.printStackTrace();
}
catch (IllegalAccessException ex)
{
    ex.printStackTrace();
}
finally
{
    try
    {
        if (!rs.isClosed())
        {
            rs.close();
        }
        if (!st.isClosed())
        {
            st.close();
        }
        if (!connection.isClosed())
        {
            connection.close();
        }
    }
    catch (SQLException ex)
    {
        ex.printStackTrace();
    }
}
Java 8

Com o ARM ficaria bem mais simples.

Lendo um arquivo

String teamMember = null;
try (BufferedReader br = new BufferedReader(new FileReader("arquivo.txt")))
{
    while ((teamMember = br.readLine()) != null)
    {
        System.out.println(teamMember);
    }
}

Código JDBC com ARM

String connectionURL = "jdbc:mysql://localhost:3306/myDB";
try
(
    Connection connection = DriverManager.getConnection(connectionURL, "root", "admin");
    Statement st = connection.createStatement();
    ResultSet rs = st.executeQuery("Select * from EMPLOYEE_SALARIES");
)
{
    while (rs.next())
    {
        System.out.println("EMPLOYEE_NAME/EMPLOYEE_SALARY");
        System.out.println(rs.getString(1) + "/" + rs.getString(2));
    }
}
Groovy

Em Groovy fazer isso é extremamente simples

Lendo um arquivo

Referência

println new File('arquivo.txt').text

Lendo uma tabela com Groovy

Referência

import groovy.sql.Sql
sql = Sql.newInstance("jdbc:jtds:sqlserver://serverName/dbName-CLASS;domain=domainName", "username",
                     "password", "net.sourceforge.jtds.jdbc.Driver")
sql.eachRow("select * from tableName", { println it.id + " -- ${it.firstName} --"} );
Scala

Referências um e dois

Em Scala também é simples.

def using[T <: { def close() }]
    (resource: T)
    (block: T => Unit)
{
  try {
    block(resource)
  } finally {
    if (resource != null) resource.close()
  }
}

using(new BufferedReader(new FileReader("file.txt"))) { r =>
  var count = 0
  while (r.readLine != null) count += 1
  println(count)
}

Referência

val lines = for { file <- managed(new java.io.File("some.txt"))
       stream <- new java.io.FileInputStream(file)
       line <- makeLineIterator(stream) } yield line



Switch com String?

Sinceramente eu acho essa parte até meio brincadeira, pois é muito barulho para uma funcionalidade muito simples. Essa mudança faz parte do projeto Coin.

Java 7

A funcionalidade é simples, a única diferença é que agora suporta String.

Groovy

O suporte do Groovy é bem mais rico que o suporte à Strings. Claro que pode ser mais complicado num primeiro momento, cheio de possibilidades, mas para mim é só um comportamento mais completo, com tudo que se espera.

Referência

def x = 1.23
def result = ""

switch ( x ) {
    case "foo":
        result = "found foo"
        // lets fall through

    case "bar":
        result += "bar"

    case [4, 5, 6, 'inList']:
        result = "list"
        break

    case 12..30:
        result = "range"
        break

    case Integer:
        result = "integer"
        break

    case Number:
        result = "number"
        break

    default:
        result = "default"
}

assert result == "number"

E podemos ainda sobrescrever o método isCase(valor), que por default chama equals(valor)

class Estado{
    String uf
    def isCase(valor){
        uf == valor
    }
}

def estado = new Estado(uf: "MS")

switch ( estado ) {
    case "MS":
        println "Mato Grosso do Sul"
        break

    case "SP":
        println "São Paulo"
        break

    default:
        println "Sei lá..."
}
Scala

Scala assim como Groovy tem um mecanismo bem interessante que pode ser usado num switch, o Pattern Matching. Como isso vale um artigo a parte, recomendo a leitura desse post. Mas para exemplificar vou colocar um exemplo:

def checkPrime(number:Int) = number match {
  case 1 => true
  case 2 => true
  case 3 => true
  case 5 => true
  case 7 => true

  case _ => false
}

Comparando pelo tipo

var obj = performOperation()
var cast:Color = obj match {
  case x:Color => x
  case _ => null
}

Em Java o equivalente seria

Object obj = performOperation();
Color cast = null;
if (obj instanceof Color) {
    cast = (Color) obj;
}

E em Scala temos ainda as case classes, que são tipos especiais de classes, que dentro outras coisas não precisamos de new para instanciá-las e podem ser usadas direto com pattern matching.

Referência

case class Number(value:Int)

def checkPrime(n:Number) = n match {
  case Number(1) => true
  case Number(2) => true
  case Number(3) => true
  case Number(5) => true
  case Number(7) => true
  case Number(_) => false
}

checkPrime(Number(12))

Outro exemplo

class Color(val red:Int, val green:Int, val blue:Int)

case class Red(r:Int) extends Color(r, 0, 0)
case class Green(g:Int) extends Color(0, g, 0)
case class Blue(b:Int) extends Color(0, 0, b)

def printColor(c:Color) = c match {
  case Red(v) => println("Red: " + v)
  case Green(v) => println("Green: " + v)
  case Blue(v) => println("Blue: " + v)

  case col:Color => {
    print("R: " + col.red + ", ")
    print("G: " + col.green + ", ")
    println("B: " + col.blue)
  }

  case null => println("Invalid color")
}

printColor(Red(100))
printColor(Blue(220))

printColor(new Color(100, 200, 50))
printColor(null)

Saída

Red: 100
Blue: 220
R: 100, G: 200, B: 50
Invalid color



Properties

Suporte à properties é bem esperado mas já foi praticamente “limado” da lista de features que vão entrar nas próximas versões de Java. Na verdade o suporte à properties é mais do que vamos ver aqui. Um suporte completo permitiria a gente ter type safe criteria na JPA2 sem necessidade de geração de código. Mas com certeza esse suportezinho simples, à la Groovy, já ajuda bastante.

Java

Sem suporte. Getters and Setters

public class Pessoa{
  private String nome;
  private String endereco;
  private String nome;

  //getters e setterss gerados pela IDE.
  //Vocês já devem estar enjoados de ver, então vou economizar espaço e nem colocar esse código aqui
Groovy

Em Groovy fazer isso é extremamente simples. O compilador gera altomaticamente os getters e setters para atributos não privados. Depois de compilado fica igualzinho um “bean” java, atributos privados e métodos de acesso públicos.

class Pessoa{
  String nome
  String endereco

  //para essa propriedade não teremos getters e setters gerados
  private Integer idade

  //aqui fica igual os getters e setters gerados para nome e endereco.
  //Só lembrando que a tipagem em groovy é opcional
  def Integer getIdade(){ idade }
  def void setIdade(Integer idade){ this.idade = idade }
}
Scala

Em Scala também é simples.

class Pessoa(var nome:String,
             var localidade:String,
             private var _idade:Int) {
  //assim como no exemplo em Groovy, quando marcamos um atributo como privado os métodos de acesso não são gerados
  def idade = _idade
  def idade_=(idade:Int) = _idade = idade
}

val pessoa = new Pessoa("Gilliard", "Campo Grande/MS", 26)
pessoa.nome = "Gilliard Cordeiro"
pessoa.idade = 27
println( pessoa.localidade )



Performance

Tem mais um monte de coisas que eu poderia comentar mas essas são as primeiras que me ocorreram. Mas para finalizar, pelo menos por enquanto, vamos falar de performance.

Não encontrei nenhum benchmark atualizado para linkar aqui, mas no geral Java e Scala estão bem próximos em performance, com mais vantagem para o Java e em alguns casos Scala na frente. Já o Groovy é meio patinho feio nessa comparação entre as três linguagens, mas ainda assim – com base em benchmarks um pouco antigos – ele ainda é mais performático que PHP por exemplo. E eu nunca ouvi ninguém dizer que deixaria de usar PHP por causa de performance, mas quando se fala de Groovy esse assunto sempre surge.

Sobre Java e Scala nem vale muito a pena falar, mas os benchmarks envolvendo Groovy tem que ser encarados com cautela. Primeiro porque se o benchmark for meio antigo é bem possível que de lá pra cá a performance já melhorou bastante. Até porque quanto mais lento, mais espaço para melhorar um ambiente de execução tem. O segundo ponto é que em todos os comparativos sempre vejo código 100% linguagem A contra código 100% linguagem B. Já na prática dificilmente a gente vai ter uma aplicação com código 100% Groovy. Vamos pegar como exemplo uma aplicação feita em Grails. Minha bola de cristal diz que no total de código da aplicação (bibliotecas incluídas) nem 30% é Groovy.

Para complicar ainda mais a conta, você já viu o tamanho da StackTrace quando executamos nosso código num servidor de aplicações? O tanto de AOP, interceptors e outros serviços rodando ao mesmo tempo com certeza vai levar mais tempo do que a diferença entre a execução de duas linguagens diferentes. Por fim a maioria dos problemas de performance não é culpa do que se usa, e sim de como se usa uma ferramenta.

Update: Só mais uma “coisinha” sobre performance do Groovy. Existe também o Groovy++, que compila estaticamente partes do código Groovy (depende do que você anotar com @Typed) aumentando assim a performance consideravelmente pelo que li, mas não conheço na prática. Quando eu já tiver mexido com isso eu posto, mas até lá vocês podem ver alguma coisa aqui, aqui e aqui.



(Minha) Conclusão

Terminado então esse post, acho que ficou claro que, pelo menos para mim, sentimos falta de um ou outro recurso da linguagem mas, ou praticamente não vamos usar a função quando ela sair (pois não faz falta de verdade hoje), ou não conhecemos as outras opções que a plataforma, e não a linguagem Java nos dá. Pois se conhecermos as opções e realmente quisermos usar essas funcionalidades, não faz muito sentido não usar o que se tem.