Lei de Demeter e Ruby

December 8, 2009

Na semana passada tivemos uma discussão bem interessante na Globo.com sobre Lei de Demeter e ruby. Basicamente a questão era: faz sentido se aplicar a Lei de Demeter quando se está usando uma linguagem dinâmica como ruby?

(Para entender o que é a Lei de Demeter, vale a leitura do artigo na Wikipedia).

Ao seguir a lei de Demeter o código escrito tende a ter um acoplamento mais baixo e, portanto, é mais fácil de manter e evoluir. Por outro lado, quando a lei é violada, o acoplamento aumenta. Isso independe se a linguagem utilizada é dinâmica ou não. Ao enviar uma mensagem para um colaborador do colaborador você está aumentando o acomplamento.

Na minha opinião, a questão correta para se discutir é somente: faz sentido aplicar a Lei de Demeter? E, nesse caso, a resposta é a já manjada “depende”.

Assim, sem nenhum contexto, aplicar Demeter faz sentido. Acoplamento baixo é algo desejável. Mas, dependendo do caso, o custo de aplicar a lei pode não compensar. Por exemplo, se o modelo de domínio é muito simples, com pouquíssimas regras de negócio, podemos ser mais pragmáticos, não aplicando a lei, sem que isso tenha maiores consequências.

Como quase tudo que fazemos no nosso dia a dia, trata-se de uma questão de entender o conceito e pesar seus prós e contras dentro de um contexto para então decidir o que fazer.

Advertisements

Dev in Rio 2009: Eu Vou!

August 30, 2009

No dia 14/09 vai rolar um evento aqui no Rio de Janeiro que promete ser um sucesso: Dev in Rio 2009. E, claro, eu não poderia deixar de estar presente. Organizado pelo meu amigo Guilherme Chapiewski e pelo Henrique Bastos, contará com a presença de grandes nomes nacionais e internacionais falando sobre Open Source, Java, Ruby on Rails, Django e Desenvolvimento Ágil.

Nos vemos lá!

Dev in Rio 2009


will_paginate sem carregar ActiveRecord

April 21, 2009

Update: A solução abaixo não é mais necessária. Criei um fork do will_paginate no meu GitHub com um pequeno patch que habilita o will_paginate mesmo quando não temos o ActiveRecord carregado (obviamente, só habilita as partes que não precisam do ActiveRecord).

Para instalar:

sudo gem install gcirne-will_paginate --source http://gems.github.com

Além disso, fiz um pull request para o mislav aplicar meu patch no repositório dele. Se ele aceitar, teremos essa modificação na gem oficial do will_paginate.

Segue o post original.

O will_paginate é uma excelente gem para fazer paginação no Rails. Por default, ela pagina models do ActiveRecord. Mas também é possível paginar qualquer coleção. Basta usar o método create da classe WillPaginate::Collection.

Em aplicações Rails é possível não carregar determinados componentes do framework que não serão utilizados. Por exemplo, com a linha abaixo no arquivo config/environment.rb desabilitamos o ActiveRecord na nossa aplicação:

Rails::Initializer.run do |config|
  ...
  config.frameworks -= [ :active_record ]
  ...
end

Porém, com essa configuração o will_paginate não funciona, dando o seguinte erro:

undefined method `will_paginate'

Isso ocorre porque, ao carregar, o will_paginate insere alguns métodos em ActiveRecord::Base. Quando o ActiveRecord não está presente, o will_paginate simplesmente não carrega.  Isso é, no mínimo, estranho, já que o will_paginate funciona perfeitamente sem o ActiveRecord. Seria de se esperar que o will_paginate, nessa configuração sem ActiveRecord, carregasse normalmente, porém sem os métodos inseridos em ActiveRecord::Base (obviamente). Mas não é isso que ocorre, como podemos ver na linha abaixo no arquivo lib/will_paginate.rb da gem do will_paginate, responsável por habilitar o will_paginate:

...
if defined?(Rails) and defined?(ActiveRecord) and defined?(ActionController)
  WillPaginate.enable
end

De qualquer forma, a solução é bastante simples. Basta fazer a chamada a WillPaginate.enable_actionpack no arquivo config/environment.rb que tudo funcionará normalmente:

Rails::Initializer.run do |config|
  ...
  config.frameworks -= [ :active_record ]
  ...
  config.gem 'mislav-will_paginate',
    :lib => 'will_paginate', :source => 'http://gems.github.com', :version => '2.3.8'
end

WillPaginate.enable_actionpack

InfoFundos

March 23, 2009

Está no ar o InfoFundos, um site onde é possível acompanhar as rentabilidades de todos os fundos de investimento do mercado financeiro brasileiro. Mas este post não é sobre o site em si, e sim sobre o seu desenvolvimento.

O site é um projeto pessoal desenvolvido por mim com ruby e rails. O legal deste tipo de trabalho solo é a possibilidade de experimentar ideias, práticas, técnicas, etc.

Como não poderia deixar de ser, o desenvolvimento seguiu – e continua seguindo – os princípios e valores dos métodos ágeis. Ou seja, o site está sendo desenvolvido de forma incremental e evolutiva. A ideia é ir colhendo feedback para evoluir continuamente. Cada funcionalidade é desenvolvida da forma mais simples que poderia funcionar (simplest thing that could possibly work), com refactoring constante para deixar o código o mais limpo possível.

Uma técnica que pude usar desde o início e que ajuda a garantir a aplicação dos princípios e valores acima é o desenvolvimento outside-in sugerido pelo BDD. Cada funcionalidade é descrita por uma feature do cucumber guiada por selenium. Um passo dessa feature é escrito e, obviamente, ele falha. Então é preciso escrever apenas código suficiente para fazer este passo passar. Para isso, escrevo um spec com rspec e depois apenas o código necessário para este spec passar. Continuo assim sucessivamente, escrevendo specs e código, de fora para dentro, ou seja, das camadas mais externas até as mais internas, até que o passo esteja passando. Então, repito o ciclo continuando com o próximo passo até que toda a feature esteja passando. O ciclo completo seria algo mais ou menos assim:

feature > step > spec > implementação para spec passar > repete spec e implementação até step passar > repete step até feature passar

No final, tenho uma funcionalidade totalmente coberta por testes de aceitação com cucumber/selenium e com 100% de cobertura com rspec. Isso ajuda a garantir um código limpo, podendo ser refatorado e evoluído com bastante segurança.

Tenho diversas ideias de funcionalidades futuras para o InfoFundos e, certamente, qualquer assunto relacionado ao seu desenvolvimento será postado aqui.


Implementando uma fluent interface para um webservice REST com method_missing

July 13, 2008

Nesse post vou mostrar como usar o method_missing do ruby para implementar uma fluent interface em um cliente de um webservice REST. Vamos supor um webservice imaginário com recursos que podem ser acessados nas seguintes URLs:

/recurso/id

/recurso/doTipo/algumTipo

Queremos que um cliente ruby para esse webservice forneça a seguinte fluent interface para acesso às URLs acima:

WebService.new.recurso(1).get

WebService.new.recurso.do_tipo(algumTipo).get

Uma maneira mais tradicional de se implementar esse cliente seria algo como:

require 'net/http'
require 'uri'

class WebService

  def initialize
    @url = String.new
  end

  def recurso(id = nil)
    @url << '/recurso'
    @url << "/#{id}" unless id.nil?
    self
  end

  def do_tipo(tipo)
    @url << "/doTipo/#{tipo}"
    self
  end

  def get
    response = Net::HTTP.get_response(URI.parse("http://localhost:8080#{@url}"))
    response.value
    response.body
  end

end
&#91;/sourcecode&#93;

Repare que nos métodos <code>recurso</code> e <code>do_tipo</code> é retornado <code>self</code>, possibilitando o encadeamento dos métodos na fluent interface. No método <code>get</code>, <code>response.value</code> sobe uma exceção se o retorno do webservice for qualquer coisa diferente de 200 e <code>response.body</code> retorna o corpo do response.

Utilizando o method_missing a implementação fica bem mais simples e elegante:


require 'net/http'
require 'uri'

class WebService

  def initialize
    @url = String.new
  end

  def get
    response = Net::HTTP.get_response(URI.parse("http://localhost:8080#{@url}"))
    response.value
    response.body
  end

  def method_missing(metodo, *args)
    @url << "/#{camel_case(metodo)}"
    @url << "/#{args&#91;0&#93;}" if args.length > 0
    self
  end

  private

  def camel_case(metodo)
    primeira = true
    metodo.to_s.split('_').map {|palavra|
      if primeira
        primeira = false
        palavra
      else
        palavra.capitalize
      end
    }.join
  end

end

Uma característica interessante da implementação com method_missing é que ela serve para qualquer URL de qualquer recurso que já exista ou que venha a ser criada (obviamente isso só vale se houver a padronização entre a URL e a fluent interface).


RailsConf 2008

June 13, 2008

Finalmente, com muito atraso, vou falar um pouco do que vi na RailsConf 2008.

Eu perdi o primeiro dia da RailsConf pois estava no Google I/O. Então, para mim, o evento começou na sexta-feira com o keynote do Joel Spolsky da Fog Creek Software. Foi muito bom… o cara é muito carismático.

O keynote do David Heinemeier Hansson também foi um ponto alto do evento. Uma das coisas interessantes que ele falou foi sobre o fato de Rails ser opinionated. Ele mencionou que normalmente as pessoas consideram o fato de ter escolhas como sendo algo positivo. Mas na hora de efetivamente decidir por uma opção elas ficam perdidas e gostam da ajuda de alguém para decidir isso. O Rails adota essa filosofia: já vem com as escolhas feitas… mas sempre é possível mudar o default. O engraçado é que após esse keynote, nós passamos exatamente por essa situação no jantar. Fomos num lugar que oferecia mais de 150 rótulos de cerveja. Esse foi exatamente o chamariz para irmos lá. Mas na hora de escolher uma, eu e outros ficamos perdidos. Eu acabei pedindo ajuda da garçonete para escolher para mim!

Outro keynote que não posso deixar de mencionar foi o do Kent Beck. Ele é o criador do eXtreme Programming (XP). Foi com o livro dele, eXtreme Programing eXplained: Embrace Change, 1ª edição publicado em 1999, que eu comecei a me interessar e estudar métodos ágeis. Foi muito bom a oportunidade de assistí-lo ao vivo.

O foco (informal) da conferência foi escalabilidade. Praticamente todas as sessões que eu assisti (mesmo as que não tinham isso como tema) falavam sobre escalabilidade de alguma forma, nem que fosse uma piada ou um comentário. O consenso geral (e eu concordo) é que não é uma linguagem (Ruby) ou framework (Rails) que escala ou não. O que escala é a arquitetura da aplicação. O problema é que as pessoas muitas vezes não conhecem bem as ferramentas. Java EE pode não escalar se for mal utilizado. Diversas sessões falavam de sites com muitos acessos e como funcionava a arquitetura deles. Não há nenhum segredo ou truque. É pura aplicação de conhecimento técnico para identificar e resolver gargalos.

Um dos pontos altos foi a apresentação do MagLev. MagLev é uma máquina virtual para Ruby baseada na VM GemStone/S, que roda Smalltalk. Como eles disseram, Ruby e Smalltalk são muito parecidas. Assim, eles aproveitaram o know-how e tecnologia de décadas de desenvolvimento do GemStone/S para fazer uma VM Ruby. Com apenas alguns meses de desenvolvimento, o MagLev já apresenta desempenho fantástico. Alguns benchmarks são 100x mais rápidos do que MRI. A tecnologia toda envolve as VMs, caches em memória (um pra cada VM) e um repositório de objetos no backend. Assim, é possível fazer o que eles mostraram na apresentação: uma VM é iniciada em um terminal; nessa VM instancia-se um objeto; em outro terminal, inicia-se uma segunda VM; o objeto instanciado na primeira VM está disponível na segunda VM, de forma totalmente transparente. E isso tudo com completo controle transacional! O repositório comporta trilhões de objetos e até 17 petabytes de dados! O Akita fala sobre o MagLev em mais detalhes no seu blog.

Outra apresentação de impacto foi a do Phusion Passenger. O Passenger é um módulo do Apache para Ruby on Rails. Na apresentação eles explicaram que o objetivo era facilidade de uso. Ainda não tive oportunidade de testar, mas parece que eles conseguiram. O legal é que a performance não ficou comprometida. Está compatível com as alternativas existentes. Tá aí um importante passo para aumentar a adoção de Ruby on Rails.

A apresentação do Story Runner do RSpec do David Chelimsky também foi muito boa. Para mim, o melhor de Ruby/Rails é o RSpec! O Story Runner é a parte do RSpec para testes de aceitação. Com ele é possível literalmente criar histórias (user stories) executáveis. Dessa forma é simples assegurar quando determinada história está pronta (done) e atende ao que o usuário deseja.

Vin�cius Teles, Jim Weirich, Guilherme Cirne e Pedro TeixeiraDialogue Concerning the Two Chief Modeling Systems foi diferente do que se está acostumado em termos de apresentação e também foi muito boa. Utilizando o formato de uma peça de teatro, os três apresentadores (atores!) discutiam sobre qual a melhor forma de modelar sistemas: uma centrada em dados e o schema do banco e outra centrada em objetos e suas interações. No final, a conclusão é de que não se deve ser extremista em favor de uma ou outra forma; deve-se buscar encontrar o meio termo ideal. Essa conclusão é diferente do que está escrito no link anterior sobre a apresentação. Eles explicaram que inicialmente a idéia era mostrar que a forma OO é superior, mas ao preparar o material eles mudaram suas conclusões.

Galera do Brasil (incluindo o Carl!)Além das palestras, foi muito bom conhecer algumas pessoas que estavam presentes no evento. Eram muitos brasileiros. Tive a oportunidade de conhecer melhor e trocar várias idéias com o Vinícius Manhães Teles, o Fábio Akita e o Carl Youngblood, um americano que fala português melhor que muito brasileiro!!! Foi uma excelente experiência!


“Google I/O 2008” e “RailsConf 2008”

May 22, 2008

Na próxima semana estarei viajando novamente. Dessa vez vou para os EUA para dois eventos. O primeiro é o Google I/O que acontece nos dias 28 e 29/05 em São Francisco. O segundo é o RailsConf, que ocorre do dia 29/05 ao dia 01/06 em Portland, mas eu só estarei lá a partir do dia 30/05.

Como os dois eventos têm muitas sessões interessantes em paralelo, o difícil vai ser escolher o que assistir! Depois conto o que vi por lá!