Friday, 3 December 2010

Django

Last night at GothPy we had a play with Django, a web application framework for Python. I'm fairly familiar with Rails, so it was interesting to see a different take on solving the same kinds of problems.

I downloaded Django for the first time when preparing for the meeting, and spent about a day going through the tutorial and trying stuff out. At the meeting were a few people who have used Django before, notably Mikko Hellsing, who has worked with it daily for several years.

It was so much easier learning the tool from people who knew it than by reading the documentation. Constant code review and real time answering of questions is just brilliant for learning.

At the meeting we decided to implement a very very simple web application, similar to the one that Johannes Brodwall performed as a Kata at XP2010 together with Ivar Nilsen. He calls it "Java EE Spike Kata" since he does it in Java with no particular web frameworks, just what comes with Java. (There is a video of him doing it on his blog, and sample solution here on github).

I thought we should be able to implement the same little application in any web framework, and it might be interesting to see differences, so I though we should try doing it in Django. It just involves two pages. One page "Add User" which lets you create a new user and save it to the database, and another page "Search User" which lets you search for users, and presents results. So the scenario is to create a user, search for them, and see they are returned.

When I work on a problem in Rails I usually start with a Cucumber scenario for the feature, and I discovered there is a python version of Cucumber called Lettuce. We could have course have just used Cucumber with python, but given the big "WARNING - Experimental" notice Aslak wrote on this page, I thought we could give Lettuce a try.

So at the meeting we all worked together with one laptop and a projector, (me at the keyboard), and we started with a Lettuce scenario. We implemented step definitions using Django's test Client, which is a kind of headless browser that understands how to instrument a Django application. Then we spent a couple of hours writing Django code together until the scenario was all green.

The code we ended up with isn't much to write home about, but I've put it up on github here.

What we learned from this exercise
Of course since I know Rails much better, I found it interesting to compare the two web frameworks. Django seems similar in many ways. It was dead easy to get up and running, it gives you a basic structure for your code, and separates the model from the presentation layer.

The O-R mapping looks quite similar to ActiveRecord in the way you declare model classes backed by tables in the db. The presentation layer seems to have a different philosophy from Rails though. The html view part is rather loosely coupled to your application, and doesn't allow you to embed real python code in it, just basic control structures.

You hook up the html to the controller code using url regular expression matching. I was a little confused about exactly how was supposed to work, since what I considered controller code was put in a file called "views.py". Most of the code we wrote ended up in here, and I feel a bit unhappy with it. It seems to be a mixture of stuff at all levels of abstraction. The Django Form objects we used seemed quite powerful though, and reduced the amount of code we had to write.

The biggest difference I noticed compared with Rails was how explicit Python is about where stuff comes from. You always have to declaratively import or pass stuff before you can use it, so I found it straightforward to follow the connections and work out which code was executed and where it came from. I think that is because of Python's philosophy of strict namespaces, which Ruby doesn't have so much of.

I also liked the way Django encourages you to structure a larger web application into a lot of independent smaller ones, and lets you include and re-use other people's small apps. Rails has plugins too of course, but I thought Django's way made it seem very natural to contribute and re-use code.

Comparing Lettuce to Cucumber, they look almost the same, (by design). One small difference I found was that Cucumber step definitions don't care if you write "Given", "When" or "Then" in front of them, whereas Lettuce did. So I had steps like this:

Then I should see "results found"
And I should see "Name"

where the first step passed and the second step was reported as unimplemented by Lettuce. So Lettuce need a little more work to be really usable.

I was also pretty disappointed by the Django test client for implementing test steps. It seemed to interact with pages at an abstraction layer lower than I am used to - at the level of making post and get requests and parsing html as a dom. I missed Capybara and its DSL for interacting with web pages. I couldn't find any equivalent. I probably should have turned to Selenium directly, but since we had no client side javascript it seemed overkill. (Francisco Souza has written about using Lettuce with Selenium compared with the Django test client here).

When it comes to unit-level testing, Django provides an extension to the normal unittest tool that comes with python (unittest was originally based on JUnit). We didn't do much with it at the session, and it seemed to work fine. It's nothing like RSpec though, and I miss that expressiveness and structure for my tests whenever I work in Python.

Overall
All in all it was fun to look at Django with a group and to get some really helpful comments and insights from people who know it far better than I do. The Kata we chose seemed to work ok, but I should really do it again in Rails since I spent the whole time comparing Django with Rails in my head, not Django with Johannes' Java code :-)

My conclusions are basically that Django looks like a good alternative to Rails. It would take time to learn, and surely has strengths and weaknesses I can't really evaluate from one short session looking at it. However, I'd fairly sure I'd have to do some work improving the testing tools if I was going to be happy working with it for real.

2 comments:

  1. Wish I had been there! I've been using Django for the work I'm doing, and I have mixed feelings. What you might want to do is look at some package which used Django well, and see how they implement things. For example, I've been working with OSQA, and that code is very clean and well written. I've learned a bit about how to write web apps that way.

    I can answer some of the questions you've had about Django. As far as I can tell, "views.py" is simply the wrong word. http://www.linuxjournal.com/article/9738 says "both Django and Rails use an approach that is best known as MVC (model, view, controller) developed in the Smalltalk community but adopted by many other languages and frameworks since then. These terms, used verbatim in the Rails world, are called models, templates and views in the Django world, and they form the bulk of a Django-based site." And in http://translated.by/you/the-django-book-2-0/original/ "# views.py (the business logic)."

    Here's another reference from "Ajax: the definitive guide": "When I say 'loosely based MVC' I am echoing what Django's developers stated: that they "feel like the design of Django had to feel right, and [they] will not be bound to a particular design pattern." As a result, the controller in a typical MVC framework is the "view" in Django, and the view is instead called the "template." "

    DJango's way of using small apps was a bit of a revelation. After using it I really like how you can have an installed Python module, independent of the main web system, which can provide app services, and all you need to make it work is a couple of lines.

    They made a design choice to exclude the ability to embed Python code in a template. Here's a recent post on why some people like "dumb" template languages: http://pydanny.blogspot.com/2010/12/stupid-template-languages.html . There were a number of blog posts responding to it.

    I've not used the Django test client but the documentation suggests it probably wasn't the right tool.

    I'm have to investigate the testing options for me now since I have written client-side Javascript which talks to a embedded Java app and does an AJAX call to the server to put things into the database and the filesystem. I think I'll try Selenium.

    ReplyDelete
  2. Thanks for all that information, Andrew, I'm sorry you couldn't make the meeting!

    I hope you have some success with Selenium. It's the best thing I know of for testing webapps with client side javascript, but it's not that great really. I've written code it's been unable to test :-(

    I look forward to you telling us about your experiences at a future GothPy meeting!

    ReplyDelete