

A Django Developer’s Views on Rails - foobar2k
http://loopj.com/2009/05/23/a-django-developers-views-on-rails/

======
mdasen
_In the Rails world, the layer which generates the final markup sent to the
browser is called the View layer. In a Rails View, you can chuck as much rails
code as you like in amongst your markup.

Some of the early sites I worked on many years ago were written in PHP, which
had the same idea._

Um. . . Sure, you _can_ put any logic you want in a Rails template, but people
don't. Rails applications tend to have a nice separation of layout and
application logic. Django really likes to constrain users here - not even
letting them use a full "if" statement. It's really unfair to just say Rails
== Unmaintainable PHP. PHP often becomes that way because there is no
immediate way of separating the code. Smarty and others can force you, but
both Rails and Django put a really obvious place to put your app logic and
developers tend to respect that. Part of this is just how much rope do you
give a developer and it's fair to say that one shouldn't give developers that
much leeway. However, it's wrong to just equate the two.

 _Multiple Apps in a Project_

Really, neither framework (or any code) is as pluggable into random situations
as we programmers would like. The author suggests that you can use models from
different applications in Django. That sounds cooler than it is. They're all
running off the same database and in the same project. Really, what Rails
creates are projects in Django-speak. And the "apps" convention in Django
doesn't help you in development. It helps in organization sometimes -
especially the admin interface - but it isn't some spectacular thing where you
can just reuse random code in a way that you can't with Rails. Well, I take
that back, there is one way that is really nice: namespacing. You can have a
blog app that has an Entry and Category model without having to name it
BlogEntry and BlogCategory because it would conflict with your Category model
for, say, a real estate part of your app. And that is helpful in a way that
Rails doesn't solve nicely. However, for the most part Rails and Django
provide decently equal utility in this area, they just name the things
differently.

 _URL Routing_

Django's routing is really verbose. You have to specify each route you want.
Rails has a bunch of shortcuts for common cases (REST as well as
:controller/:action/:id). In a way, this is just the explicit vs. implicit
thing. Django makes you explicitly state your URLs while Rails will let you
state them, but you don't have to should you like the defaults. The Django
folk say that it takes very little time to write routes (true) and that one
should be thoughtful when making URLs (also true). But sometimes it just feels
tedious. Really, it's just a matter of preference.

 _Ruby (Perl’s Ugly Sister)_

This is kinda low at some points (why I went to it last - I don't like
dwelling on such poor arguments). Ruby doesn't actually use that many symbols
ala Perl. All variables are done without symbols; I think strings built as
"#{var} is cool" are easier to understand than "%(var)s is cool" % {'var':
var}. And it isn't like Python doesn't have weird things like "/".join(list).

Really, my beef with Ruby would be how easy (and common) it is to add methods
to ancestors without really making it clear. As you start adding methods to
Object, you can get yourself into a position where Python's explicitness is
really nice. However, when you want to get something done, Ruby can be nice in
that respect. It's like having a circular saw: really good for both cutting
wood and cutting your hand off. Likewise, Python's mixins are put onto
attributes of the model - so that you have things like house.photo.url rather
than house.photo_url (although Django did create the second for a long time).
That makes it very clear what you're adding while if you say
"acts_as_nested_set" in Rails, you don't immediately see which methods are
being added.

Ruby's problems aren't really syntactic, but it can have things that one could
define as problems.

\--

I've put out two sites in Django and one in Rails and at this point I'm
developing two projects in Rails. The Django community is really smart and
understated and I still read a lot (smart information translates well to
anything), but Django just doesn't see the same pace of development that Rails
does. Even something simple such as following reverse foreign keys isn't
implemented in Django. Yep, if you try
Entry.objects.all(select_related="comments") it will just silently fail (how's
that for letting errors pass silently that shouldn't!). And it is difficult
and Malcom has way more on his plate than any normal person could even
conceive of, but. . . it's still missing.

And the Rails community has calmed down a bit, the Merb camp seems to be
adding nicely to Rails 3, the Rails framework covers so many more edge cases
than it used to as well as just seeming more reliable, and deployment has
really stepped up with Passenger.

Django is a wonderful piece of software with great features and really smart,
considerate people using it. It just isn't seeing as great a push toward
little simplifications for more edge cases in the way that Rails has been.
Frankly, they're so much alike in all the meaningful ways - I think that's why
I have such an easy time wrapping my head around both.

Eh, I have to get dinner.

~~~
ubernostrum
"Django really likes to constrain users here - not even letting them use a
full "if" statement."

Yes, but as you've noted it's for a good reason. This is really one of the few
places where Django gets opinionated by default, and personally I'm OK with
that; keeping people off the slippery slope of "well, I _should_ write this in
a cleaner way, but for now I'll just stuff some application logic in the
template and fix it later" is a goal I can get behind.

"The author suggests that you can use models from different applications in
Django. That sounds cooler than it is. They're all running off the same
database and in the same project."

Not really. I can have multiple different Django "projects", each running its
own settings, its own database, its own URL configuration, its own templates,
etc., but all using the same single copy of an application module somewhere on
the server. Last I checked this was non-trivial to do in Rails, while in
Django it's made very easy since it's a common use case, and encourages neatly
abstracting/encapsulating common pieces of functionality for reuse.

"The Django folk say that it takes very little time to write routes (true) and
that one should be thoughtful when making URLs (also true). But sometimes it
just feels tedious. Really, it's just a matter of preference."

Personally, I tend to view this more as a security concern than a programmer-
convenience concern; if my framework is auto-mapping URLs to any code it can
find, it may auto-map some things that I didn't want to expose (this was the
source of an exploitable vulnerability in Rails a while back, as you may
remember). If the framework only handles the URLs I tell it to handle, I don't
get that situation.

Mostly, though, I like Django because it (and Python) fits my brain.

~~~
mdasen
If people don't agree on the IF statement, they just don't agree on it. I find
that I can discipline myself enough to use a full IF - having always used the
pyif (<http://www.djangosnippets.org/snippets/130/>) template tag in Django. I
don't think this is such a big deal since one can swap out the templating
layer in both Django and Rails for something they'd rather. If anyone reading
this sees this as a big point, Liquid in Rails offers a more Django-like
experience and Cheetah will give you things like full IFs in Python.

You make a good point about not having to copy the code into the project
directory and have multiple pieces of code sitting on the server. Someone
pointed out that Rails Engines (included in 2.3) allow for this, but I haven't
personally used them to know how nicely they work.

For the security concern of auto-routes, this is actually a bigger concern in
Python than in Ruby just because of the different ways that they handle OO
stuff. In Python, everything is a public method. So, if Django just mapped
URLs to methods, there would be no way of hiding a method you didn't want
called. Ruby has the ability to make private and protected methods and Rails
only makes public methods available as actions (the private and protected ones
still being able to be called in their scope).

So, it isn't a great security concern in Rails since it's trivial to define
what is public and what isn't. Likewise, if one chooses, you can decide to map
all of the URLs explicitly like Django and turn off the default
:controller/:action/:id route. So, Rails offers both ways.

Just as a note about Python: Django could just auto-map URLs to any method not
starting with an underscore (the convention used in Python to say, this is
kinda private even though Python will let you use it). Or there could be a
kwarg (keyword argument) in the method signature that Django looked at.
Anyway, there are ways around the fact that the Python language doesn't have
explicitly private methods. Django's convention (like Python's) is just that
explicit is better.

~~~
ubernostrum
"If people don't agree on the IF statement, they just don't agree on it."

Pretty much. And while individual cases can be argued, I think the general
goal of keeping program logic out of templates is a good one.

"For the security concern of auto-routes, this is actually a bigger concern in
Python than in Ruby just because of the different ways that they handle OO
stuff. In Python, everything is a public method. So, if Django just mapped
URLs to methods, there would be no way of hiding a method you didn't want
called."

Actually, what I'm thinking of is a case where you might have a single
application running on multiple sites, and -- for security reasons -- there'd
be some views that you wouldn't want exposed on one or more of those sites.
Forgetting to "un-map" even a single URL could lead to major problems (and,
since an auto-mapping system can, in theory, locate anything that's on the
import path, the risk seems to me to be a bit too much to accept just for the
convenience of occasional automatic URLs).

------
carbon8
_"Python vs. Ruby (Perl’s Ugly Sister)...This makes the Ruby syntax look like
someone emptied all the symbols from the keyboard into a shotgun and shot them
into your face."_

It's amazing watching the python web development community develop, nurture
and encourage so much mindless trolling. It has turned reddit completely
septic and now this garbage is on the front page here? Sigh.

~~~
tvon
"It's amazing watching the python web development community develop, nurture
and encourage so much mindless trolling."

Where are you seeing this? There are a fair number of Django and Python posts
on HN and this is the first I've read that I can remember any such trolling.

~~~
carbon8
_"on HN"_

Indeed, but even here it has been increasing. This made it to #2 within a half
hour of posting. Even watching this thread you can see people driving through
down modding even mdasen's post. Another recently popular blatant nonsensical
anti-rails/pro-django troll that comes to mind was the "Magic Sucks, Django
Rocks!" submission: <http://news.ycombinator.com/item?id=596833>

------
mahmud
Django vs Rails is like Old Navy vs the GAP.

Lisp web development is haute couture; sure, we might need to travel to the
ends of the world to fetch silk, velvet, safron and red dyes, feathers of
griffins, and we might need to raise our own albino beavers and translucent-
neon chimps to harvest for leather, but the end result is a gallant style fit
for a high princely court. (It might also involve a slight invasion of
neighboring states to capture their sartorial secrets.)

~~~
tptacek
"Lisp web development is haute couture"

ie, not actually intended for people to use.

Well played!

~~~
mahmud
It's up to you to take the red pill, or take the chill pill ;-)

------
look_lookatme
What does this article say that hasn't been said before? This stuff just isn't
interesting anymore.

~~~
fiaz
What this article says to me is:

1) there exists multiple frameworks that are independently excellent

2) some of the best minds in both worlds have nothing better to do other than
to take sides in meaningless discussions

~~~
stcredzero
_some of the best minds in both worlds have nothing better to do other than to
take sides in meaningless discussions_

That and some unsubtle flirting with language wars and trolly word choice is
exploitable for linkbait and HN karma.

------
petercooper
Sorry Pythonistas, but whenever you say that having "only one way" to do
something is a _good_ point (and many have said this), you sound like
religious nutjobs.

There's more than one good and obvious way to do anything worth doing, be it
giving birth, building a bridge, adding two numbers together, or developing
algorithms in a programming language.

I like Python on many levels - particularly the indentation - but the
religious-ness of the philosophy and language design is off-putting in so many
other ways.

~~~
chairface
Well, for me, it is a good point. For some reason it's just much easier for me
to remember a particular language's way of doing something when there's only
one way.

Also, I'm a little obsessive about my code consistency, so I dislike having to
remember that I've been using Array#size instead of Array#length, for
instance.

Now, these are obviously not necessarily applicable to anyone else. However, I
do feel like I can say that having only one way to do simple things is a plus,
without being a "religious nutjob". Which is kind of inflammatory of you to
say, by the way.

~~~
petercooper
There's a big difference between a person stating an opinion or a preference,
as you have, and a community standard being defined and defended to the hilt.
The first is choice; the second is religion.

People who blindly defend Python's wacky standards as some sort of community
issue are the religious nutjobs, not people like you who merely have a
personal preference.

So, no, you're not necessarily a religious nutjob. But, yes, it was meant to
inflammatory; people who blindly defend groupthink deserve to have their cages
shaken from time to time.

------
sreque
It is fairly easy to avoid symbol soup in ruby.

First, don't use global variables. I'm perfectly OK with global variables
sticking out and looking ugly.

Second, use the English module packaged with Ruby if you find yourself using
Perl-like special global variables a lot. I very rarely use them and so never
need to use the module.

Finally, use accessor methods to work with instance variables instead of
accessing them directly. This also makes it easier to add logic to handle your
instance variables without having to rewrite or break any code.

If you follow these three steps alone, you will have about the same amount of
symbol soup as you would in python, which is almost none.

(By the way, I am also a fan of both python and ruby and think they are both
great languages).

------
richcollins
> the developer is forced to keep business logic and complex constructs
> separate from the markup

Nothing I like better than having options taken away without any upside!

------
heycarsten
There are many ways of doing the same thing in Ruby? I guess that's true to
some extent but I'm not really sure why it's a problem?

['cat', 'dog'] %w[ cat dog ]

Although these are not technically the same ... lambda { } proc { } Proc.new {
}

string.match(/regex/) string =~ /regex/

object.is_a?(Thing) Thing === object

hash.merge!(hash) hash.update(hash)

Anyways, I'm not a Python programmer, but I can say (with regards to Ruby)
when you are used to the language it feels right.

Why can't we just all get along and not troll the shit out of each-other?

