25 de fevereiro de 2007

Queries nativas em Java.

Na onda de sugestões para facilitar o desenvolvimento de aplicações Java, veio em mente um projeto que eu e o Vitor gostaríamos de ter feito um tempo atrás. A idéia é oferecer queries nativas em Java, acabando com algumas fraquezas de consultas baseadas em String. Na verdade este projeto era para ter saído no lugar no SnailDB, mas como o objetivo era a gente se formar, acabamos priorizando o Snail para fechar créditos na disciplina de BD.

1) Uma limitação de consultas baseadas em String é que a checagem sintática e de tipos é feita em tempo de execução, um exemplo SQL:

"SELECT nome FROM Pessoa WHER idade > 20"

O desenvolvedor saberia do erro sintático no "WHER" apenas em tempo de execução. Outra questão são os erros semânticos, supondo que o desenvolvedor atribua o retorno de um registro desta consulta a uma variável de tipo "Integer", este erro também só aconteceria em tempo de execução.

2) Outra grande limitação é que os atributos utilizados nesta consulta não participam de uma processo de refatoração, artifício muito utilizado pelos desenvolvedores, deixando o processo de manutenção do código oneroso. Pense em refatorar o código da classe Pessoa, para o atributo "idade" ser "idadeEmAnos". Buuummmm, esta consulta passaria a dar erro!

A idéia de queries nativas é simples, as consultas são escritas com uma sintaxe que faz "parte" da linguagem, permitindo que checagem sintáticas e de tipos possam ser feita em tempo de compilação, assim como os atributos utilizados na consulta participem em um processo de refatoração. Segue um exemplo de consulta sobre uma coleção em memória, retornando todos os clientes iniciando com nome "Java":

Collection(Customer) customers; // prevayler poderia manter esta coleção =D
...
Collection(Customer) result = FROM customers c WHERE c.name LIKE "Java%";

O objetivo do post é salientar o benefício de um recurso como este, deixando de lado a sintaxe a ser utilizada.

Quais seriam os benefícios de queries nativas ?

1) Checagem sintática e semântica
: desenvolvedor teria um feedback rápido das "cagadinhas" feitas na consulta em tempo de compilação;

2) Facilidade de manutenção:
as IDEs poderiam manter referência aos atributos utilizados na consulta, permitindo a refatoração e outros artifícios para manutenção de código;

3) Facilidade de aprendizado:
este benefício vale aos desenvolvedores vindos de consultas SQL-based.

Meu deus, vamos alterar a especificação da linguagem ? Não.

1) Poderíamos fazer algo em cima do Java, que checasse as consultas no código antes do compilador Java, para então traduzir para um código Java válido;

2) Viajando um pouco mais, poderíamos traduzir esta consulta para algum banco de dados específico, talvez.

A galera do db4o fez algo muito legal, queries nativas através de código Java. Segue um exemplo:

Collection(Customer) result = database.query(Customer)(new Predicate() {
public boolean match(Customer customer) {
return customer.getName().startsWith("Java");
}
});

Eu gostaria de algo mais simples, que o desenvolvedor não precise escrever tanto e que você mais intuitiva para o recém chegados do SQL. Quem sabe juntar os dois mundos não dê frutos ?

Porque remexi nesta idéia novamente ? Foi lendo a a especificação do C# 3.0, os caras colocaram queries nativamente na linguagem, me parece ter ficado bem descente. O projeto deles é o LINQ. Um pequeno exemplo:

var result = from c in customers
where c.name == "Java"
select c;

E o mais legal é ver uma idéia que tivemos alguns anos atrás, sendo investida e dando frutos nas linguagens do momento.

Bom deixa eu ir, mulher ta em cima. Mas vou continuar pensando a respeito e postar algo mais concreto. Abraço.

28 comentários:

Vitor Fernando Pamplona disse...

Hehehe... isso seria algo "muito afudê" como dizem os gaúchos! :D

Muito bom! :D []s

Vitor Fernando Pamplona disse...

Acho que não ficou muito claro, a idéia é ter queries nativas sobre coleções, não tem nada a ver com banco de dados, tradução para SQL e essas aberrações :D.

Talvez para uma HQL, mas para isso há muito a desenvolver na idéia ainda.

Unknown disse...

Teríamos um "core" que define toda a sintaxe e comportamento de cada comando para consulta.

Uma outra coisa seria consulta sobre coleções em memória, que faria semântica da consulta sobre os objetos em memória.

E uma terceira coisa seria a consulta sobre banco de dados. Estaríamos utilizando o mesmo "core" para tudo =D !!! Só não tenho a mínima idéia como fazer análise semântica no BD, mas para isso que somos pagos !!! hehehe

Vitor Fernando Pamplona disse...

"pagos"

Dyego Souza do Carmo disse...

Descordo... essas "query nativas" sao feitas em cima de coleções e nao do banco de dados diretamente ( no caso do LINQ ) isso a primeira vista poderia ser uma grande coisa... porem quando voce for analizar a quantidade de cagadas que isso vai gerar... vai ficar abismado... nego nao vai pensar duas vezes em sair dando order by complexos comendo um processamento monstro e transformando tudo em um ELEFANTE lento...

Fora que a keywork var no C# 3.0 é simplesmente um tiro no pé... uma linguagem que se diz fortemente tipada com uma coisa dessas ? C# esta cada vez mais VB.NET...

O rescurso só é interessante quando BEM usado... e eu acredito que isso nunca vai acontecer... o que voce vai ter eh softwares intupidos desta porcaria e voce perdendo dias fazendo otimizacoes.

Unknown disse...

Bom, nao sei se tem alguem aki tao velho quanto eu :-) , mas se tem vai lembrar, bem antigamente o Visual FoxPro (bhearg!!! $#%$^#$%^#) utilizava isso! Sem duvida eh bem produtivo.

Dyego Souza do Carmo disse...

Programar em Visual Basic tmb é produtivo. e depois ?

Unknown disse...

Olá Dyego, seja bem vindo.

"...essas "query nativas" sao feitas em cima de coleções e nao do banco de dados diretamente ( no caso do LINQ )...."

O DLinq converte as queries nativas para SQL, claro que você manipula isso através de coleções, mas no fundo elas são uma fachada para o que está acontecendo realmente, que é acessar tabelas e campos no BD.

Inicialmente fazer queries nativas sobre coleções Java seria de grande tamanho e simples de implementar. O passo para converter para SQL eu sei que é complicado, mas perfeitamente viável. O usuário pode fazer cagada sem estar percendo, pode, assim como ele pode fazer cagada no SQL.

"...Fora que a keywork var no C# 3.0 é simplesmente um tiro no pé... uma linguagem que se diz fortemente tipada com uma coisa dessas ? C# esta cada vez mais VB.NET..."

O C# abriu o olho para uma coisa, produtividade. Para que fazer o programador dizer o tipo da variável, se a expressão de atribuição já diz isso implicitamente.

O var é fortemente tipado, ele analisa a expressão que está sendo atribuída a variável para determinar o tipo em tempo de compilação.

"...o que voce vai ter eh softwares intupidos desta porcaria e voce perdendo dias fazendo otimizacoes..."

Otimizições devem ser feitas onde realmente merecem ser feitas, no resto, deixa a produtividade rolar.

Unknown disse...

"...Bom, nao sei se tem alguem aki tao velho quanto eu :-) , mas se tem vai lembrar, bem antigamente o Visual FoxPro (bhearg!!! $#%$^#$%^#) utilizava isso! Sem duvida eh bem produtivo..."

Pois é jeronimo, este era um dos objetivos do post. "Como dar produtividade ao Java"

Dyego Souza do Carmo disse...

"O var é fortemente tipado, ele analisa a expressão que está sendo atribuída a variável para determinar
o tipo em tempo de compilação."

Me desculpe, mas nao tenho como encarar isso como fortemente tipado... receber uma "laranja" com casca de "melancia" e sabor de "maça" deve ser uma beleza dentro de um sistema complexo onde voce esta debugando por exemplo...

10 linhas para cima eh uma collection , 10 linhas para baixo vira um contador de um for....

produtivo ? com certeza... mas e depois ? manutencao disso ? estamos falando de programadores .net... nao Java... jah fazem xunxos por natureza... imagina com uma coisa destas...

Dyego Souza do Carmo disse...

"Inicialmente fazer queries nativas sobre coleções Java seria de grande tamanho e simples de implementar. O passo para converter para SQL eu sei que é complicado, mas perfeitamente viável. O usuário pode fazer cagada sem estar percendo, pode, assim como ele pode fazer cagada no SQL."

Em tempos de desenvolvimento usando JPA (Hibernate , Toplink , etc.. ) me diga um motivo para retornar os massantes SQL dependentes de bd's ?

A não ser em casos especificos... usar JDBC desta forma é simplesmente terrivel... e ter algo como um DLINKQ dentro de um DAO é besteira... criar mais uma camada soh para "pegar erro de sintaxe" ?
Teste automatizados servem para que ?

Dyego Souza do Carmo disse...

Detalhe , JDBC 4.0 se nao me enganho já faz populacoes diretamente em colecoes...

Unknown disse...

"...Me desculpe, mas nao tenho como encarar isso como fortemente tipado..."

Opinião, até na literatura o termo fortemente tipado tem várias definições.


"...receber uma "laranja" com casca de "melancia" e sabor de "maça"...

Discordo, você sabe o que está recebendo, além de não conseguir misturar "laranjas" com "maças". Mas concordo que ao bater o olho o programador nao sabe o tipo, vai ter que olhar para a expressão.


"...10 linhas para cima eh uma collection , 10 linhas para baixo vira um contador de um for....

Isso não é possível.

Unknown disse...

"...estamos falando de programadores .net... nao Java... jah fazem xunxos por natureza... imagina com uma coisa destas..."

Forçasse a barra amigo, embasado em que você fala uma coisa dessa ?

Dyego Souza do Carmo disse...

"Forçasse a barra amigo, embasado em que você fala uma coisa dessa ?"

Embasado no mercado de programadores VB 6.
preciso dizer mais alguma coisa ?

Dyego Souza do Carmo disse...

"Discordo, você sabe o que está recebendo, além de não conseguir misturar "laranjas" com "maças". Mas concordo que ao bater o olho o programador nao sabe o tipo, vai ter que olhar para a expressão."

O que as vezes torna a manutenção BEM massante.

Unknown disse...

"...Em tempos de desenvolvimento usando JPA (Hibernate , Toplink , etc.. ) me diga um motivo para retornar os massantes SQL dependentes de bd's ?..."

Todos estes que você citou melhoram bastante a produtividade, mas ainda sim as queries são string-based.

E não estou dizendo que a query nativa deve gerar SQL, estou dizendo que poderia existir um módulo que converte para SQL. Assim como poderia ter outro que converte para HQL (Hibernate), os benefícios disto já foram citados no post.


"...... criar mais uma camada soh para "pegar erro de sintaxe"..."

Os benefícios seriam maiores que este.

Unknown disse...

"...Detalhe , JDBC 4.0 se nao me enganho já faz populacoes diretamente em colecoes..."


Sim preenche, mas ainda sim as queries são string-based.

Dyego Souza do Carmo disse...

Dei uma olhada no funcionamento do var keyword do C# 3.0 final ( eu tinha visto no preview ) e realmente ele "tipa" para o primeiro "tipo" selecionado e mantem ele...

é uma Variant com dispositivo anti-cagada... achei interessante...

Retiro o que eu disse sobre esse recurso... continuo nao gostando... devido a legibilidade do codigo (coisa que java tem se esforcado em manter )

Desculpe a falha minha :P

Dyego Souza do Carmo disse...

"Sim preenche, mas ainda sim as queries são string-based."

Como voce pretente fazer isso sem alterar a linguagem como foi feito no C# ?

Vc acabaria tendo que usar algo parecido com a interface Criteria do hibernate... e isso iria complicar inves de ajudar , nao acha ?

Unknown disse...

"...Desculpe a falha minha :P ..."

Para né meu, estamos aqui pra isso, para ambos evoluirem.

Unknown disse...

"...Como voce pretente fazer isso sem alterar a linguagem como foi feito no C# ?

Vc acabaria tendo que usar algo parecido com a interface Criteria do hibernate... e isso iria complicar inves de ajudar , nao acha ?..."


Penso em algo parecido com aspectos. Não faz parte da linguagem Java, é um framework acima que vasculha o código Java antes do compilador Java entrar em ação.

Dyego Souza do Carmo disse...

"Penso em algo parecido com aspectos. Não faz parte da linguagem Java, é um framework acima que vasculha o código Java antes do compilador Java entrar em ação."

Como voce faria para o compilador nao acusar erro deste codigo ? eX:

List lst = from pessoa where pessoa.nome = 'jose';

Se fizer isso no seu IDE ele vai acusar erro... como vc faria para "pular" a checagem antes... ?

Unknown disse...

Pois é, quanta coisa a ser pensada ainda. hehehe

Talvez plugins, plugins e mais plugins. Afinal, para ter produtividade, teria que se mexer na IDE.

albrecht disse...

Olhe, nao li todos os comentários.
Mas, porque não fazer um pre processador para o Java?

Collection result = QUERY("select * from pessoa");

O pre processador le o conteudo de query e faz a validação sintática e semântica e gera o .java final.

Dai pode extender para o QUERY para os comandos que modificam dados e etc...

Unknown disse...

Felipe, a idéia é muito parecida com o que você está dizendo, pré-processador.

Mas não veja necessidade destes comandos QUERY, UPDATE, DELETE, ...
me lembram as queridas macros do C++ heheh

Anônimo disse...

O post é meio antigo, mas só pra complementar a idéia do Giovane sobre o comentário do Felipe: da forma como foi sugerida, com um pré-processamento, não seria possível utilizar o intellisense. :(

No meu mais que humilde ponto de vista, é trocar 6 por meia dúzia.

T+

Anônimo disse...

ler todo o blog, muito bom