Rails Way #7: Geradores de Código

7 de abril de 2009  |  Rails Way  | 

2084287794_ecbee303db

O Ruby on Rails possui algumas dezenas de geradores de código que visam automatizar tarefas repetitivas, economizando o tempo de desenvolvimento e evitando que o programador tenha que se repetir. Geradores de código tem tudo a ver com a filosofia “Don’t Repeat Yourself”.

Aplicativos que geram código

Se expandirmos nossos horizontes para outras linguagens de programação menos dinâmicas, talvez geradores de código possam ser muito úteis na criação de arquivos XML de configuração, justificando de maneira óbvia o seu custo. Ao usar ferramentas como o Microsoft Visual Studio eu simplesmente informava ao editor que desejava criar uma aplicativo MFC (Microsoft Foundation Classes) e ele gerava para mim um esqueleto com mais de 2000 linhas de código, uma economia de tempo incalculável.

Algumas pessoas são totalmente contra este tipo de gerador de código porque na maioria dos casos o programador que o utiliza não entende exatamente o que o código gerado está fazendo. Embora isto seja uma realidade, isso não deve ser uma justificativa para evitar ferramentas como essa, já que na maior parte do tempo o problema está no programador e não na ferramenta. No exemplo que dei acima, embora eu nunca tenha parado para analisar cuidadosamente o que cada uma das 2000 linhas de código gerados pelo Visual Studio faça, eu entendo no contexto o porque delas, e para mim isto sempre foi o suficiente para tocar um projeto à partir deste esqueleto.

No Rails também encontramos alguns geradores deste tipo na forma de scripts (./script/generate scaffold, por exemplo). Os scripts geradores de código do Rails nos ajudam a manter as convenções propostas pelo framework com mais facilidade, e normalmente incluem apenas algumas poucas linhas de código em cada arquivo gerado.

Raramente você achará útil criar um script ou aplicativo gerador de código para um projeto Rails. Mas ao criar um plugin ou mesmo o seu próprio framework em Ruby, talvez seja prático investir na criação deste tipo de gerador. Mas não se engane, construir um gerador de código deste tipo é uma tarefa que consome tempo e um grande esforço. Além do tempo gasto na codificação do gerador, também deve-se levar em consideração o esforço necessário para manter o projeto (atualizações, correções de bugs e inclusão de novas funcionalidades) e para treinar a sua equipe (e re-treinar após modificações).

A escolha do seu editor preferido também depende muito da capacidade que ele possui de gerar código. O TextMate, por exemplo, durante muito tempo foi (no meu caso ainda é) considerado o melhor editor para se trabalhar com código Ruby, e isto se deu graças aos seus famosos Bundles, que não são mais do que scripts geradores de código.

Muitos editores também permitem que você crie seus próprios “bundles”. Na maior parte do tempo é mais fácil e barato criar um script utilizando as ferramentas que seu editor lhe fornece do que criar um aplicativo do zero afim de automatizar a criação de códigos mais simples.

Metaprogramação

Usamos metaprogramação para criar softwares que tenham a capacidade de escrever código por si mesmo. Um bom exemplo disso é o ActiveRecord do Rails, que cria em tempo de execução todo o código necessário para a manipulação de informações de um banco de dados. Ao adicionar uma nova coluna no banco de dados, não precisamos alterar nenhuma linha no código do modelo, o ActiveRecord usando metaprogramação consegue identificar a nova coluna e automaticamente criará todos os métodos e atributos necessários para permitir o acesso a esta nova coluna.

Linguagens dinâmicas como o Ruby favorecem muito o uso de metaprogramação. Programadores mais avançados fazem muito uso destes recursos para diminuir repetições em seus códigos.

A ferramenta mais comum de metaprogramação é um compilador, já que ele permite que você escreva pequenos programas em uma linguagem de alto nível afim de gerar programas em linguagem de máquina. Uma brincadeira comum que envolve o exercício de metaprogramação é montar um quine, que é um programa que deve produzir uma única saída que é o seu próprio código fonte. Veja um exemplo em Javascript:

unescape(q="unescape(q=%22*%22).replace('*',q)").replace('*',q)

Execute o código acima e você terá como saída um texto com exatamente o mesmo código gerador. Tente fazer o mesmo em Ruby, é um bom exercício!

Helpers

O diretório helpers não foi adicionado ao Rails à toa, ele está lá para ser utilizado. Helpers são fáceis de criar e podem ajudar a diminuir uma quantidade razoável de repetições em suas views. Quando criados utilizando-se de recursos de metaprogramação podem fazer uma grande diferença.

Linguagens de marcação como o Haml, servem de grande incentivo para estimular a criação de helpers em projetos Rails.

Finalizando

Geradores de código são ferramentas essenciais no dia-a-dia dos programadores e são extremamente importantes para aumentar nossa produtividade e evitar que tenhamos de escrever códigos desnecessários.

Faça uso dos geradores que você tem a disposição, e também crie seus próprios geradores quando forem realmente necessários. Mas mantenha-se longe de geradores que criem código que você não sabe para que serve ou que não entende.


5 Comentários


  1. E ae Carlos!

    “Mas não se engane, construir um gerador de código deste tipo é uma tarefa que consome tempo e um grande esforço.”

    Concordo e assino em baixo. Foi por esse motivo que eu enviei para o Google Summer of Code desse ano uma proposta para reescrever a estrutura de geradores do Rails.

    A idéia é ter uma DSL para geradores e que eles possam ser herdáveis e facilmente manipulados. No estado atual, o pessoal do rspec tem que manter um gerador chamado rspec_scaffold, que gera tudo (modelos, controladores e views), então ele assume mais responsabilidades do que deveria. O mesmo acontece pro cucumber, eles tem que manter um cucumber_scaffold. Se você quer usar rspec + cucumber no scaffold, ou você roda dois comandos, ou você tem que criar um terceiro scaffold: rspec_cucumber_scaffold.

    A idéia é ter uma linha no seu environment que permita a customização:

    config.rails.scaffold :activerecord, :actioncontroller, :actionview, :testunit, :public

    Se você quiser usar Datamapper e Rspec:

    config.rails.scaffold :datamapper, :actioncontroller, :actionview, :rspec, :public

    E quiser adicionar Cucumber:

    config.rails.scaffold :datamapper, :actioncontroller, :actionview, :rspec, :cucumber, :public

    Espero que eu consiga esse projeto. ;) Caso não, quem precisar de um gerador descente, com boa DSL, pode usar o projeto que o pessoal do Merb usa:

    http://github.com/jnicklas/templater/tree/master

    Abraços!

  2. @José,

    Sinceramente também espero que você consiga! Mas se não conseguir… vamos conversar… hehe

  3. Geração de código é um assunto polêmico.

    Eu estava escrevendo um monte aqui, mas acabei com um post pro blog:

    http://blog.dolucas.com/o-dilema-da-geracao-de-codigo

    Resumindo, acho que o uso de gerador (seja em disco ou em memória) é valido enquanto o código se mantiver simples para o programador. Complicou ou perdeu a flexibilidade que ele desejava? Aí é hora de parar pra pensar se vale a pena ou é melhor bolar uma estratégia mais reutilizável.

    Inclusive, acho que às vezes, código repetido, como um scaffold padrão, é bom pra manter essa simplicidade. Todo mundo sabe como ele funciona. Eu não gosto de plugins que fazem muito mas exigem um bom aprendizado para poder utilizá-los.

    @José: Parabéns pelo projeto!

  4. Olá Carlos,

    Acompanho seu blog pois acho que você escreve coisas bem legais sobre Rails…

    Me permita colocar então meu ponto de vista sobre geradores de código:

    Eu sinceramente acho que gerar código é o inverso de DRY pois o gerador repete o código pra você. Só mudou o ator da ação mas o resultado é o mesmo. Um projeto com zero código duplicado eu realmente nunca vi, pois existem algumas situações que generalizar o código torna a manutenção até pior, que ocorre bastante quando estamos falando do componente view de uma aplicação web.

    De qualquer maneira é o meu ponto de vista e continuo respeitando o seu, pois como disse o colega acima, o assunto é um pouco polêmico.

  5. @emerson,

    DRY quer dizer “Don’t repeat YOURSELF”, a idéia é exatamente que você não precise digitar o mesmo código duas ou mais vezes. Seja em um mesmo projeto ou em outros.

    Um outro exemplo de gerador de código é o comando “rails” que você executa ao criar um novo projeto Rails. O que ele faz é evitar que você precise criar todos os arquivos básicos para iniciar um projeto.

    Talvez o que você tenha em mente seja um gerador que produz exatamente o mesmo código em arquivos diferentes. Embora isto também seja considerado um gerador de código, não é do tipo que ajuda, mas do tipo que mais atrapalha porque ele estaria gerando duplicação de código. A ideia por traz de um gerador é criar um código padrão, um esqueleto. Como acontece com os arquivos gerados pelo ./script/generate model do Rails, por exemplo.

    Eu gostaria de saber sua opinião sobre estes geradores.

Trackbacks

  1. lucas de castro — O dilema da gerção de código

Deixe um comentário