Pular navegação

Prólogo

Se você, como eu, conheceu Ruby através do rails, certamente iniciou seu aprendizado com o livro agile web development with rails. Depois de brincar um pouco com Rails, você por ora começou a ficar mais interessado em Ruby. Ruby com certeza é uma ótima linguagem, mas leva um tempo relativamente maior que o usual para programar efetivamente.

 

Programar efetivamente em Ruby significa conhecer muito bem a programação de objetos e meta-objetos, ou melhor, meta-programação. Esse novo tipo de programação tem seus pontos fortes e pontos fracos, assim como qualquer outra coisa em software.

 

Tenha em mente que meta-objetos é um tipo de meta-programação. No entanto, meta-programação não é somente meta-objetos. Para deixar este texto mais limpo, vou explicar detalhadamente ao decorrer do artigo.

 

Enfim, muitos dizem que a meta-programação é a mágica do Ruby, eu até concordo, bem… parcialmente…

 

Receitas de um desastre

Indubitavelmente, um projeto com excessiva meta-programação é um projeto confuso, complexo e irritante. Aquelas mensagens de ArgumentError, NameError, que uma vez foram tão claras, já não começam a ser mais explicativas. A razão disso? é simples, estas mensagens são geradas em pontos muito profundos do código.

 

Meta-programação envolve uma série de chamadas em tempo de execução/avaliação, geralmente envolvendo uma ou diversas, tendo como inputs, o resultado de outras chamadas, avaliações de sub-códigos, classes programáveis e claro, inputs dos próprios desenvolvedores. Muitas vezes, esses inputs somados a natureza imprevisível de um código em tempo de execução, e certos comportamentos, resultam numa perfeita receita para o desastre.

 

Quando a meta-programação começa a ter uma extensão mais profunda, o pessoal logo nome-a como DSLs (Domain Specific Language(s)). Neste caso, algo mais interessante acontece comparado a programação usual. Neste momento, a meta-programação passa a ter conhecimento e controle sobre a linguagem e o domínio ao qual está sendo aplicado.

 

Se sua linguagem de programação suporta mecanismos de circularidade, isto é, reflexão, macros, templates, meta-objetos ou qualquer outro tipo de coisa que possa ser avaliável ou gere funcionalidade que a linguagem compreenda, então, muito provavelmente você poderá criar DSLs. Repare que a meta-programação envolve o uso de um ou vários desses recursos citados acima.

 

Em teoria isso é perfeito, no entanto, o mundo em prática nos reserva grandes surpresas. Como descrito anteriormente, erros gerados em meta-programação são erros gerados nas profundezas dos códigos. São erros que não fazem sentido, são erros complicados de debugar e navegar.

 

Não apenas isso, a medida em que se usa descontroladamente recursos de meta-objetos, reflexão, macros, o desenvolvedor passa a perder interatividade com a linguagem. A linguagem passa a perder interatividade consigo mesma. Como resultado, a meta-programação começa a inferir novos desafios ao desenvolvedor.

 

Acredite se quiser, a coisa mais desafiante quando meta-programando é lidar com um sistema razoável de avaliação. Isso sempre faz-me pensar cinco vezes antes de usar qualquer recurso de meta-programação.

 

 

Lado negro da feitiçaria

Embora argumentáveis, gostaria que o leitor assumisse essas duas afirmações como verdades:

 

  1. DSL é uma nova linguagem construida no topo de uma outra linguagem;
  2. DSL toma o mecanismo de avaliação da linguagem base como seu;

 

Desenvolvedores, em sua maioria, não dão muita importância a essas coisas. Eles colocam confiança demais na linguagem de base e esquecem o domínio. Lembrem-se, DSLs são tudo sobre domínio, por sua vez, domínio não é quase nada sobre linguagem.

 

Embora não seja elegante ou ético apontar projetos de companheiros Rubystas como casos malsucedidos, as vezes se faz necessário. É como dizem por aí, “entrou na água, é para se molhar”.

 

O projeto que eu ponho em discussão é rSpec. Para quem não conhece, rSpec, é uma biblioteca de testes, assim como o tão popular test/unit do ruby.

 

Minha recomendação, como desenvolvedor, que já usou e usa meta-programação em diversos projetos. Projetos criados por mim e por outras pessoas, é fazer uso desses recursos somente quando realmente necessário.

 

Desde que comecei a mexer com software, tenho um amigo que sempre martelava em minha cabeça sobre manter as coisas simples. Diga-se de passagem, demorei muito para aprender isso.

 

Desde então, sigo uma linha muito direta e extremista de raciocínio. Se as coisas podem ser feitas simplesmente, não vale o esforço tentar sofistica-las. Simples assim.

 

Tenha em mente esse pedaço de código em rSpec:

 

describe Bowling do

  before(:each) do

    @bowling = Bowling.new

  end

  it 'should score 0 for gutter game' do

    20.times { @bowling.hit(0) }

    @bowling.score.should == 0

  end

end

Agora com a biblioteca padrão de testes:

class BowlingTestCase < Test::Unit::TestCase

  def setup

    @bowling = Bowling.new

  end

  def test_score_0_for_gutter_game

    20.times { @bowling.hit(0) }

    assert_equal @bowling.score, 0

  end

end

 

 

Será que justifica codificar 10.000 linhas de meta-programa para cumprir apenas uma função estética? Isto é, trocar class BowlingTestCase por describe Bowling? Será que DSLs valem mais de 3.000 commits num repositório? será?

 

É claro que rSpec não compreende apenas isso. É possível usar um monte de outras funcionalidades. De qualquer forma, rSpec tornou testes, uma tarefa trivial, que é realizado simplesmente, em algo muito sofisticado.

 

Conclusão

Se a meta-programação não for muito bem planejada e desenvolvida, problemas com avaliações, erros, comportamentos inesperados, tolenadas de código mágicos serão alguns dos desafios. Para contornar esses desafios, o desenvolvedor tem de programar sistematicamente e acima de tudo, entender profundamente cada ponto do sistema e do domínio de forma que possa criar um sistema de avaliação apropriado.

 

Se minhas palavras têm sido duvidosas, sugiro que o leitor dê uma olhada no repositório do rSpec no rubyforge.

 

Antes de mergulhar, devemos pensar se realmente vale a pena tornar tarefas tão triviais (como testar pedaços de código) em algo tão elaborado. Devemos pensar se isso realmente vai nos trazer algum avanço ou produtividade como resultado final.

 

Seguir

Obtenha todo post novo entregue na sua caixa de entrada.