Programadores Precisam Aprender SQL!

De uns tempos para cá, tenho vistos muitos códigos bizarros acontecendo no mundo dos ORMs, que eventualmente me deixaram pensando: será que ORMs estão fazendo-nos esquecer como se faz SQLs?

No mundo Ruby/Rails, virou quase uma regra não-escrita que escrever SQLs na mão é errado. Quanto mais pudermos aproveitar o ActiveRecord (e algumas mágicas que ele faz por nós), melhor. Isso acaba trazendo algumas coisas bem esquisitas, tal como achar que 90% dos códigos nunca vão precisar de “OR” (e maior, menor, diferente, etc), já que a API do ActiveRecord não suporta isso, ou algumas outras práticas meio estranhas. Do outro lado, temos por exemplo o framework “Play!”, de Scala, que faz o extremo oposto: não usa nenhum ORM, e todas as queries SQL passam a ser feitas na mão…

O ponto é que quando temos um ORM, parece que abusamos dele e esquecemos que nem tudo é um “SELECT * FROM <table> WHERE <attribute> = <value>”. Por exemplo, no código abaixo:

users = User.all
users.each do |user|
  puts &quot;User #{user.name} has #{user.addresses.count} addresses&quot;
end

Temos o famoso caso do “N+1”: 1 busca para achar N usuários, e a partir daí “N” buscas para achar a contagem de endereços. O problema é que muita gente acha que apenas um “User.include(:addresses)” resolve o problema, quando na verdade não resolve: o “include” vai trazer todos os endereços, mas a contagem (se o Rails optar por usar “count”) vai continuar sendo feita em banco, ou então (se o Rails optar por não usar “count”) será feita em Ruby, e teremos trazido registros a mais do banco de dados sem necessidade. A solução, nesse caso, é usar um comando SQL mesmo:

users = User.all
num_addresses = Address.join(:user).group('user.id').count
users.each do |user|
  puts &quot;User #{user.name} has #{num_addresses[user.id]} addresses&quot;
end

Ok, mas SQL é difícil, chato, e é mais fácil fazer as coisas em Ruby, certo? Bom, sim e não. É mais fácil fazer os comandos em Ruby (ou na linguagem que você escolher) puramente por “costume”. Estamos acostumados a fazer a sequencia: buscamos uma lista, tratamos a lista, exibimos a lista. SQL não trabalha com “listas”, mas com “conjuntos”. E é isso que vamos ver a seguir:
(more…)

ArelOperators e Buscas sem SQL

Continuando o trabalho em cima da biblioteca ArelOperators, há algumas novidades.

Para o pessoal que foi no encontro do Guru-SP, apresentei um pouco do trabalho. A idéia, conforme o post anterior sobre o assunto, é tornar o Arel mais transparente na hora de formar queries no ActiveRecord, aproveitando os recursos de Operator Overloading do Ruby.

A idéia é bem simples, na verdade, mas vem de uma dificuldade que eu acredito que muitos desenvolvedores têm: quando estamos escrevendo um código em qualquer linguagem, seria bom se pudéssemos apenas usar aquela linguagem para resolver nossos problemas. Não é conveniente usar duas, três linguagens no mesmo código-fonte (exceto, talvez, para o pessoal que usa Java, que tem que se entender com XML… ok, parei de zuar Java, juro!), e nem é recomendável de acordo com o fantástico livro “Clean Code”, do Robert Martin.

Então, por que SQL? Com uma linguagem expressiva como Ruby, e uma biblioteca fantástica como o Arel, não há mais motivos pra escrevermos “fragmentos de SQL” ou mesmo ficar fazendo “joins” e buscas estranhas manualmente. E isso trás algumas mudanças na cultura de buscas em banco de dados.
(more…)

Arel e Operator Overload

Finalmente, o Rails 3 foi lançado, e junto com ele vieram diversas funcionalidades legais: maior suporte para frameworks Javascript, mais rápido, mais agnóstico, etc etc… mas na minha opinião, a maior vantagem está no ActiveRecord 3.0

O ActiveRecord ganhou uma dependência chamada Arel, uma biblioteca de álgebra relacional. Muitos blogs já falaram sobre o assunto, então não vou me extender, vou direto ao ponto: Ruby é uma linguagem orientada a objeto, e ela é BOA no que faz. SQL é uma linguagem para fazer buscas, e devo dizer, ela também é BOA no que faz. Ruby entende objetos, SQL entende tabelas, e, bom, misturar os dois deveria ser muito mais transparente do que é. Por exemplo, o código a seguir:

maiores = Pessoa.maiores_de_idade
homens = Pessoa.homens
return maiores + homens

(more…)

A saga da busca em bancos de dados

Num mundo perfeito, todos os sistemas de armazenamento se conversariam, a nível do servidor e não do cliente, e jamais precisaríamos manualmente definir por “joins”, ou seja lá qual a forma que seu banco de dados faz.

Claro, o mundo não é perfeito.

Nesse caso, precisamos no mínimo padronizar uma forma de buscar dados. A maioria dos sistemas relacionais entende SQL, embora isso também não seja padronizado. Pior ainda, se for necessário buscar uma informação que está em uma tabela da base de dados X, e uní-la (join) com uma da base de dados Y, temos que fazer a busca manualmente.

Entra, aí, uma idéia.
(more…)