Notificadores de email no GNOME

Uma categoria de programas que (em teoria) facilitam a vida daqueles que lêem seus emails várias vezes ao dia é a dos notificadores de novas mensagens. Esses softwares, por motivos de facilidade de instalação e uso, costumam ser associados a um ambiente integrado (como KDE ou GNOME) e, após configurados, exibem de maneira discreta notificações a respeito de novas mensagens que estejam chegando na sua caixa de entrada. Este artigo analisa as opções disponíveis para o GNOME.

O primeiro que testei foi o mail-notification. Para instalar (assumindo uma distribuição Ubuntu ou baseada em apt):

sudo apt-get install mail-notification

Em seguida abra o programa e configure uma nova conta (botão Add da aba inicial). Lá é possível escolher entre alguns servidores de email. No meu caso configurei o Gmail.

Em poucos minutos de uso notei que o programa não é livre de bugs. A notificação de mensagens aparece e desaparece quando menos se espera (mas fiquei com a impressão de que isso é um comportamento proposital).

Clicando com o botão direito sobre o ícone é possível abrir a última mensagem (no meu computador o programa provocou o início do Firefox, mas como eu não estava autenticado fiquei empacado na tela de login).

Outra opção é o gmail-notify. Para instalar:

sudo apt-get install gmail-notify

A vantagem desse sobre o mail-notification é que o ícone de alerta não some da tela quando você menos espera. A desvantagem é que você não pode ver informações básicas sobre as mensagens que estão na sua caixa de entrada.

Para ser sincero não gostei de nenhum dos dois, então tentei ainda o o checkgmail. Para instalar:

sudo apt-get install checkgmail

A vantagem dele é que possui o melhor dos outros dois programas: seu ícone de notificação não some da tela e apresenta detalhes sobre as últimas mensagens da caixa de entrada quando posicionamos o mouse sobre ele. Sua vantagem sobre os outros é que é possível configurar o programa para conferir não apenas a caixa de entrada, mas quaisquer outros labels que você desejar. O lado negativo do programa é que os caracteres especiais do português (como cedilha e até mesmo acentuação) não são convertidos corretamente para um charset adequado e são exibidos de forma problemática. Mas o pior de tudo não é isso: após fechar o programa pela primeira vez tentei abri-lo de novo. Não consegui. Fui alertado sobre a falta de um pacote para encriptação e o erro me apontava para o site CPAN (que, se não estou enganado, é um conjunto de bibliotecas Perl).

Resumo: escolha aquele que funcionar pra você. Eu ainda não decidi qual vou usar…

Se você usa KDE então experimente o kcheckgmail, que não tive a oportunidade de testar.


Criador do RSpec agora trabalha no Google

Em: 12/09/2007 Tags: RSpec Comentários (2) Referencie do seu blog (Trackback)

O criador do RSpec, Dave Astels, agora trabalha para o Google. Espero escrever ainda alguns artigos sobre o RSpec assim que eu tiver mais tempo.


Estilizando o seu Gmail com Stylish

Nota (08/11/2007): Após a modificação da interface do Gmail o código CSS apresentado neste post deixou de funcionar.

Há alguns meses, procurando entender para que serviam as tais “user stylesheets”, me deparei com a extensão Stylish, para o Firefox. Não vou entrar em detalhes sobre todo o potencial dela, mas basta saber que com ela é possível definir suas folhas de estilo para todos os sites que você visualiza. Essas folhas passam a ser carregadas automaticamente, e você pode desabilitá-las facilmente. Sim, isso é muito bonito… mas tem algum uso prático?

Instalação e utilização

Após instalar a extensão reinicie seu Firefox. Note que, agora, aparece um novo ícone no canto inferior direito da janela. Clicando sobre esse ícone, e em seguida passando o mouse sobre a opção “Write style…”, podemos escrever estilos para a URL sendo visualizada (1ª opção) e para o domínio sendo visualizdo (2ª opção). Deixo para você a missão de descobrir as demais possibilidades. Para este tutorial você precisa lembrar apenas da 2ª opção.

Gmail

Eu utilizo o Gmail já há alguns anos, e embora goste bastante de sua usabilidade, considero sua interface muito poluída para alguém que utiliza sua interface por várias horas ao dia. Como não sou o desenvolvedor do Gmail, você pode pensar que eu terei de conviver com a minha infelicidade pelo resto da vida, certo? Mas com a Stylish é possível modificar (quase) por inteiro a interface de um site e, portanto, do Gmail.

Minhas mudanças foram simples: eliminei alguns links do menu esquerdo, eliminei algumas bordas, consegui remover duplicações da interface… Basicamente utilizei CSS para esconder elementos. Se você quiser ver o Gmail da mesma forma que eu vejo, siga a receita de bolo a seguir. Note, no entanto, que você precisa conhecer os principais atalhos de teclado do Gmail para não prejudicar sua usabilidade após importar estes estilos. Fique atento para os comentários que deixei no código CSS para saber qual declaração deve ser omitida para reativar algum link que você não consiga viver sem.

  • Clique no ícone da Stylish, no canto inferior direito da sua tela do Firefox
  • Vá para a opção “Write style…”, e em seguida em “For mail.google.com…”
  • Substitua toda a declaração que aparece na área central da nova janela pela listagem de código CSS abaixo
  • Defina uma descrição para essa folha de estilos
  • Salve a configuração

Meu CSS para o Gmail:

@namespace url(http://www.w3.org/1999/xhtml);

@-moz-document domain("mail.google.com") {

body .lk { /* Tries to remove the underline from all the links - but fails */
    text-decoration: none !important;
}

body div#gbar { /* The Google Services links on the top left */
    display: none !important;
}

body div#guser.mlo { /* The "username@gmail.com | ... | Sign out" links */
    float: left !important;
    padding-left: 1em !important;
}

body #guser #prf_g.setl,
body #guser a { /* The "Settings | Help | Signout" links */
    text-decoration: none !important;
}

/* The search-related elements */
body table tr td div#mt1.s table tr td span#mt_cf1.lk { /* The "Create a filter" link */
    display: none !important;
}

body div#nav div#nb_1 { /* "Invite a friend" box */
    display: none !important;
}

body div#nav div#nb_2 { /* "Messaging" box */
    display: none !important;
}

body div#nav div#nb_0 div#nvl table tr td b.rnd { /* Green lines that stand above and below the "Label" box */
    display: none !important; 
}

body div#nav div#nb_0 div#nvl div.nb { /* "Label" box outter */
    background: none !important;
}

body div#nav div#nb_0 div#nvl div.nb div#nt_0.s td.s { /* "Label" box header */
    display: none !important;
}

body div#nav div#nb_0 div#nvl div.nb div#prf_l.lk { /* The "Edit labels" element */
    display: none !important;
}

body div#nav div.nl span#comp.lk, /* The "Compose Mail" element */
body div#nav div.nl span#ds_all.lk, /* The "All Mail" element */
body div#nav div.nl span#ds_drafts.lk, /* The "Drafts" element */
body div#nav div.nl span#ds_starred.lk, /* The "Starred" (and star image) elements */
body div#nav div.nl span#ds_sent.lk, /* The "Sent Mail" element */
body div#nav div.nl span#ds_chats.lk, /* The "Chats" (and ballon image) elements */
body div#nav div.nl span#ds_spam.lk, /* The "Spam" element */
body div#nav div.nl span#cont.lk { /* The "Contacts" element */
    display: none !important;
}

body div div#co div#tct.thc div.tbc div.tbcr { /* "Refresh" */
    display: none !important;
}

body div#co div#tct.thc div.tbc div.tbcb button { /* The "Archive", "Report Spam" and "Delete" buttons */
display: none !important;
}

body div#co div#tct.thc div.tbc div.tbcs span#sl_r.l, /* Select: Read */
body div#co div#tct.thc div.tbc div.tbcs span#sl_u.l, /* Select: Unread */
body div#co div#tct.thc div.tbc div.tbcs span#sl_s.l, /* Select: Starred */
body div#co div#tct.thc div.tbc div.tbcs span#sl_t.l { /* Select: Unstarred */
    display: none !important;
}

body div div#co div#tcb.thc div.tbc { /* The message toolbar of the bottom (Select: All, None, ..., Unstarred) */
    display: none !important;
}

body div div#co div.fs table tr td#fi div#rhc div.rh div#ra { /* The big AdSense box */
    display: none !important;
}

body div div#co div.fs table tr td#fi div#rhc div.rh div#rb div.rhh { /* The "About these links" container */
    display: none !important;
}

body div#ft div.ft {
    display: none !important; /* The first line: random help messages */
}

body div#ft div.fv {
    display: none !important; /* Last but one (Gmail view: standard with...) */
}

body div#ft div.fcs {
display: none !important; /* The last line (Termos of User, Privacy Policy etc.) */
}

}

Se tudo deu certo as mudanças se aplicarão ao Gmail imediatamente. Para desabilitar o estilo é só clicar no ícone da Stylish, e em seguida clicar sobre a primeira opção que aparece, de baixo para cima, que será a descrição que você deu ao estilo.

Para editar esse código uma vez que ele foi aplicado a um site, clique no ícone da Stylish e vá em “Manage Styles…”. Em seguida escolha a folha de estilos desejada.

Conclusões

O grau de utilidade da Stylish para determinado site é diretamente proporcional ao grau de preocupação dos criadores desse site com a separação entre estrutura (HTML) e apresentação (CSS). Os desenvolvedores do Gmail, por exemplo, possuem diversas propriedades ligadas à apresentação expressas inline em seu código HTML (como a largura do logo do Gmail). Neste caso em especial é impossível para mim sobrescrever a largura desse logo pelo CSS, pois a prioridade dos estilos inline é sempre superior a daqueles declaradas em um arquivo CSS externo.

Portanto, saiba desde já que você não poderá fazer tudo que pensar com todos os sites que você mais gosta, mas provavelmente poderá se divertir bastante tentando.

Atualização 1 (15/10/2007):

  • Link “Sent Mail” foi retirado
  • Link “Drafts” foi retirado
  • Link “All Mail” foi retirado
  • Botão “Archive” foi retirado
  • Botão “Report Spam” foi retirado
  • Botão “Delete” foi retirado
  • Os links do topo esquerdo foram removidos
  • Os links do topo direito foram arrastados para o extremo esquerdo
  • Muitos links perderam o sublinhado

Atualização 2 (17/10/2007):

  • Links “Settings | Help | Logout” não são mais sublinhados

Atualização 3 (30/10/2007):

  • Link “Spam” foi retirado: os spams são removidos pelo Gmail em 30 dias, então melhor não vê-los, certo?

Atualização 4 (08/11/2007):


Mudando de Netvibes para Google Reader

Meu primeiro leitor de feeds foi o Netvibes. O sistema é bastante simples de usar e poderoso. Possui diversos atalhos de teclado, possibilidade de se criar abas para organizar melhor o conteúdo entre outros. Meu problema com o Netvibes passou a ser exatamente o “entre outros”. Como eu o utilizo apenas para ler feeds, comecei a achar a interface dele um pouco poluída. Eu disse “um pouco”: apesar da infinidade de recursos, o Netvibes ainda consegue prover uma interface limpa se você quer usar apenas 10% de seus recursos.

Passei então para o Google Reader. Exportar os feeds de um serviço para o outro é muito simples graças ao formato OPML. E o que eu achei do Google Reader? Gostei muito do sistema. A interface é tão intuitiva quanto a do Netvibes mas, no meu caso, limpa do jeito que eu preciso. Os atalhos de teclado estão lá, e são muito úteis. Até o momento não senti falta de nenhuma funcionalidade do Netvibes.

Listando todos os feeds sob a mesma tag

Enquanto o Netvibes organiza nossas tags em abas, e os feeds em caixinhas, o Google toma uma abordagem mais simples. As tags e seus respectivos feeds são listadas na esquerda, em forma de árvore (como a hierarquia de diretórios do Windows Explorer). A vantagem é que se clicamos na tag, e não no feed, vemos todos os artigos de todos os feeds sob aquela tag listados na área central. Isso agiliza a leitura, pelo menos para mim.

Velocidade

Outra vantagem do Google Reader sobre o Netvibes foi o tempo para carga da página inicial. O tempo que o Netvibes leva para carregar, após o login, é muito alto se comparado ao serviço do Google.

Para aqueles com resoluções menores

No meu trabalho estou, atualmente, utilizando um computador digno de museu, que me dá resolução máxima de 800×600. Com essa resolução o Google Reader aproveita melhor a tela do que o Netvibes. Para resoluções maiores a diferença não é muito notável.

Conclusão

Se você só precisa de um leitor de feeds, e gosta de boas interfaces, vá de Google Reader. Se quer algo além disso, então o Netvibes deve ser a melhor opção pra você.


Atalhos de teclado do Gmail

Os defensores dos padrões web certamente não morrem de amores pelo Gmail (e com razão). Mas o fato é que ainda não conheço outro software baseado na web com tantos atalhos úteis quanto ele. Para compartilhar com vocês os atalhos que uso (acredito que não existam muitos outros) montei esta listagem. Espero que seja útil.

Vale lembrar que os atalhos do Gmail, por padrão, são desativados. Dentro da sua conta vá até “Settings”, e marque a opção “Keyboard shortcuts on”. Clique no botão “Save changes” para gravar a modificação da preferência. Agora o suporte a atalhos de teclado está ativado.

Navegação básica

  • g depois a: vai para a listagem de todas as mensagens
  • g depois c: vai para a listagem de contatos
  • g depois d: vai para a listagem de drafts
  • g depois i: vai para a caixa de entrada
  • g depois s: vai para a listagem de mensagens com estrela
  • g depois t: vai para a listagem de emails enviados
  • j: em uma listagem, desce o cursor para a mensagem anterior
  • k: em uma listagem, sobe o cursor para a mensagem superior
  • [: quando dentro de uma mensagem arquiva a mensagem atual e move para a anterior
  • ]: quando dentro de uma mensagem arquiva a mensagem atual e move para a próxima
  • u: quando dentro de uma mensagem volta para a última listagem apresentada
  • /: posiciona o cursor na caixa de busca

Ações

  • c: compor uma mensagem
  • x: seleciona / des-seleciona uma mensagem
  • s: adiciona estrela a / remove estrela de uma mensagem
  • u: quando na Inbox atualizará (mesmo efeito do clico em “Refresh”) sua caixa de entrada
  • !: marca uma mensagem como spam
  • #: remove o email
    • quando em uma listagem, removerá as mensagens selecionadas
    • quando dentro de uma mensagem removerá essa mensagem e voltará para a última listagem apresentada
  • m: quando dentro de uma mensagem faz com que você não receba mais atualizações dessa conversação na Inbox - ela cairá direto no arquivo, não-lida.
  • y: pode ser utilizado para arquivar mensagens
    • quando em uma listagem. arquivará as mensagens selecionadas
    • quando dentro de uma mensagem
    • Se essa mensagem estiver na Inbox então ela será arquivada e você será direcionado para a Inbox
  • <Shift> + i: marca a mensagem como lida
  • <Shift> + u: marca a mensagem como não-lida
  • z: desfaz a última ação (desde que ela tenha gerado a mensagem de “Undo”
  • <Shift> + n: atualiza a conversação (ideal quando alguém manda uma resposta para o email que você está lendo)

Improvisando atalhos

  • Ver meus drafts:
    • /: para chegar à busca
    • Preencher o campo de busca com “in:trash” ou “label:trash” e apertar Enter

Pode-se utilizar a mesma técnica para visualizar mensagens com estrela (is:starred), não lidas (is:unread) etc. Para conhecer melhor os filtros de busca consulte esta questão do Gmail FAQ.

Outra solução para improvisação é a utilização da extensão GreaseMonkey do Firefox.

Compondo uma mensagem (atalhos do editor WYSIWYG)

  • Ctrl + b: aplica negrito ( bold) ao texto selecionado.
  • Ctrl + i: aplica itálico (italic) ao texto selecionado.
  • Ctrl + s: salva (save) a mensagem sem a enviar.
  • Ctrl + u: aplica sublinhado ao texto selecionado.
  • Ctrl + z: desfaz uma modificação.

Atualização 1 (15/10/2007):

  • Adicionados os atalhos para “All Mail”, “Drafts”, “Report Spam”, “Sent Mail” marcar como spam.
  • Improvisação do atalho para a listagem de drafts tornou-se desnecessária.

Atualização 2 (08/11/2007):


Symfony: uma visão geral

O último framework que pretendo analisar este ano é o Symfony. Há algumas razões para escolhê-lo:

  1. É escrito em PHP (minha análise já inclui frameworks em Ruby e Python)
  2. Não tenta ser uma versão PHP do Rails (não que isso fosse algo ruim)
  3. Possui farta documentação (inclusive um livro em português, que divide sua atenção com outros frameworks PHP populares)
  4. Possui um livro oficial já publicado (isso é uma vitória quando consideramos que há em torno de 50 frameworks PHP por aí)

Este artigo, diferente de outro em que comparei Rails e Django frente a frente, pretende ser mais “light”: aponta apenas as diferenças de abordagens entre Rails e Symfony, sem entrar em tantos detalhes. Dito isso podemos seguir em frente.

Instalação

A instalação do framework foi feita sem grandes problemas, seguindo o tutorial do Symfony Brasil para instalação no Ubuntu. Basicamente fazemos a instalação com auxílio do PEAR. Não conheço nada a respeito do projeto PEAR, mas para mim pareceu uma alternativa PHP ao RubyGems.

Rodando a primeira aplicação

Durante a instalação somos “convidados” a criar a nossa primeira aplicação. Após a instalação fica disponível o comando symfony, responsável por criar a estrutura básica de diretórios do projeto, como acontece com o Rails. Em seguida, somos também convidados a configurar nosso apache2.conf para rodar essa nossa aplicação… peraí, já estamos no Apache? Será que não existe, dentro do Symfony, um servidor web para desenvolvimento, que iniciamos com um comando apenas, ao estilo WEBrick, do Ruby, ou o servidor de desenvolvimento do Django?

Resolvi ir direto à fonte, o livro do Symfony, no capítulo 3, “Running Symfony”. A seção “Configuring the Web Server” vai pelo mesmo caminho: configuração do Apache. Isso me intimidou um pouco, pois tenho um histórico de surras memoráveis contra o Apache (horas a fio para configurar as regras mais simples). Decidi não rodar minha aplicação recém-criada para evitar muito estresse.

Decidi, então, conhecer o framework “de fora para dentro”: como são implementadas suas funções principais, tais como ORM, validações e TDD.

Mapeamento Objeto-Relacional

Da mesma forma como Rails e Django, o Symfony adota um Mapeamento Objeto-Relacional (ORM) como maneira de facilitar a programação de código orientado a objetos sobre bancos de dados relacionais.

O ORM do Symfony é delegado a uma biblioteca provida por terceiros (Propel), a qual é desenvolvida sobre uma biblioteca de abstração de banco de dados (Creole). Propel parece ser uma biblioteca madura e robusta, de acordo com as funcionalidades descritas no site do projeto.

A parte que mais me interessa no caso de ORM é a definição de relacionamentos entre as tabelas ou modelos. A abordagem da ActiveRecord, por exemplo, fez uso das facilidades de Ruby para metaprogramação, criando uma Linguagem de Domínio Específico (DSL) para definição de modelos e suas relações. Como a Propel se sai nessa tarefa?

Tanto as tabelas Propel quanto os relacionamentos entre essas são definidos por esquemas XML. Bom, lembro de ter lido uma vez, não lembro onde, que XML só podia ser considerada uma linguagem “peso leve” se comparada à Java, uma linguagem “peso pesado”. Por exemplo, na comunidade Ruby, sempre que possível, vejos os projetos utilizando YAML em detrimento de XML. Por que? Pois YAML é mais fácil de manter manualmente, por não ser baseada na “sintaxe do abre-e-fecha” do XML. “Ah, mas quem precisa manter XML manualmente se temos IDE enormes que fazem isso por nós?”. Ok, cada um na sua.

E não é que a comunidade Symfony também gosta de YAML? Quando trabalhando em um projeto Symfony você define seus modelos em YAML, e o framework se encarrega de traduzir suas definições para o formato XML do Propel. Isso é muito bom!

Embora eu não tenha encontrado esse fato na minha leitura rápida pela documentação, Elliot Smith alerta para o fato de que no Propel é necessário declarar 4 classes por tabela, o que achei bastante estranho.

Validações

Uma das diferenças entre Rails e Symfony é o local onde são declaradas as validações dos modelos. No Rails elas são declaradas dentro dos próprios modelos, como código Ruby. Já no Symfony são declaradas externamente, em arquivos YAML.

Controle da evolução do banco de dados

O controle de evolução do banco de dados, no Rails, é feito por meio de migrações. Com elas é possível escrever, em Ruby, operações de atualização do seu banco de dados e garantir a atualização dos sistemas em produção de forma (teoricamente) indolor.

Como isso é feito no Symfony? De acordo com o wiki do projeto esse suporte existe, mas não conta com abstração de SGBD. Ou seja: migrações à base de SQL puro, sendo, portanto, dependente do SGBD escolhido.

Para maiores informações confira o artigo “Migrations” no wiki do Symfony.

Agilidade no desenvolvimento

Uma das coisas que torna ao menos o meu desenvolvimento ágil é o IRB do Rails. Com ele posso interagir com os meus modelos, testar minhas validações quando nada parece fazer sentido etc. Com o Django também é possível utilizar o shell interativo para interagir com os modelos. Mas e no Symfony, como fica? Acredito que não seja possível simular algo tão poderoso, depois de ter procurado sobre o assunto no Google. Isso é uma desvantagem grande.

Como não tive uma experiência real de desenvolvimento, recomendo que você confira o artigo do Elliot Smith sobre o desenvolvimento de uma pequena “blog engine” no Symfony.

Testes de software

O Symfony trabalha com um framework embutido para testes, chamado Lime. Eu não sou experiente em testes de software, e menos ainda com testes para código PHP. Mesmo assim foi possível compreender, pela documentação do capítulo 15 do livro do Symfony, que se trata de um framework completo: há testes para modelos, para controllers e para views, incluindo os testes com suporte a seletores CSS (que testam, por exemplo, se os elementos HTML que esperamos fazem parte do documento que retorna como resposta a uma determinada requisição HTTP).

Algo que chama a atenção é que, diferentemente dos frameworks xUnit, os testes do Lime não são cercados por uma classe. Os testes são executados no escopo global, após a inclusão (require) de alguns scripts. Acabei sem entender como o framework lida com a ausência dos métodos setup e tear_down. Para separar melhor a finalidade de cada teste o Lime usa e abusa da separação dos testes por diversos arquivos.

Links relacionados


Vim modo Markdown

Recentemente escrevi um post que dava dicas sobre como habilitar o formato Markdown dentro do Wordpress. Apesar de eu gostar muito do Wordpress, escrevo meus textos no Vim, meu editor de textos favorito.

Se você também usa o Vim para editar textos Markdown, talvez não saiba que existe uma forma de colorir esse texto. A seguir seguem os passos para configuração do seu Vim (considero que você utiliza um ambiente UNIX-like).

Baixe o arquivo mkd.vim e o coloque dentro do diretório .vim/syntax (crie esse diretório caso ele ainda não exista).

Crie o arquivo .vim/filetype.vim com o seguinte conteúdo:

" markdown filetype file
if exists("did\_load\_filetypes")
 finish
endif
augroup markdown
 au! BufRead,BufNewFile *.mkd   setfiletype mkd
augroup END

Por último, adicione o seguinte conteúdo ao seu arquivo .vimrc:

syntax on
augroup mkd
    autocmd BufRead *.mkd  set ai formatoptions=tcroqn2 comments=n:>
augroup END

A coloração de sintaxe passa a funcionar agora em todos os seus arquivos de extensão .mkd.

Para maiores informações consulte a página do criador dessa técnica.


Comparação entre Rails e Django

Recentemente decidi conhecer o framework Django pois, de acordo com algumas discussões na lista do Rails, aquele era mais adequado para o desenvolvimento de aplicações modulares. Como disse em outro post, estou construindo uma aplicação web extensível (através de plugins e temas, por exemplo).

Meus testes com o Django duraram mais ou menos uma semana. Em primeiro lugar eu precisava ganhar um pouco de conhecimento da linguagem sobre a qual o framework é construído: Python. Essa foi a parte mais fácil. Não porquê eu a tenha considerado uma linguagem simples de aprender, e sim porquê eu não precisava aprender tanta coisa assim antes de poder mergulhar no uso do framework.

Antes de começar a comparação, gostaria apenas de adiantar uma das conclusões: o tipo de modularidade que eu preciso, que é a capacidade de escrever uma aplicação com componentes plugáveis (semelhante aos temas, plugins e widgets do Wordpress) é bem diferente do conceito de modularidade pregado pelo Django (e isso eu só descobri ao longo do estudo). O significado de modularidade para os desenvolvedores do Django é a facilidade para trocar componentes completos entre aplicações. Isso ficará mais claro ao longo deste artigo.

Este artigo assume que você tem um entendimento superficial sobre a proposta do Rails, mas não do Django. As versão analisadas são Rails 1.2 e Django 0.96.

A terminologia dos frameworks

As diferenças entre Rails e Django começam cedo, já na terminologia. Ambos são construídos sobre a arquitetura MVC. Mas o que cada uma dessas letras significa em cada uma das abordagens?

O que há de comum nas terminologias:

  • O M significa Model, modelo, e se traduz na biblioteca de software que abstrai o banco de dados da aplicação. Classes são mapeadas para tabelas, e objetos são mapeados para registros.

O que muda:

  • C (Controler)
    • Em Rails, o Controller é uma classe cujos métodos são responsáveis por atender as requisições da aplicação. Cada método, em geral, realiza funções tais como recuperar uma listagem de registros do banco de dados e deixar os dados prontos para que um View os apresente.
    • Os criadores do Django vêem o próprio framework como o Controller da aplicação, e entendem por View aquilo que o Rails entende por Controller.
  • V (View)
    • Em Rails, um View é um trecho de código responsável por gerar saída HTML. Nenhuma operação de acesso ao banco de dados deve ser realizada em um View (essas fazem parte do Controller). As variáveis inicializadas no Controller ficam disponíveis para o respectivo View.
    • O Django entende por Template aquilo que o Rails entende por View.

Resumindo, tem-se as seguintes relações:

  • Rails Controller X O próprio framework Django
  • Rails Model X Django Model
  • Rails View X Django Template

Criando uma aplicação

Em Rails uma aplicação pode ser criada com um simples comando:

> rails nome_da_aplicacao

Em Django:

> django-admin.py startproject nome_da_aplicacao

Estrutura de diretórios

Uma vez criada a aplicação, acabamos com a seguinte estrutura de diretórios para a aplicação Rails (apenas os principais arquivos foram listados):

app/
 controllers/
 helpers/
 models/
 views/
   templates/
config/
 routes.rb
 database.yml
db/
script/
 generate
test/
vendor/

Para o Django, a estrutura criada é bem mais enxuta:

__init__.py
manage.py
settings.py
urls.py

Enquanto o Rails cria uma grande árvore de arquivos, o Django cria apenas 4.

Durante a construção de uma aplicação Rails essa estrutura de diretórios, em geral, é mantida. O desenvolvedor faz uso do programa script/generate para gerar Controllers, Models e Views (e seus respectivos testes).

No Django, ao contrário, o desenvolvedor acabará, obviamente, com uma estrutura de diretórios bem maior do que aquela com a qual iniciou o projeto. Em geral cada nova funcionalidade demanda um novo diretório, pois essa é a filosofia do Django: cada diretório da sua aplicação deve, em teoria, ter a capacidade de ser “plugado” em uma outra aplicação Django e, com poucas configurações, continuar funcionando. É dessa forma que os desenvolvedores do Django entendem a palavra modularidade: uma aplicação é construída a partir de componentes menores, os quais podem ser trocados entre aplicações diferentes.

Processamento de requisições

Uma vez entendida a diferença de nomenclaturas entre os dois frameworks pode-se entender facilmente que, de forma geral, o processamento de requisições ocorre da mesma maneira nos dois frameworks:

  • O mapeamento entre URLs e o código-fonte (quais URLs invocam quais classes e métodos) fica em um arquivo de rotas (Rails e Django).
  • A lógica de negócio fica no Controller (Rails) ou em um View (Django)
  • O acesso ao banco de dados fica encapsulado por uma biblioteca implementando o padrão Active Record (Rails e Django)
  • A saída HTML é gerada dentro de Views (Rails) ou Templates (Django)

Roteamento de requisições

O roteamento de requisições, em ambos os frameworks, declara qual URL invoca qual ação em qual Controller. A grande difereça aqui, que para mim favorece o Rails, é que o Django exige que façamos a configuração de todas essas rotas, por mais simples e óbvias que possam ser.

Imagine a seguinte URL:

http://exemplo.com/users/view/1

O Rails utiliza um esquema default de mapeamento que deduz, a partir da URL acima, o seguinte:

  • controller = users (será instanciada a classe UsersController)
  • action = view (será invocado o método view nessa instância)
  • id = 1 (dentro desse método estará disponível a variável local params[:id])

Para uma aplicação simples, esse esquema pode ser suficiente para todas as suas necessidades. Se não for, você pode definir novas regras, que possuem prioridade dependente da ordem em que são declaradas.

Com o Django, por outro lado, todos os mapeamentos precisam ser definidos por meio de expressões regulares. Não é complicado (graças à documentação), mas se podemos ter isso de graça no Rails, fica chato ter que voltar a se preocupar com esse tipo de coisa dentro do Django.

Rails Controllers versus Django Views

Para comparar as duas abordagens vamos considerar que a nossa lógica de negócio envolve a manipulação de uma tabela “users”. Estamos implementando a ação “list”, que deve preparar, para exibição, todos os registros dessa tabela.

Em Rails (no arquivo app/controllers/users_controller.rb):

class UsersControler < ActiveRecord::Base
  def list
    @user_pages, @users = paginate :users, :per_page => 10
  end
end

Em Django (no arquivo nomedasub_aplicacao/views.py):

from django.shortcuts import render_to_response

def list(request):
  users = User.objects.all()
  return render_to_response('users/list.html', {'users': users})

Diferenças fundamentais:

  • Um Rails Controller é definido como uma classe, enquanto um Django View é um conjunto de funções
  • O arquivo que define o Rails Controller não costuma requerir outros arquivos ou pacotes. O arquivo que define as funções de um Django View, por sua vez, costuma requerir um ou mais pacotes.
  • Os métodos de um Rails Controller não recebem parâmetros vindos do framework. As funções de um Django View sempre recebem um objeto HttpRequest.
  • Todas as variáveis que se deseja utilizar em um Rails View devem ser inicializadas, dentro do Rails Controller, como variáveis de instância (@users, no exemplo). Esse mesmo comportamento não pode ser alcançado com o Django: é necessário passar as variáveis explicitamente para um Django Template, na forma de um dicionário Python (’nome da variável’: valor). No exemplo acima é passado o dicionário {'users': users}.
  • As convenções de Rails eliminam a necessidade de se declarar, dentro de um método do Rails Controller, qual View deve renderizar os objetos carregados no Controller. No Django essa declaração é obrigatória. Em Rails, é claro, se você precisar renderizar um View que não segue a convenção, você também pode fazê-lo facilmente.

Observações:

  • O tutorial básico do Django não indica como inicializar, dentro do Django View, um objeto que encapsule a paginação referente aos registros recuperados. Deve haver uma forma simples de fazer isso, mas fiquei impressionado por isso não estar presente no tutorial.

Rails Views versus Django Templates

É uma preocupação comum aos dois frameworks, por serem adeptos do MVC, localizar a renderização de código HTML em um arquivo distinto do arquivo que interage com o banco de dados. Esses arquivos possuem, em Rails, extensão .rb, enquanto no Django possuem extensão .html. Isso pode ser um problema para certos editores de texto. Eu, por exemplo, trabalho no editor Vim. Com alguns pacotes de configuração a coloração da sintaxe dos meus arquivos .rb fica perfeita. Já com arquivos .html do Django eu não tive a mesma sorte.

Seguindo o exemplo deste artigo, um trecho do Rails View que lista os usuários poderia ser o seguinte:

<ul>
<% for user in @users do %>
  <li><%= user.full_name %></li>
<% end %>
</ul>

E o mesmo trecho, para um Django Template:

<ul>
{% for user in users %}
  <li>{{ user.full_name }}</li>
{% endfor %}
</ul>

Nos dois frameworks um view/template pode ser mais complexo do que isso, incluindo estruturas de desvio condicional, por exemplo.

Diferenças fundamentais:

Observações:

  • Em Ruby, o código user.full_name é válido, e significa invocar o método full_name do objeto user. Mas em Python, ao contrário do que o exemplo acima dá a atender, a declaração user.full_name não invoca o método full_name de user. É o sistema de templates do Django quem faz esse processamento. Primeiro o Django verifica se full_name é uma chave do dicionário user (mesmo que user não seja um dicionário). Se não for, então verifica se é um atributo do objeto user. Se não for, então invoca full_name como um método.
  • No Django é possível utilizar um sistema de templates diferente do sistema provido pelo framework. Em Rails é possível apresentar os templates em formato XML.

Rails Models versus Django Models

Tanto em Rails quanto em Django a camada de abstração do banco de dados implementa o mesmo padrão de projeto: Active Record, proposto por Martin Fowler. Apesar disso, as duas implementações são bastante diferentes.

A implementação Ruby faz uso intenso de metaprogramação para, “automagicamente”, definir atributos e métodos dos Models. Exemplo:

class User < ActiveRecord::Base
  has_and_belongs_to_many :communities
end

No exemplo acima, declaramos a classe User, o nosso Model. Quando o código é executado, nossa classe ganha diversos métodos e atributos, referentes a todas as colunas presentes na tabela “users” do banco de dados. A invocação do método has_and_belongs_to_many também cria diversos métodos para a classe. Como todas essas definições são feitas em tempo de execução, a performance fica prejudicada. É uma escolha que se faz: facilidade e agilidade para definição de seus modelos em troca de uma performance um pouco inferior.

Mas há outra vantagem nessa abordagem: uma mudança no banco de dados não significa, obrigatoriamente, uma mudança na definição da nossa classe. No início do projeto, quando ainda não se sabe quais campos nossa tabela deve ter, isso é uma grande vantagem para o desenvolvimento. Essa filosofia de evitar repetições está presente por todo o Rails, e é conhecida como DRY (Don’t Repeat Yourself, ou “Não se repita”).

A abordagem do Django é inversa: o nosso Model é quem diz qual será a estrutura da nossa tabela. Um exemplo:

from django.db import models

class User(models.Model) # Em Python isso significa que User extende models.Model
    first_name = models.CharField(max_length=60)
    last_name = models.CharField(max_length=60)

Quando queremos que o banco de dados se modifique, precisamos rodar um comando do Django que processa as definições de modelos e cria as respectivas tabelas (se elas não existirem):

> python manage.py syncdb

A performance da implementação Django para o Active Record é, em teoria, superior a do Ruby, uma vez que as classes não são definidas por metaprogramação. Isso pode ser um fator determinante para aqueles que necessitam de alto desempenho (embora isso varie muito dependendo da configuração do seu servidor - Apache servindo em modo mod_python ou fastcgi, por exemplo).

Observações: * No Django é possível utilizar uma outra camada de abstração de banco de dados que não essa apresentada anteriormente. Segundo a documentação essa troca é feita de maneira trivial. Já no Rails, tentar utilizar uma outra biblioteca para isso provavelmente não vale a pena, pelo trabalho que daria. Mas será que alguém realmente não gosta da ActiveRecord do Ruby?

Evolução do banco de dados

No Rails, controlar a evolução do banco de dados é muito simples (comparado com Django): cada modificação na estrutura do banco de dados demanda a criação de uma nova migração. Imagine, por exemplo, que o nosso sistema já está em produção e o cliente nos diz que ele precisa de mais uma informação a respeito do usuário: sua data de nascimento.

Com o seguinte comando criamos uma nova migração:

> ruby script/generate migration add_birthday_to_users

Esse comando gera o arquivo db/migrate/???_add_birthday_to_users, onde ??? é o número dessa migração (o Rails o controla automaticamente). Abrindo esse arquivo editamos o código Ruby que realiza a nossa tarefa. Supondo que estejamos trabalhando com controle de versão de software, fazemos o commit da nossa modificação e em seguida vamos até o servidor de produção para aplicar a mesma modificação nesse banco de dados. Atualizamos o código da aplicação (com “svn up”, por exemplo), e em seguida executamos:

> rake db:migrate

Esse comando irá trazer o banco de dados para a última versão disponível.

Agora você me pergunta: e como faço essa mesma operação no Django? E eu te responderei: faça tudo sozinho, em SQL puro. É sério. No Django você controla a evolução do seu banco de dados manualmente. Para o exemplo acima isso pode até não ser um problema, pois nossa modificação era trivial. Agora considere modificações maiores, que envolve transferências de dados entre tabelas. E se sua aplicação for independente de banco de dados? Bem, você terá que escrever o SQL específico de cada SGBD.

Esse é um dos fatores que, na minha opinião, conta muito contra o Django, em sua versão 0.96.

Testes de software (TDD e BDD)

Este tópico pode ser irrelevante para quem não aplica desenvolvimento dirigido por testes, ou simplesmente teste de software. Se você se inclui nesse grupo, então não ficará triste por saber que não há uma forma muito simples de seguir essa metodologia no Django (ao menos o tutorial de iniciação no framework não dá nenhuma dica nesse respeito), e buscas pelo Google não me ajudaram muito também.

No Rails as opções são várias: você pode utilizar a biblioteca fornecida pelo próprio Rails, Selenium, RSpec (que eu utilizo e recomendo), entre outras. RSpec, por exemplo, é integrado ao Rails por meio de um plugin, muito fácil de instalar e de começar a utilizar.

A falta de TDD e BDD integrado ao Django é, na minha opinião, mais um fator que conta contra o Dango.

Particularidades do Django

Uma das características que os desenvolvedores do Django mais exaltam no framework é a interface administrativa criada “automagicamente” para os Models definidos por você. Essa interface é realmente poderosa, pois é capaz de manipular relacionamentos 1-N que o scaffold básico do Rails ignora. Para colunas que representam datas você ganha até caléndários Ajax para definir os valores.

No entanto, o visual dessa interface administrativa dificilmente será aquilo que você realmente deseja para a sua aplicação. De qualquer modo, melhor tê-la do que não tê-la.

Para o Rails há um plugin que reproduz funcionalidade semelhante: Auto Admin (o site estava fora do ar quando acessei pela última vez).

Livros sobre o assunto

Buscando por “rails” no site da Amazon encontrei em torno de 20 livros sobre o assunto. Já sobre Django, encontrei apenas 2. A situação do Django pode mudar nos próximos meses, principalmente se a versão 1.0 do Django for lançada.

A documentação do Django é muito boa, e pode ser acessada aqui. No momento, no entanto, a documentação do Rails é incomparável, com uma grande quantidade de tutoriais espalhados pela internet, blogs sobre o assunto e muitos livros disponíveis.

Conclusões

Este artigo teve por objetivo dar uma visão geral das principais diferenças entre a utilização do Rails e do Django em um projeto. Quando comecei a estudar o Django estava disposto a deixar o Rails de lado se o primeiro realmente se provasse mais adequado para o tipo de aplicação que desejo fazer. Mas, no fim das contas, concluí que nenhuma delas facilita a minha vida nesse sentido.

Bom, se nenhuma delas me ajuda no desenvolvimento de uma aplicação extensível, então qual o meu critério de escolha? A que me dá mais vantagens durante o desenvolvimento (mas outras pessoas podem escolher performance, deployment, familiaridade com a linguagem etc.). Rails, nesse sentido, está anos luz à frente. A definição de tabelas utilizando sintaxe Ruby, a definição de modelos de forma DRY, o controle da evolução do banco de dados de forma trivial, os testes com RSpec facilmente integrados à aplicação…

Se você é um programador Python experiente, recomendo que use o framework por umas semanas e tire suas próprias conclusões. Você pode se sentir muito à vontade com ele e não sentir falta dessas coisas que listei.

Se você é um programador Ruby, no entanto, recomendo que continue com o Rails. Mas essa é apenas a minha opinião.

Referências

Atualização 1 (03/11/2007): alguns trechos de código-fonte tinham problemas (apontados pelo Marcelo Minholi nos comentários). Verifique também os comentários de Andrews Medina para conhecer mais sobre as opções do Django para TDD, que não foram abordadas no artigo por não estarem explícitas na documentação oficial na época em que esta comparação foi escrita.