Fork me on GitHub

Keep Learning Conhecimento nunca é o bastante

Postado em
7 January 2010 @ 16:46

Tag(s)
Ruby

Sentinel: observers transparentes para seu código Ruby

Para uma determinada funcionalidade no Busk, precisava “trackear” todas as buscas feitas no site pelos usuários. Existem várias maneiras de conseguir esse resultado. Decidi por, de alguma forma, interceptar as chamadas ao método responsável pelas buscas (que faz o tratamento da query de busca enviada pelo usuário e chama o Sphinx). Uma das formas de se fazer isso é através do padrão conhecido como Observer.

Existem algumas bibliotecas open source que implementam Observers em Ruby e até mesmo uma na própria linguagem. Porém, queria que a implementação fosse transparente, sem alterar nada no método observado, nem mesmo adicionando uma chamada para notificar os observers, como é feito na implementação mais comum. Daí nasceu a ideia de criar uma pequena biblioteca provendo essa funcionalidade através do recurso de aliasing do Ruby e o resultado foi batizado de Sentinel, disponibilizado como uma gem.

Com essa gem, é possível interceptar chamadas a métodos de instância ou de classe através de um simples mixin (veja o Readme da gem para mais informações). De forma declarativa, definimos qual o método a ser observado e qual será o Observer notificado (qualquer objeto que responda ao método notify).

Sinta-se à vontade para sugerir modificações e notificar erros.


5 Comentários

Comentário por
Rodrigo Kochenburger
8 January 2010 @ 0:34

Cool. Ruby é muito flexivel e possibilita fazer muitas coisas que lembram um pouco AOP (Aspect Oriented Programming). Show de bola 😉


Comentário por
Rodrigo Kochenburger
8 January 2010 @ 0:37

Porém eu acho que as declarações deveriam ser feitas no observer pq se tu define o observer na declaração do objeto sendo observado, voce cria uma dependencia do objeto para o observer.

E o objeto observado, por definição, não deveria “saber” do observador 😉


Comentário por
Lucas Húngaro
8 January 2010 @ 1:02

Rodrigo, esse seria o máximo da “transparência” mesmo. Se você der uma olhada na implementação que linkei (dada pelo Russ Olsen em seu livro Design Patterns in Ruby), ela modifica não apenas a classe, mas também os métodos observados.

Eu queria algo um pouco menos intrusivo e cheguei a essa implementação. Gosto do estilo declarativo e, como minha necessidade é “observar” uma classe sobre a qual tenho pleno controle, o resultado foi satisfatório.

Obrigado pelos comentários! 🙂


Comentário por
Lucas Húngaro
8 January 2010 @ 12:29

De qualquer modo, se for necessário isolar o subject (classe com comportamento observado) e retirar as referências diretas ao Observer, é fácil tornar isso configurável através de uma constante.

Num arquivo de configuração (no Rails, um initializer, por exemplo):

module MyApp
  SEARCH_OBSERVER = MyObserver
end

E, na declaração no subject:

observe :metodo, :notify => SEARCH_OBSERVER

Também creio que é possível, com pouca alteração no código da gem, mover essa declaração para o Observer, deixando o subject totalmente livre de mudanças.


[…] Em Janeiro criei a gem Sentinel, que provê a funcionalidade do padrão Observer de forma transparente para código Ruby. Bom, olhando os exemplos de uso da primeira versão, é possível perceber que a biblioteca não é tão transparente assim: apesar de não alterar os métodos observados, a classe subject tem conhecimento do observer, o que não é bom (nos comentários do post linkado acima falo sobre um “hack” para contornar isso, mas não é uma solução elegante). […]


Deixe um comentário