Comparação entre Rails e Django

Em: 01/09/2007 Tags: Django, Rails Referencie do seu blog (Trackback)

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.

12 respostas para “Comparação entre Rails e Django”

  1. Valdinei disse:

    Muito bom seu post, gostei das informações passadas.

  2. Paiva disse:

    Muito bom Post, pena não ter visto ele antes pois estava estudando os 2 frameworks pra desenvolver um projeto igual ao seu. E a minha conclusão foi a mesma. Quanto ao seu projeto, eu tenho 2 lms desenvolvido, 1 foi o e-proinfo que realizei quando trabalhava no Mec, e tenho um outro baseado no dokeos que pra mim é um dos melhores lms já realizados. Se precisar trocar ideias sobre lms mande um email que terei prazer em ajudar, sobre o moodle esquece pq pedagogicamente ele quebra todas as regras de educação a distância. Eu comparo o moodle como “a vergonha” dos lms, usa quem não conhece os outros.

  3. Marinho Brandão disse:

    Olá Caio, parabéns pelo artigo! Ficou bacana xD

    Sobre alguns apontamentos seus, considere os seguintes links:

    Quanto à sua conclusão, faço coro e complemento: o Rails está à frente, o Django vai muito bem, e ambos são grandes opções para quem está chegando.

    Um abraço!

  4. Caio disse:

    Olá, Paiva Não conheço bem o Dokeos, mas obrigado pela dica, vou procurar conhecer os recursos dele.

    Marinho: Obrigado pelas dicas! É bom saber que o Django possui todas essas opções que tu mencionou.

  5. Andrews Medina disse:

    Olá,

    muito legal seu post, mas há algumas informações erradas nele!

    Primeiramente o Django aceita TDD, através de Doctests, Unittests e tem um módulo específico para testar views (posts, gets, e etc), pode achar documentação sobre ele no site oficial do Django.

    A extensao dos arquivos de template é você que define, se quiser usar .html pode usar, se achar melhor .djhtml pode usar, ou qualquer outra que achar melhor. Quanto a visualização do vim tem um plugin para templates do Django no site oficial do vim, e que funciona com .html normalmente.

    Na questão de tutoriais, o Django tem uma comunidade aqui no Brasil e tem vários blogs sobre Django. Há varios sites que auxiliam os desenvolvedores que usam Django como o djangosnippets.org , que é um cookbook com muita coisa em django. Tem o djangobook.com que é um livro online, entre outros.

    Eu acho que Django não tem tudo que rails, por isso se tu programa em ruby, mas se sentir mais confortável que o rails. Mas o Django tem coisas que o rails não tem, e creio que até a versão 1.0 serão supridas.

    Como tu mesmo disse a escolha vai de cada um, eu acho o rails uma ferramenta fantástica, mas na minha experiência o Django é mais produtivo!

  6. Marcelo Minholi disse:

    Oi Caio, Paiva e demais leitores. O artigo ficou realmente muito bom, eu estou desenvolvendo um projeto para a Universidade onde trabalho (não é um LMS) usando o Django e tenho me sentido muito a vontade com o Framework, embora esteja esperando a liberação do newforms-admin para poder fazer uma série de coisas que preciso.

    Quanto ao Moodle e o Dokeos como LMS’s, eu uso os dois, conforme pode ser visto nos endereços http://virtual.unipar.br e http://moodle.unipar.br e inclusive fui o responsável por traduzir o Claroline e também o Dokeos para a língua portuguesa ainda nos anos iniciais da existência dos projetos. Fiquei interessado na opinião do Paiva sobre o Moodle, principalmente por saber que esteve envolvido no desenvolvimento no e-Proinfo, que é um projeto pelo qual tenho grande admiração, mas gostaria de levar essa discussão adiante se possível, pois não vejo algo que desabone o Moodle como AVA, pelo contrário.

    Quanto a usar o Django como plataforma para rodar apps plugáveis, isso é possível, mas seria necessário para isso desenvolver uma aplicação que pudesse ser capaz de fornecer a arquitetura básica necessária para tal, já que o Django é um Framework e não um CMS. Aliás, existem vários projetos hoje em andamento com a proposta de desenvolver um CMS de código aberto em Django, e acho que isso seria bastante interessante se viesse a acontecer em breve.

    Também gostaria de apontar um pequeno erro em um dos códigos do artigo onde o seguinte código Django:

    {% for user in users %}

    • {{ user.full_name }}

    {% endfor %} deveria ser escrito assim:

      {% for user in users %}
    • {{ user.full_name }}
    • {% endfor %}

  7. Marcelo Minholi disse:

    Oops!

    Código original do artigo:

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

    Código correto:

    
    <ul>
    {% for user in users %}
      <li>{{ user.full_name }}</li>
    {% endfor %}
    </ul>
    
  8. Gabriel Falcão disse:

    Não vou falar com certeza absoluta, mas acho q o conceito de active record[1] se aplica perfeitamente ao rails, mas não tão bem ao django, a camada de interface com persistência do django pode ser considerada um ORM[2], a do rails sim, uma ctive record. Por exemplo, o elixir[3] é um active record para o ORM Sql Alchemy[4] Mas como já disse, não posso dizer ao certo, é só um parêntese mesmo :)

    Abração! [1] - http://en.wikipedia.org/wiki/Activerecord [2] - http://en.wikipedia.org/wiki/Object-relationalmapping [3] - http://elixir.ematia.de/ [4] - http://www.sqlalchemy.org/

  9. Bruno Azisaka Maciel disse:

    Muito bom o post.

    Poderia fazer um passo-a-passo de desenvolvimento de um sisteminha simples em Rails e depois em Django. Abraço

  10. EduardoWillians disse:

    Caí de para-quedas aqui. Ótima comparação. Parabéns! Ótimo post. Seu blog é excelente.

  11. Caio Moritz disse:

    Valeu, Eduardo!

    Espero que continue acompanhando o blog.

    Abraço

  12. Lauro disse:

    Outro paraquedista :) .

    Muito boa tua analise, estou investindo meu tempo em django por causa do python.

    Mas, a existência do Abelo me dá animo para conhecer RoR também.

Escreva um comentário (utilize o formato Markdown)