Comentário interessante Java x Ruby

[quote=saoj]Dá ou não dá para ter ActiveRecord em Java ???
Alguém poderia postar um exemplo de como ActiveRecord funciona na prática ?[/quote]

Claro, imagine que você têm uma tablea chamada clientes, com os campos id, nome, nascimento. No ActiveRecord seria:

class Cliente < ActiveRecord::Base end
Editado: Isso mesmo, sem declarar nem as variáveis. O código está completo (como todos os outros códigos).

Agora digamos que você quer ter certeza que o campo nome e nascimento sejam preenchidos.

class Cliente < ActiveRecord::Base validate_presence_of :nome, :nascimento end

obs: Existe vários validade_ e você ainda pode fazer os seus.

Agora, digamos que vc crie uma tabela "pedidos", aonde tem um foreing key para cliente (cliente_id).

[code]class Cliente < ActiveRecord::Base
validate_presence_of :nome, :nascimento
has_many :pedidos
end

class Pedido < ActiveRecord::Base
belongs_to :clientes
end[/code]

Por default já existe um método find generico, mas você pode escrever seus proprios finds. Exêmplo:

[code]class Cliente < ActiveRecord::Base
def self.find_by_nome(user_name)
find(:all, :conditions => [ "name = ?", user_name])
end

def self.find_by_id(user_id)
find(:first, :conditions => [ "id = ?", user_id])
end
end[/code]

Obs: O ActiveRecord já tem como fazer load por id, mas eu criei esse só pra exemplifica a diferença entre :all e :first.

E o mais legal são os acts_as, aonde vc pode dizer o comportamento daquela entidade (pode ser tree, taggable, searchable, etc…). Que você define assim:

class Artigo &lt; ActiveRecord::Base acts_as_searchable end

Então essa classe é indexada por um indexador de full text (tipo lucene for ruby), e é so utilizar assim:

Outro legal é o acts_as_taggable, que se não me engano é mantido pelo CV.

E é fácil criar os seus próprios acts_as.

E tem mais, tem por exemplo os campos created_at e updated_at, que se tiver na sua tabela ele preenche automaticamente.

Bom, qualquer error ai, perdão. Eu ainda sou muito novato em Ruby (pra ser honesto, terminei de ler o capitudo sobre ActiveRecord ontem).

obs: Tudo é guiado por padrão, e se o padrão que vc usa não é esse, você pode configurar (tanto o seu padrão, quanto o resto).

http://jroller.com/page/buggybean/20050710#activemapper_part_1_automatic_mapping

Isso parece muito com Hibernate, com a diferença é que vc não precisa definir/configurar nenhuma campo.

[quote=saoj]http://jroller.com/page/buggybean/20050710#activemapper_part_1_automatic_mapping
Isso parece muito com Hibernate, com a diferença é que vc não precisa definir/configurar nenhuma campo.[/quote]

Mesmo assim não é ActiveRecord, só é parecido. Os metodos de find,save,delete não estão no tipo, ainda precisa de um DAO. Não é dinámico, você precisa definir as variáveis e os gets e sets. Não têm acts_as, validade_ e eu não consigo imaginar como deve ser relacionamentos entre classes.

Mas não deixa de ser uma solução legal, mas ainda não é tão fácil é produtiva quanto ao ActiveRecord.

Como eu disse antes, é impossível se ter ActiveRecord no Java, por causa do próprio Java. Isso não é uma coisa ruim.

Lembre-se, ActiveRecord é só um detalhezinho do Rails, tem ainda um bocado de coisas que o fazem muito bom para aplicações web database-driven.

Mas, certamente não é nenhuma bala de prata.

Sim. Isso está mais para Hibernate sem configuração do que para ActiveRecord.

O meu DBBean está mais para ActiveRecord porque o save/load/delete estão no tipo.

Vc não precisa definir as variáveis no ActiveRecord ???


public class Person {

private int id;

private String username;

}

Não, não precisa. O que torna ele bem iterativo. Se algum campo novo aparecer, é só criar na tabela.

Os códigos que postei no exêmplo estão completos.

Ok. Legal isso. Mas onde vc define em que banco/connection/tabela ele deve pegar os campos do bean ?

Isso eu acho que é a questão do Convention over Configuration. Ele deve pegar como padrão tabelas com o mesmo nome da classe, colunas com o mesmo nome dos atributos, etc. Já o servidor e o nome do banco você tem que configurar, se não me engano.

O rails têm uma estrutura de diretórios padrão (veja aqui essa estrutura), e existe um arquivo /config/database.yml aonde você configura três banco, um para desenvolvimento, um para testes e um para produção.

O arquivo é mais ou menos assim:

development: adapter: mysql database: noc_dev host: localhost username: root password: test: adapter: mysql database: noc_tests host: localhost username: root password: production: adapter: mysql database: noc host: localhost username: root password:

[quote=saoj][code]

public class Person extends DBBean {

private DBField id = new DBField(this, “id”, DBType.INTEGER);
private DBField username = new DBField(this, “username”, DBType.STRING);

}

[/code]

Assim vai funcionar bonito, mas tá longe de se parecer com ActiveRecord. Não é nem um pouco “puro” tb.
[/quote]Pode funcionar, mas bonito eu não achei nao… :smiley:

[quote=David][quote=saoj][code]

public class Person extends DBBean {

private DBField id = new DBField(this, “id”, DBType.INTEGER);
private DBField username = new DBField(this, “username”, DBType.STRING);

}

[/code]

Assim vai funcionar bonito, mas tá longe de se parecer com ActiveRecord. Não é nem um pouco “puro” tb.
[/quote]Pode funcionar, mas bonito eu não achei nao… :D[/quote]

Sim. Funciona mas não é bonito nem puro. É isso que estamos querendo evitar aqui.

Pensando algo rápido:


public class Person extends DBBean {


}

Daí o DBBean descobre por reflection o nome da classe (Person), recebe uma connection por IoC, vai no banco, pega os campos da tabela, constroi uma lista de DBFields, cacheia isso, etc e tal.

Estaríamos chegando mais perto do ActiveRecord assim, creio eu…

Exato. Nome da classe no singular, nome da tabela no plural. Nome dos atributos igual ao nome das colunas. Tipos idem. Chave primaria eh “id” por default. E assim por diante. Se voce usar o padrao dele, funciona sem configurar nada. Mas voce pode configurar se nao gostar do padrao (eu p.ex., prefiro nome das tabelas no singular).

Agora, isso nem eh o mais interessante. Os finders automaticos e os relacionamentos que ele cria, p.ex., sao muito uteis.

Dados de conexao do banco (tipo, host, banco, usuario, senha) precisam ser configurados (tem um arquivo especifico pra isso, config/database.yml, basta abrir e alterar).

Marcio Kuchma

[quote=saoj]
Pensando algo rápido:

public class Person extends DBBean { }

Daí o DBBean descobre por reflection o nome da classe (Person), recebe uma connection por IoC, vai no banco, pega os campos da tabela, constroi uma lista de DBFields, cacheia isso, etc e tal.

Estaríamos chegando mais perto do ActiveRecord assim, creio eu…[/quote]

Não, ainda falta os gets e sets, os finds… Java não é uma linguagem dinâmica. Falta os acts_as_ or validades_…

Já o Grails, é uma solução bem legal também. Pelo menos na teoria (eu nunca utilizei).

Não é necessário ter getters e setters. Eu até prefiro que não tenha. Por que não acessar diretamente os atributos private? O Hibernate, por exemplo, permite fazer coisas assim.

Entendi. Teria que criar os sets/gets dinamicamente, e isso não dá em Java, certo ?

A não ser que alterássemos o byte code em tempo de execução tipo JDO.

Alguém aqui tem experiencia com isso ?

Sim, mas para utiliza-los eles teriam que ser publicos (ou protected) ou ter get/set. De qualquer forma você têm que definir os atributos.

Mas, em Java, não utilizar get/set pode ser problema. Os frameworks que você vai utilizar esperam que haja get/set para seu attributos. (Um SpringMVC da vida, até mesmo o Struts). Ao não ser que você não exponha as suas entidades pro seu framework. Ai, você teria que desenvolver mais uma camada… mas trabalho.

Exato. E eh ai que comecamos a sentir o poder do Ruby e outras linguagens mais “dinamicas” em relacao ao Java. Vai chegar um ponto em que os recursos de reflection do Java nao vao dar conta (como os finders dinamicos). Claro, sem contar a questao da clareza do codigo.

Eh isso que as vezes o pessoal nao entende. Nao eh questao de “menos linhas” simplesmente - eh a “expressividade” da linguagem, digamos assim. Coisas como essa que estamos discutindo, que envolvem meta-programacao, tornam-se muito mais simples nesse tipo de linguagem. Pra desenvolver infra-estrutura seria uma mao-na-roda contar com recursos como classes abertas e modulos (modulos Ruby especificamente).

Ha uns dias quis criar um componente Table Swing que mantivesse-se sincronizado com uma lista de objetos e vice-versa de forma transparente, sem depender da interferencia do programador da aplicacao. A saida que achei foi utilizar a cglib.

Coisas como AOP causam “frisson” na comunidade Java, mas sao recursos para simplesmente contornar limitacoes da linguagem no campo da meta-programacao. Em linguagens como Ruby, Lisp, Smalltalk, Python, etc, isso nao faria sentido.

Marcio Kuchma

Certo.

[quote=saoj]A não ser que alterássemos o byte code em tempo de execução tipo JDO.
Alguém aqui tem experiencia com isso ?[/quote]

Também não dá. Em tempo de execução seria até possível, mas quando você tiver programando, como você vai fazer? Vai dar erro de compilação por que o método(get/set) ou o atributo não existe.

Mas há uma luz no fim do túnel, no Java6 o APT pode modificar uma classe, e esse auto-mapeamento poderia ser feito pelo APT. Mas só no Java 6.

Não adianta, Sérgio, por causa do static bingind o compilador vai esperar que a classe chamada tenha o método para compilar sua classe, este método não pode ser criado dinamicamente.

O que dá pra fazer é usar algo como o APT ou um outro pré-processador mas aí eu acho que você está tentando tornar uma linguagem estáatica dinâmica e se for rpa fazer isso é melhor usar Groovy ou JRuby.

Boa. O futuro promete. A estrutura da JVM esta evoluindo pra suportar mais facilmente outras linguagens. Essa eh a saida para essa questao. Eu pessoalmente acho que na linguagem Java nao da pra ter, e nem mesmo da pra querer ter, esse tipo de recurso. As grandes empresas querem eh compatibilidade retroativa, estabilidade nos recursos da linguagem, mao-de-obra em abundancia que entenda a sintaxe (pelo menos) da linguagem.

Entretanto a plataforma Java pode avancar suportando linguagens mais dinamicas. Utilizar a plataforma Java, a tecnologia da JVM e uma linguagem como Ruby ou Python [editado: ou Groovy], seria o melhor dos mundos, dentre as possibilidades viaveis.

Marcio Kuchma

[quote=pcalcado]Não adianta, Sérgio, por causa do static bindind o compilador vai esperar que a classe chamada tenha o método para compilar sua classe, este método não pode ser criado dinamicamente.

O que dá pra fazer é usar algo como o APT ou um outro pré-processador mas aí eu acho que você está tentando tornar uma linguagem estáatica dinâmica e se for rpa fazer isso é melhor usar Groovy ou JRuby.[/quote]

Concordo plenamente, com execão do JRuby, e não vejo nenhum problema em se utilizar Ruby se for melhor e assim. Java é java, ruby é ruby. E viva as diferenças.