Law of Demeter simples em Ruby com a gem demeter

Posted by Emerson Macedo on novembro 26th, 2009

Depois de programar algum tempo em Ruby, me senti muito incomodado em ter que repetir um determinado código para manter minha estrutura respeitando a Law of Demeter. Pra quem não está familiarizado, segue um simples exemplo em Rails:

#models
class Post < ActiveRecord::Base
  has_many :comments
end

class Comment < ActiveRecord::Base
  belongs_to :post
end

#view - erb|haml
@comment.post.title
@comment.post.name
@comment.post.something_else

O exemplo é um pouco forçado, mas o problema claro do exemplo é que estamos conhecendo demais sobre o objeto post dentro de comment. Se for necessário alguma alteração em algum dos atributos que estamos acessando diretamente, possivelmente isso resultará em modificações em cascata em todo código.

Depois dessa explicação básica para quem ainda não conhecia a Law of Demeter, vamos aplicar algumas soluções:

Segunda tentativa:

#models
class Post < ActiveRecord::Base
  has_many :comments
end

class Comment < ActiveRecord::Base
  belongs_to :post
  def post_title
    post ? post.title : nil #preciso verificar se é nulo, caso contrário terei problemas
  end
  def post_name
    post ? post.name : nil #preciso verificar se é nulo, caso contrário terei problemas
  end
  def post_something_else
    post ? post.something_else : nil #preciso verificar se é nulo, caso contrário terei problemas
  end
end

#view - erb|haml
@comment.post_title
@comment.post_name
@comment.post_something_else

Essa mudança resolve o problema. Acontece que isso acaba sendo um pattern para resolver o problema, portanto, precisamos encontrar uma forma de não ficar repetindo esse código.

Quem já leu o livro The Pragmatic Programmer, tem bem na memória o capítulo que apresenta o conceito DRY – D’ont Repeat Yourself. Quem programa em Ruby e principalmente já usou o framework Rails sabe bem que DRY é um dos chavões que estão imbutidos na propaganda. Vamos então tentar fazer mais algumas modificações pra tentar alcançar esse objetivo:

Terceira tentativa:

#models
class Post < ActiveRecord::Base
  has_many :comments
end

require 'forwardable'
class Comment < ActiveRecord::Base
  extend Forwardable
  belongs_to :post
  def_delegator :post, :name, :post_name
  def_delegator :post, :title, :post_title
  def_delegator :post, :something_else, :post_something_else
end

#view - erb|haml
@comment.post_title
@comment.post_name
@comment.post_something_else

O módulo Forwardable já vem com o Ruby. Portanto, a solução mais obvia foi usar esse módulo para melhorar o exemplo anterior. Apesar de escrever menos código, essa alternativa tem o inconveniente de não verificar se o objeto post é nil, causando assim NoMethodError em alguns casos. Sendo assim, a alternativa anterior ainda parece ser mais adequada. Porém, a duplicação de código ainda me incomodava bastante, portanto, resolvi montar uma solução única que deu origem a gem demeter.

A solução definitiva:

#no shell
> sudo gem update --system
> sudo gem sources -a http://gemcutter.org
> sudo gem install demeter

#models
class Post < ActiveRecord::Base
  has_many :comments
end

class Comment < ActiveRecord::Base
  extend Demeter     #extends demeter module
  demeter :post      #demeter post object
  belongs_to :post
end

#view
@comment.post_title
@comment.post_name
@comment.post_something_else

Basicamente o problema foi resolvido com 2 linhas de código:

  extend Demeter
  demeter :post

A vantagens são visíveis porque (1) você escreve bem menos, (2) já existe a verificação de objetos nulos e (3) caso você queira sobrescrever o comportamento padrão, basta criar um método que responda a mesma mensagem que a gem demeter responde. Dessa forma, o método criado pelo programador semrpe terá prioridade.

O código fonte do projeto está em http://github.com/emerleite/demeter com todas as instruções para utilização tanto em Ruby quanto em Ruby on Rails. O código fonte tem todos os testes automatizados que cobrem diversos cenários. O resultado desses testes podem ser vistos em http://runcoderun.com/emerleite/demeter. A página da gem fica em http://gemcutter.org/gems/demeter

Aguardo o feedback de vocês :)

JBehave Brasil – BDD em Java no nosso idioma

Posted by Emerson Macedo on abril 15th, 2009

No mês passado, resolvi aplicar BDD em um projeto Java que estava desenvolvendo. Atualmente, existem ferramentas em outras linguagens que podem ser usadas para esse fim. Por uma série de razões, resolvi usar o JBehave para resolver o meu problema nesse projeto em específico (lembre-se, não existe bala de prata). Acontece que o JBehave é todo em Inglês e não dá suporte a i18n.

Quando comecei a usa-lo no meu projeto, logo percebi que usar em inglês não seria legal, pois o projeto só fazia sentido no Brasil e portanto o interessante era escrever os cenários em português. A partir desse momento, comecei a escrever algumas classes pra fornecer esse suporte. Felizmente, as classes Scenario e Steps permitem fácil extensão para resolver esse problema. Após as modificações necessárias, o arquivo de cenário passou a se chamar nome.cenario e o texto no arquivo ficou da seguinte forma:


Cenário: Nome em português do Brasil

Dado que eu quero rodar o Jbehave em português do Brasil
Quando eu usar o meu idioma
Então tudo deve funcionar perfeitamente

Feito isso, achei legal disponibilizar uma biblioteca para que outros desenvolvedores que precisem usar o JBehave no nosso idioma possam faze-lo de forma trivial. Nesse momento nasceu o projeto jbehave-br, extraido desse projeto e disponibilizado no GitHub aqui. O projeto é muito simples e pequeno, com o objetivo de resolver especificamente esse problema e nada mais.

Depois de criar o projeto, pervebi que seria simples modifica-lo para posteriormente suportar qualquer idioma. Em breve estarei liberando essa nova versão. Por conta disso o projeto talvez mude de jbehave-br para outro nome.

RioJUG, REST e …. Mundo Java?

Posted by Emerson Macedo on maio 29th, 2008

Ontém tivemos a reunião mensal do RioJUG com a palestra de REST do Bruno Pereira. Mas pera lá, o que a Mundo Java tem a ver com a história? rs. Bem isso eu conto mais pra frente.

A palestra foi bem interessante e apesar de já conhecer REST, agente sempre aprende alguma coisa, sempre. Por isso que eu vou a diversos eventos, como por exemplo o Falando em Java 2008, que tinha algumas palestras que teoricamente não iriam acrescentar muito a mim, mas tem sempre alguma coisa que o palestrante fala que agrega, e as vezes muito.

A palestra do Bruno Pereira foi bem legal, explicando bem os conceitos do estilo arquitetural, falou um pouquinho do framework Jersey e deu bons exemplos de código. Quem não foi perdeu …

E a Mundo Java, heim? Bem vamos lá.

Quando saia da empresa para ir ao evento, comentei com um amigo o fato de eu nunca ganhar nada nesses sorteios de brindes que tem nos eventos (pronto, acabou o suspense :) ). No Falando em Java 2008 eu queria ter ganho o Nintendo WII, mas infelizmente não deu :( ). Então, voltando ao papo que eu estava tendo com meu amigo do trabalho, comentei que eu queria ganhar a assinatura da Mundo Java, pois é a publicação de Java que eu gosto mais aqui do Brasil.

O engraçado do sorteio é que o deixou a assinatura Mundo Java por útimo e eu fiquei naquela espectativa por nunca ganhar nada nesses sorteios.

E o resultado foi …

QUE EU GANHEIIIIIIIIIIIII :)

Espero que agora que eu ganhei alguma coisa pela primeira vez eu consiga ganhar novamente em outras oportunidades.

Substituição: sai Bloglines, entra Google Reader

Posted by Emerson Macedo on maio 16th, 2008

Sempre usei o Bloglines como meu leitor de feeds e quando usei o Google Reader não gostei muito. Acontece que resolvi testar novamente pra ver se algo tinha melhorado. Eis que tive uma bela surpresa …

Não sei se alguns dos recursos já estavam lá e não dei a atenção desejada. Não sei mesmo. O fato é que algumas coisas simples que o Google Reader me proporcionaram me fizeram migrar instantaneamente. Seguem algumas delas:

  1. As mensagens são marcadas como lidas apenas quando clico nelas, ao contrário do Bloglines, onde assim que seleciono a pasta, o mesmo marca tudo como lido e eu preciso manualmente informar o que eu quero marcar como não lido.
  2. No Google Reader eu tenho como alternar entre visualização das mensagens em forma de listagem e a visualização expandida (i.e. conteúdo completo). Isso é ótimo, uma vez que alguns feeds eu apenas leio o título da matéria e já descarto e quando é algum feed que eu já sei que quero ver tudo, como o caso de alguns blogs, eu passo para a visualização extendida e tudo beleza.
  3. O Google Reader tem um recurso de recomendações muito interessante, que me recomenda feeds de acordo com feeds que já assino. Logo de cara eu encontrei um blog legal sobre Rails que eu não conhecia e isso foi ótimo.
  4. A parte de tendências também é muito importante. Essa feature me ajuda a ver feeds que tem muitas mensagens e que na verdade eu leio pouca coisa, de forma que eu possa perceber se aquela inscrição não está valendo a pena e dar um unsubscribe nela.

No fim das contas eu estou gostando muito de usar o Google Reader. Se alguém tiver algum contra-argumento é muito bem vindo.


Copyright © 2007 codificando.com. All rights reserved.