Problema com múltiplos joins em Criteria

O Criteria é uma API do Hibernate que facilita muito quando precisamos montar uma query complexa com filtros opcionais. Adicionar restrições ou criar joins com esta API é muito mais simples de gerenciar do que concatenando Strings, como faríamos ao trabalhar com SQL puro.

Apesar das vantagens, o Criteria também tem alguns problemas. O último que encontrei foi ao tentar fazer 2 joins entre as mesmas 2 tabelas. No meu caso, eu tinha no banco as tabelas projeto e historico. A segunda tabela é populada através de uma trigger no banco: sempre que o status do projeto muda, a tabela historico registra o status anterior do projeto com data/hora da mudança. Eu precisava fazer uma query que buscasse um projeto com status “iniciado” num determinado período de datas e com status “finalizado” em outro período. Inicialmente, pensei simplesmente em criar 2 joins entre as tabelas, cada um com um alias diferente e filtrando pelas datas específicas:

Criteria criteria = getSession().createCriteria(Projeto.class);

// Primeiro join
criteria.createCriteria("historicoList", "historicoIniciado", Criteria.LEFT_JOIN)
        .add(Restrictions.eq("historicoIniciado.status", Status.INICIADO.value()))
        .add(Restrictions.ge("historicoIniciado.data", dataIniciadoDe))
        .add(Restrictions.le("historicoIniciado.data", dataIniciadoAte));

// Segundo join
criteria.createCriteria("historicoList", "historicoFinalizado", Criteria.LEFT_JOIN)
        .add(Restrictions.eq("historicoFinalizado.status", Status.FINALIZADO.value()))
        .add(Restrictions.ge("historicoFinalizado.data", dataFinalizadoDe))
        .add(Restrictions.le("historicoFinalizado.data", dataFinalizadoAte));

O código acima, apesar de semelhante ao que eu já havia criado para adicionar outros filtros à query de projetos, fazendo joins com outras tabelas, não funcionava. Tentei retirar um dos joins com a tabela historico e funcionou. Ou seja, o problema estava na criação do segundo join com as mesmas tabelas, mesmo utilizando aliases diferentes. Ao pesquisar este problema, descobri que não é um bug. Na verdade, o Criteria não suporta múltiplos joins para a mesma associação.

Sendo assim, a solução que encontrei para este problema foi criar uma subquery para a tabela historico, utilizando um DetachedCriteria:

DetachedCriteria historicoCriteria = DetachedCriteria.forClass(Historico.class, "historicoIniciado")
        .setProjection(Projections.distinct(Projections.property("projeto")))
        .add(Restrictions.eq("historicoIniciado.status", Status.INICIADO.value()));
        .add(Restrictions.ge("historicoIniciado.data", dataIniciadoDe));
        .add(Restrictions.le("historicoIniciado.data", dataIniciadoAte));
criteria.add(Subqueries.propertyIn("id", historicoCriteria));

Desta forma, apenas um dos joins precisa ser substituído por uma subquery. O outro join pode ser mantido sem problemas.

Resumo do Dev in Rio

No último dia 14 aconteceu o Dev in Rio (veja vídeos e fotos do evento). Organizado pelo Guilherme Chapiewski e pelo Henrique Bastos, o evento foi um grande sucesso.

Na abertura do evento, Guilherme e Henrique informaram que o evento seria totalmente voltado para os desenvolvedores, destacando a importância de se integrar e reunir as pessoas para troca de experiências. Eles também ressaltaram a importância de se integrar comunidades de diferentes tecnologias, reforçando também a tendência dos desenvolvedores poliglotas.

A primeira palestra foi de Ryan Ozimek, sobre o CMS Joomla. Ryan, que não é desenvolvedor, falou sobre a história deste projeto, destacando a importância da participação da comunidade para o crescimento do Joomla.

Na palestra seguinte, Nico Steppat e Guilherme Silveira, da Caelum, falaram sobre Java como plataforma, e não como linguagem, destacando o suporte a várias linguagens, permitindo que possamos escolher a linguagem mais adequada a cada situação sem perder as vantagens oferecidas pela plataforma.

Após o almoço, Fábio Akita trouxe uma geral sobre o ecossistema Ruby on Rails. Na minha opinião, esta foi a melhor palestra do evento, pois ele soube resumir em pouco tempo uma quantidade enorme de conteúdo. Primeiramente, ele trouxe um histórico da linguagem Ruby, e, através de uma “meta-apresentação”, mostrou um pouco da linguagem e suas principais características, como meta-programação, por exemplo. Depois, falou sobre Rails, destacando algumas de suas principais características e os mais famosos mitos, como “Rails não escala” (link para a apresentação).

Em seguida, Jacob Kaplan-Moss, um dos criadores do Django, falou sobre este framework Python, sua história, evolução e principais características (link para a apresentação).

Na última palestra, Jeff Patton falou sobre metodologias ágeis, mas focando na criação de produtos e interação com o cliente, e não no desenvolvimento em si. Ele trouxe como exemplo o desenvolvimento de um produto real, as dificuldades encontradas e as soluções utilizadas.

Finalmente, foi feita uma espécie de mesa redonda com a maioria dos palestrantes e alguns convidados, como Marcos Tapajós, Sylvestre Mergulhão e Daniel Cukier, entre outros. Vinicius Teles fez o papel de mediador entre os participantes e o público.

Em paralelo às palestras, ocorreram coding dojos de Ruby, Python e Java. Destaque também para a tradução simultânea das palestras (tanto inglês-português quanto português-inglês), serviço que foi bastante elogiado por aqueles que o utilizaram. Também foram sorteados vários brindes no final, como ingressos para o Rails Summit.

No final, o balanço do evento foi extremamente positivo, pois conseguiu reunir muita gente, incluindo figuras bastante importantes e conhecidas no desenvolvimento de software. Os organizadores estão de parabéns, pois tudo correu sem qualquer problema aparente, todas as palestras foram muito pontuais e de excelente qualidade. Agora, só resta esperar pelo Dev in Rio 2010! Vale a pena conferir também os posts do Guilherme e do Henrique sobre o evento.

Desenvolvedores e plataformas poliglotas

Há alguns anos atrás, era muito comum encontrarmos desenvolvedores que conheciam somente uma linguagem, e por isso intitulavam-se “desenvolvedor Java”, “desenvolvedor Delphi”, “desenvolvedor ASP”, ou qualquer outra linguagem. Eram pessoas que conheciam uma, e somente uma, linguagem de programação, e a defendiam com unhas e dentes em qualquer discussão nos fóruns, frequentemente gerando flame wars.

Esse tipo de desenvolvedor ainda existe, mas é cada vez menos comum, e isto é muito positivo. O livro The Pragmatic Programmer recomenda que aprendamos uma linguagem nova por ano, e, com isso, muitos daqueles desenvolvedores Java ou C# estão aprendendo Ruby, Python ou Erlang. Mesmo que não tenhamos pretensão de trabalhar com estas linguagens, pelo menos a curto ou médio prazo, cada linguagem tem suas particularidades, ajudando a quebrar paradigmas. Quando conhecemos somente uma linguagem, temos uma grande tendência a resolver os problemas sempre da mesma forma, conforme aprendemos e como é feito tradicionalmente com aquela linguagem. Desta forma, a tendência é a estagnação, pois não procuramos outras maneiras de resolver os problemas. A partir do momento em que começamos a estudar outras linguagens, abrimos nossa cabeça e começamos a “pensar fora da caixa”, e percebemos que existem muitas outras maneiras de resolver aquele mesmo problema, muitas delas mais simples e adequadas à situação. Surgem os desenvolvedores poliglotas.

Na época dos desenvolvedores monoglotas (sim, essa palavra existe!) era muito comum vermos discussões do tipo: “que linguagem é melhor, X ou Y?”. A melhor resposta é: depende! Depende da situação, do projeto, da experiência da equipe… Para cada situação, uma linguagem pode ser mais adequada que outra, o que traz uma grande vantagem para os poliglotas, pois, para se tomar esta decisão, é necessário conhecer as linguagens disponíveis. Ao mesmo tempo, se ninguém na equipe tiver experiência com determinada linguagem, seria um grande risco utilizá-la no projeto. É como uma caixa de ferramentas: se eu tiver somente um martelo na minha caixa, como farei para apertar um parafuso? É importante termos o maior número possível de ferramentas disponíveis, e conhecimento sobre cada uma delas, para que possamos escolher a mais adequada em cada situação.

Acompanhando esse comportamento, há atualmente uma forte tendência a plataformas poliglotas, o que também é muito positivo. As plataformas existentes já estão bastante maduras, têm algoritmos eficientes para gerenciamento de memória e Garbage Collection, por exemplo, e são bem conhecidas. Encontram-se nesta categoria as plataformas Java e .NET, que estão continuamente aumentando o número de linguagens suportadas – veja a lista de linguagens suportadas pela JVM e pelo .NET. Com isso, a escolha da linguagem para cada projeto fica muito mais fácil, permitindo, inclusive, projetos poliglotas. Se você trabalha com Java e decide utilizar Ruby no seu projeto, por exemplo, basta adicionar o jar do JRuby.

A conclusão que podemos tirar disso é que um desenvolvedor nunca deve estagnar. Procure sempre estudar e aprender novas coisas, mesmo que não seja nada relacionado com o que você está trabalhando atualmente, pois, mesmo que não venha a trabalhar, isso ajuda a quebrar paradigmas e permite que você se torne um melhor desenvolvedor.

Dev in Rio – eu vou!

Muitos já devem estar sabendo, mas acho que não custa nada ajudar a divulgar: no dia 14 de setembro ocorrerá aqui no Rio de Janeiro um evento imperdível: o Dev in Rio. Organizado pelo Guilherme Chapiewski e pelo Henrique Bastos, o evento terá palestras sobre Rails, Django, Java, Open Source e metodologias ágeis, contando, inclusive, com palestrantes internacionais. A inscrição custa apenas R$ 65,00, e, pelo sucesso que está fazendo, acho que as vagas vão acabar logo!

Para quem estiver sem grana, vale a pena tentar ganhar ingressos pelo RubyInside ou pela revista TI digital.

Mais informações sobre o Dev in Rio no site e no twitter. Parabéns aos organizadores pela iniciativa!

Feeds autenticados no Google Reader

Há muito tempo eu uso o Google Reader como leitor de feeds. A principal vantagem sobre as demais alternativas para desktop é o fato de não necessitar de instalação, podendo ser acessado diretamente pelo browser.

Outro dia, tentei cadastrar o feed do Twitter no Google Reader, e recebi a seguinte mensagem: “Sorry, an unexpected condition has occurred which is preventing Google Reader from fulfilling the request”. Tentei acessar o feed diretamente no Firefox, e, após solicitação de login e senha, os feeds apareceram normalmente. Após uma rápida pesquisa, descobri que o Google Reader não suporta feeds autenticados, o que é o caso do Twitter.

Uma das alternativas a este problema seria utilizar um leitor de feeds que suporta autenticação, como a extensão NewsFox para Firefox ou algum outro. Porém, para poder continuar utilizando o Google Reader, uma solução é o FreeMyFeed, um serviço que funciona como uma espécie de proxy para feeds autenticados: você informa a URL, o login e a senha do feed que exige autenticação, e ele gera um novo endereço de feed que permite acesso direto, inclusive pelo Google Reader.

Livros técnicos traduzidos nunca mais

Há alguns meses atrás, eu estava interessado no livro Effective Java, segunda edição. A princípio, eu pretendia comprar na Amazon, mas decidi pesquisar antes. Pela internet, não achei o livro mais barato em nenhum lugar, mas acabei encontrando em uma livraria perto do trabalho por um precinho camarada. Só tinha um problema: era a edição traduzida em português.

Inicialmente nem pensei em comprar a edição traduzida, pois acho que livros técnicos devem ser mantidos na língua original. Algumas pessoas que discordam disto argumentam que nem todos dominam o inglês, mas, sinceramente, se você tem dificuldades com inglês e quer estudar informática, procure um curso de inglês urgente! Por mais que você procure ler somente livros em português, em algum momento vai precisar consultar alguma documentação, referência ou fórum de discussão em inglês. Além disso, acho que nas traduções, por melhores que sejam, acaba-se perdendo um pouco do original (como num filme dublado, em que algumas piadas em inglês perdem completamente o sentido quando traduzidas), aumentando a possibilidade de erros e a dificuldade de compreensão do assunto. Num livro de programação então nem se fala, pois é muito comum utilizarmos muitos termos em inglês que não têm tradução para português – ou até tem, mas o original se popularizou tanto que é usado como se fosse uma palavra do nosso vocabulário.

Na época em que fiz essa pesquisa, o livro estava mais caro na Amazon do que hoje, e ainda tinha que incluir o frete. Aquela edição traduzida sairia por menos da metade. Além disso, eu não teria que esperar a entrega, era só dar um pulo na livraria e comprar. Decidi dar uma folheada no livro, só pra ver se tinha algum erro gritante de tradução, como trechos de código traduzidos – sim, eu já vi livros com aberrações como “calculaMédia”, com acento mesmo. Como não encontrei nada de mais, acabei me deixando levar pela tentação de economizar uns trocados e comprando o livro traduzido.

Quando comecei a ler, achei a tradução muito boa. Nos primeiros capítulos, o único termo que machucou os ouvidos foi “encaixotamento automático” em vez de autoboxing – por mais que esteja correto, esse é um daqueles termos que não se costuma traduzir. Além disso, os trechos de código foram mantidos originais, e abaixo de cada um há a tradução de cada linha de comentário. Achei um pouco desnecessário, porém interessante.

Ao chegar no capítulo 4, estranhamente os comentários nos códigos passaram a ser substituídos pelos traduzidos. Isso continua até o final do livro. Aparentemente a tradução foi feita por pessoas diferentes, e faltou uma revisão mais rigorosa no final. Porém, não é nada que atrapalhe. Mais adiante, vi uma citação a uma referência bibliográfica e resolvi verificar qual era o nome do livro referenciado. Descobri que o livro não tinha bibliografia! Obviamente isso é uma exclusividade da edição em português. Mais uma falha de revisão, e esta é mais grave.

Quando comecei a ler o capítulo 5, que fala sobre generics, achei o trecho abaixo bem estranho:

Antes da versão 1.5, essa teria sido uma declaração de coleção exemplar:

/**
* Minha coleção de selos. Contém apenas instâncias de Stamp.
*/
private final stamps = …;

Não está faltando definir o tipo de stamps? Tudo bem, eu não devo ter entendido direito. Sigo a leitura e, um pouco mais à frente aparece o seguinte:

Com os genéricos, você substituiria o comentário por uma declaração de tipo aperfeiçoada para a coleção que passaria ao compilador as informações que anteriormente ficariam ocultas no comentário:

private final stamps = …;

Ué, mudou alguma coisa? Não é exatamente igual ao código anterior? Resolvi pegar o livro original em inglês emprestado com um amigo, e vejo que nele aparecem os seguintes trechos:

Before release 1.5, this would have been an exemplary collection declaration:

// Now a raw collection type – don´t do this!

/**
* My stamp collection. Contains only Stamp instances.
*/
private final Collection stamps = … ;

e

With generics, you replace the comment with an improved type declaration for the collection that tells the compiler the information that was previously hidden in the comment:

// Parameterized collection type – typesafe
private final Collection <Stamp> stamps = … ;

Os destaques em negrito são do livro original. Aparentemente, tudo o que estava em negrito foi omitido na tradução! E, se estava em negrito, é porque é exatamente o trecho mais importante do código! Posteriormente, descobri que isso acontece em todo o capítulo 5. Do 6 em diante os códigos voltam ao normal e não encontrei mais nenhuma bizarrice, exceto a tradução de “thread” para “segmento”.

Outro erro que se repetiu bastante no livro são as referências a números de páginas (ex: “veja a página 147″). Em todas as situações em que isso ocorre, o número da página que é referenciado é o do livro original, tornando a referência inútil na edição traduzida.

A conclusão que tirei dessa situação: livro técnico traduzido nunca mais! Os trocados que resolvi economizar com o livro acabaram saindo muito caros. Vale muito mais a pena investir um pouco mais no livro original – e num curso de inglês, caso você precise – para não ter dor de cabeça com livros mal traduzidos.

Suporte a HTML 5 no Firefox 3.5

Esta semana saiu o Firefox 3.5, com uma série de melhorias, como o recurso de geolocalização e o modo Private Browsing. Além disso, o browser está muito mais rápido que na versão anterior, devido principalmente ao novo engine de Javascript e ao suporte nativo a JSON.

Além disso, outra novidade importante é a adição de suporte ao HTML 5. Esta versão ainda é um working draft, que traz como principais novidades as tags <video> e <audio>, para suporte nativo a mídias. Assim, não é mais necessário usar tags <embed> e um player externo para a exibição dos já onipresentes vídeos online. Existem vários sites que já utilizam HTML 5 para demonstrar os novos recursos, como mostra este post do Zumo e o Video Bay.

Instant Rails, o ambiente Rails de bolso

Com a proliferação dos pen drives com alguns GB de capacidade e a preços acessíveis, aplicativos que rodam sem necessitar de instalação tornaram-se igualmente populares. Estes aplicativos “portáteis”, mais conhecidos como Portable Apps, podem ser executados diretamente do pen drive, geralmente com todas as funções dos equivalentes instaláveis. Eles são mais comuns em ambiente Windows (o site mais conhecido é o PortableApps, mas existem outros, como o The Portable Freeware Collection), porém também existem Portable Apps para Mac OS X. Até onde eu sei, não existem Portable Apps para Linux, porém, é possível executar os Portable Apps de Windows via Wine.

Como não poderia deixar de ser, existem também muitos ambientes de desenvolvimento portáteis. Talvez o mais conhecido seja o XAMPP, que inclui um servidor Apache com MySQL, PHP e Perl, entre outras ferramentas. Basta descompactar e executar.

Para Ruby on Rails, também existe um ambiente portátil. É o Instant Rails, infelizmente disponível somente para Windows. A exemplo do XAMPP, basta descompactar um arquivo zip para se ter um ambiente Rails totalmente funcional, com Mongrel, Apache e MySQL. É possível, inclusive, instalar RubyGems e plugins Rails normalmente, como num ambiente Rails comum. O pacote inclui ainda o SQLite, PHP, phpMyAdmin, o editor SciTE e o typo, sobre o qual já escrevi aqui no blog.

A principal desvantagem do Instant Rails é que ele está bastante desatualizado – a versão atual, 2.0, é de dezembro de 2007, e inclui as seguintes versões:

  • Ruby 1.8.6
  • Rails 2.0.2
  • Mongrel 1.1.2
  • RubyGems 1.0.1
  • Rake 0.8.1
  • Apache 1.3.33
  • MySQL 5.0.27
  • SQLite 3.5.4
  • PHP 4.3.10
  • SciTE 1.72
  • phpMyAdmin 2.10.0.2

Segundo o wiki do projeto, há uma petição solicitando o upgrade para a versão 1.9.1 do Ruby.

UPDATE: Só agora vi que o Urubatan escreveu sobre o mesmo assunto no blog dele. Só que ele citou o Ruby on Rails Portable, um projeto muito semelhante ao InstantRails, porém um pouco mais atualizado: a versão do Rails atualmente é 2.1.0 (a do Ruby é 1.8.6).

Outro projeto semelhante que encontrei, mas ainda não testei, é o Flash Rails.

Tutoriais de JSF

Uma das maiores dificuldades para se aprender JSF é seu aparentemente complexo ciclo de vida, composto por 6 fases. Ao debugar uma aplicação JSF, percebe-se que alguns métodos dos Managed Beans são executados várias vezes, uma em cada fase, o que não é muito intuitivo, principalmente quando se está acostumado com outros frameworks web que utilizam abordagens bem diferentes.

Para facilitar a compreensão do ciclo de vida do JSF, recomendo o tutorial The JSF application lifecycle, da IBM. Ele explica cada fase, e apresenta um exemplo bem simples de uma aplicação usando JSF. Este tutorial é a segunda parte da série “JSF for nonbelievers”. As demais partes também são bem interessantes:

Scrum e comprometimento

No ano passado trabalhei na Globo.com, e lá tive algumas oportunidades de trabalhar com Scrum (aliás, para quem ainda não leu, recomendo o post do Guilherme Chapiewski sobre a adoção de Scrum na Globo.com). Eu pretendia escrever sobre isso há algum tempo, mas a procrastinação me impedia de transformar um rascunho antigo neste post.

Quando cheguei na empresa, eu não sabia nada sobre Scrum, e fiquei muito curioso ao ver que, em determinado horário, todos os dias, todos os membros de algumas equipes levantavam-se, reuniam-se (em pé!) em torno de um cartaz na parede com vários post-its, e, após 15 minutos, todos retornavam às suas atividades normais. Comecei a observar e estudar o assunto, e aos poucos fui percebendo a simplicidade desta metodologia: tudo o que não for realmente necessário não deve ser feito. Acredito que isto seja um dos principais elementos do Scrum, pois ajuda a manter o foco naquilo que é realmente importante.

Outro ponto importantíssimo, e que é o assunto principal deste post, é o comprometimento. Para que o Scrum realmente funcione, é necessário que o time esteja comprometido com o projeto.

Num dos projetos em que trabalhei com Scrum, o Scrum Master era o Guilherme Chapiewski e o Product Owner, inicialmente, era o Antônio Carlos Silveira. Porém, por falta de tempo disponível para dedicar-se ao projeto, o Antônio saiu do time, repassando o papel de PO para outra pessoa. De todo o time, incluindo o SM e o PO, eu era o único que não estava envolvido em outro projeto. O GC, por exemplo, trabalhava em um outro projeto que era muito maior e mais importante que este, que, consequentemente, tinha baixa prioridade. Desta forma, começamos a passar pelos seguintes problemas:

  • nos Daily Meetings geralmente eu tinha concluído a minha tarefa, e muitas vezes até adiantado alguma outra, enquanto os demais membros do time não tinham nem iniciado as suas, pois estavam muito ocupados com seus outros projetos, e já sabiam que não poderiam iniciá-las nos próximos 2 ou 3 dias;
  • após algumas semanas, começamos a não conseguir mais realizar o Daily Meeting todos os dias, pois não conseguíamos 15 minutos livres de todos os membros do time simultaneamente.

Quando isso começou a acontecer com mais frequencia, começamos, na prática, a parar de usar Scrum, pois já não havia mais comprometimento. Como o Bruno Carvalho já escreveu, Daily Meeting é comprometimento. Não estou dizendo que o time estava desestimulado ou não queria se dedicar ao projeto. Pelo contrário, todos achavam o projeto bem interessante, porém não conseguiam se comprometer a ele, exatamente por estarem comprometidos com outro.

A solução encontrada pelo GC foi pararmos de usar Scrum neste projeto, pois tornou-se impossível praticar Scrum sem que todos os membros estivessem comprometidos. Continuamos a utilizar algumas das práticas do Scrum, como o Planning e o Review, mas na verdade não era Scrum.

A lição que tirei daí foi que é importantíssimo ter um time comprometido com um projeto para que o Scrum realmente aconteça, e que, sem isso, fica muito difícil utilizá-lo na prática. Até acredito que seja possível trabalhar em dois projetos simultâneos com Scrum, mas com certeza exigiria uma grande disciplina para conseguir dividir igualmente o tempo entre os dois, sem deixar de comprometer-se com um ou outro.

Próxima Página »


@guilhermgarnier

Estatísticas

  • 26,195 hits