100
A Rails/Django Comparison by Ben Askins and Alan Green This work is licensed under the Creative Commons Attribution-NonCommercial- ShareAlike 2.5 License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/2.5/ or send a letter to Creative Commons, 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA. The original version of this presentation is available at http://3columns.net/habitual/docs/Pres2.odp

Rails/Django Comparison

Embed Size (px)

DESCRIPTION

Discussed: support for model and schema evolution, internationalisation, designer friendly templates, third party plugin support, javascript support and coding flavour. Source:http://www.bright-green.com/blog/2006_12_14/rails_vs_django_paper_and.html

Citation preview

Page 1: Rails/Django Comparison

A Rails/Django Comparisonby Ben Askins and Alan Green

This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 2.5 License. To view a copy of this license, visit

http://creativecommons.org/licenses/by-nc-sa/2.5/or send a letter to Creative Commons, 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA.

The original version of this presentation is available at http://3columns.net/habitual/docs/Pres2.odp

Page 2: Rails/Django Comparison

Django Rails vs.

Page 3: Rails/Django Comparison
Page 4: Rails/Django Comparison
Page 5: Rails/Django Comparison
Page 6: Rails/Django Comparison

We wrote the same application twice

Page 7: Rails/Django Comparison
Page 8: Rails/Django Comparison
Page 9: Rails/Django Comparison

TagBook

Reading

Reader n m

nn

11

Page 10: Rails/Django Comparison
Page 11: Rails/Django Comparison
Page 12: Rails/Django Comparison

Developer skill level:● Not identical● Too advanced to be called ‘beginners’● Insufficiently advanced to be ‘typical’

Development environments different:● New Mac vs Old Windows laptop● Central Coast vs Cityrail

Part-time development – start-stop effect and gaps between sessions

Didn’t consider:● Performance● Deployment● Maintainability● Enterprise-friendliness

Unrepresentative example application:● Too few pages● No Atom/RSS feeds● No public data entry

Development practices:● Didn’t do it the “best way”● Older versions of Rails and Django● Didn’t use this or that helpful third party feature

This was just a single trial. Really need:● Multiple developers● Multiple applications● Multiple environments

“Multiple” means “statistically significant”

LOC and time-to-implement measurements are stupid:

● Not transferable to other developers● Only rough indicator of complexity

Page 13: Rails/Django Comparison
Page 14: Rails/Django Comparison
Page 15: Rails/Django Comparison
Page 16: Rails/Django Comparison

Some Data

Page 17: Rails/Django Comparison

Plan

Page 18: Rails/Django Comparison

$1 000 000

Page 19: Rails/Django Comparison

US$1 000 000

Page 20: Rails/Django Comparison

Time to Implement

Page 21: Rails/Django Comparison

Initial Expectations

“This’ll be easy I’ll whip it up in a weekend.”

“You don’t understand the power of the built-in

admin application.”

Page 22: Rails/Django Comparison

Rails  Django 0.00

5.00

10.00

15.00

20.00

25.00

30.00

Hours to Implement

HTML Prototype

Page 23: Rails/Django Comparison

Rails  Django 0.00

5.00

10.00

15.00

20.00

25.00

30.00

Hours to Implement

Develop Test data HTML Prototype

Page 24: Rails/Django Comparison

Rails  Django 0.00

5.00

10.00

15.00

20.00

25.00

30.00

Hours to Implement

Project set up Develop Test data HTML Prototype

Page 25: Rails/Django Comparison

Rails  Django 0.00

5.00

10.00

15.00

20.00

25.00

30.00

Hours to Implement

Models Project set up Develop Test data HTML Prototype

Page 26: Rails/Django Comparison

TagBook

Reading

Reader n m

nn

11

Page 27: Rails/Django Comparison

Rails  Django 0.00

5.00

10.00

15.00

20.00

25.00

30.00

Hours to Implement

Models Project set up Develop Test data HTML Prototype

Page 28: Rails/Django Comparison

Rails  Django 0.00

5.00

10.00

15.00

20.00

25.00

30.00

Hours to Implement

Home page Models Project set up Develop Test data HTML Prototype

Page 29: Rails/Django Comparison

Rails  Django 0.00

5.00

10.00

15.00

20.00

25.00

30.00

Hours to Implement

Basic pages Home page Models Project set up Develop Test data HTML Prototype

Page 30: Rails/Django Comparison

Rails  Django 0.00

5.00

10.00

15.00

20.00

25.00

30.00

Hours to Implement

Admin pages Basic pages Home page Models Project set up Develop Test data HTML Prototype

Page 31: Rails/Django Comparison

Rails  Django 0.00

5.00

10.00

15.00

20.00

25.00

30.00

Hours to Implement

Amazon interface Admin pages Basic pages Home page Models Project set up Develop Test data HTML Prototype

Page 32: Rails/Django Comparison

Rails  Django 0.00

5.00

10.00

15.00

20.00

25.00

30.00

Hours to Implement

Data loading code Amazon interface Admin pages Basic pages Home page Models Project set up Develop Test data HTML Prototype

Page 33: Rails/Django Comparison

Rails  Django 0.00

5.00

10.00

15.00

20.00

25.00

30.00

Hours to Implement

Test, tidy Data loading code Amazon interface Admin pages Basic pages Home page Models Project set up Develop Test data HTML Prototype

Page 34: Rails/Django Comparison

Rails  Django 0.00

5.00

10.00

15.00

20.00

25.00

30.00

Hours to Implement

Test, tidy Data loading code Amazon interface Admin pages Basic pages Home page Models Project set up Develop Test data HTML Prototype

26:46

16:36

Page 35: Rails/Django Comparison

Rails  Django 0.00

5.00

10.00

15.00

20.00

25.00

30.00

Hours to Implement

Test, tidy Data loading code Amazon interface Admin pages Basic pages Home page Models Project set up Develop Test data HTML Prototype

Admin PagesAdmin Pages26:46

16:36

Page 36: Rails/Django Comparison

Rails  Django 0.00

5.00

10.00

15.00

20.00

25.00

30.00

Hours to Implement - without Admin

Test, tidy Data loading code Amazon interface Basic pages Home page Models Project set up Develop Test data HTML Prototype

18:21

15:39

Page 37: Rails/Django Comparison

Lines of Code

Page 38: Rails/Django Comparison

Rails Django0

100

200

300

400

500

600

700

800

Lines of Code

Model

Page 39: Rails/Django Comparison

Rails Django0

100

200

300

400

500

600

700

800

Lines of Code

View/ControllerModel

Page 40: Rails/Django Comparison

Rails Django0

100

200

300

400

500

600

700

800

Lines of Code

YAML data loading View/ControllerModel

Page 41: Rails/Django Comparison

readers.yml

# Reader test dataBen: id: 1 username: benj72 fullname: Ben Askins bio: Eats books for breakfastAlan: id: 2 username: agreen fullname: Alan Green bio: Fond of snakesFred: id: 3 username: fred fullname: Fred Wilkins bio: Loves a good romantic thriller

Page 42: Rails/Django Comparison

Rails Django0

100

200

300

400

500

600

700

800

Lines of Code

YAML data loading View/ControllerModel

Page 43: Rails/Django Comparison

Rails Django0

100

200

300

400

500

600

700

800

Lines of Code

Authentication YAML data loading View/ControllerModel

Page 44: Rails/Django Comparison

Rails Django0

100

200

300

400

500

600

700

800

Lines of Code

Schema Migration Authentication YAML data loading View/ControllerModel

Page 45: Rails/Django Comparison

Rails Django0

100

200

300

400

500

600

700

800

Lines of Code

HTML Helpers/ Template tags Schema Migration Authentication YAML data loading View/ControllerModel

Page 46: Rails/Django Comparison

Rails Django0

100

200

300

400

500

600

700

800

Lines of Code

Templates HTML Helpers/ Template tags Schema Migration Authentication YAML data loading View/ControllerModel

Page 47: Rails/Django Comparison

● Hand-coded admin application

● Concise

● Quicker● Slightly less code

Page 48: Rails/Django Comparison

Database

Web Server

Routes View

Controller

Model

Browser

Database

Web Server

urls.py Template

View

Model

Browser

Rails Django

Page 49: Rails/Django Comparison

Database

Web Server

Routes View

Controller

Model

Browser

Database

Web Server

urls.py Template

View

Model

Browser

Rails Django

Page 50: Rails/Django Comparison

ActionController::Routing::Routes.draw do |map|

map.connect '', :controller => "home"

# restful resources map.resources :books do |books| books.resources :readings end map.resources :readers do |readers| readers.resources :reader_images end map.resources :tagsend

# Some imports herefrom hrproj.hr import views

urlpatterns = patterns('',

(r'^$', views.index),

(r'^readers/$', views.reader_list), (r'^tags/$', views.tag_list), (r'^books/$', views.book_list),

(r'^readers/(?P<username>.*)/$', views.reader_detail), (r'^tags/(?P<slug>.*)/$', views.tag_detail), (r'^books/(?P<slug>.*)/$', views.book_detail),)

URL Configuration

/books/hitchhikers-guide-to-the-galaxy

Page 51: Rails/Django Comparison

Database

Web Server

Routes View

Controller

Model

Browser

Database

Web Server

urls.py Template

View

Model

Browser

Rails Django

Page 52: Rails/Django Comparison

Controller / View Function

class BooksController < ApplicationController before_filter :find_book

def show @reading_paginator, @readings = paginate :readings, :conditions => ["book_id = ?", @book.id] end

private def find_book @book = Book.find_by_title(params[:id]) end

end

def book_detail(request, slug): book = get_object_or_404(Book, slug=slug) queryset = ReadingOccasion.objects \ .filter(book=book) \ .order_by('finished') return standard_view( request, queryset, 'book_detail.html', 'readingoccasion', book=book)

Page 53: Rails/Django Comparison

Database

Web Server

Routes View

Controller

Model

Browser

Database

Web Server

urls.py Template

View

Model

Browser

Rails Django

Page 54: Rails/Django Comparison

class ReadingOccasion(models.Model): reader = models.ForeignKey(Reader) book = models.ForeignKey(Book, edit_inline=models.STACKED,

num_in_admin=1) finished = models.DateField( core=True) reading_time = models.FloatField(

max_digits=5,decimal_places=2,

core=True, blank=True) notes = models.TextField(

maxlength=2000, blank=True)

class Reading < ActiveRecord::Base  belongs_to :book  belongs_to :readerend

Page 55: Rails/Django Comparison

class ReadingOccasion(models.Model): reader = models.ForeignKey(Reader) book = models.ForeignKey(Book, edit_inline=models.STACKED,

num_in_admin=1) finished = models.DateField( core=True) reading_time = models.FloatField(

max_digits=5,decimal_places=2,

core=True, blank=True) notes = models.TextField(

maxlength=2000, blank=True)

class Reading < ActiveRecord::Base  belongs_to :book  belongs_to :readerend

Page 56: Rails/Django Comparison

Schema evolution

Page 57: Rails/Django Comparison

class CreateReadings < ActiveRecord::Migration def self.up create_table :readings do |t| t.column "book_id", :integer t.column "reader_id", :integer t.column "date_read", :datetime t.column "reading_time", :integer t.column "notes", :text end end

def self.down drop_table :readings endend

Schema is Versioned

Page 58: Rails/Django Comparison

Django DB evolution

● Drop database tables● Re-create tables

manage.py syncdbpython yaml/load_data.py

● In production, you write migration DDL by hand

Page 59: Rails/Django Comparison

Database

Web Server

Routes View

Controller

Model

Browser

Database

Web Server

urls.py Template

View

Model

Browser

Rails Django

Page 60: Rails/Django Comparison
Page 61: Rails/Django Comparison

books/show.rhtml:<%= render :partial => 'readings/list', :locals => {:key_field => "Reader"} %>

readings/_list.rhtml:<tbody> <%= render :partial => 'readings/reading', :collection => @readings, :locals => {:key_field => key_field} %></tbody>

readings/_reading.rhtml:<tr> <td class="name_col"> <% if key_field == "Book" %> <%= link_to reading.book.title, book_url(reading.book) %> <% else %> <%= link_to reading.reader.fullname, reader_url(reading.reader) %> <% end %> </td> <td class="date_col"> <%= reading.date_read_for_display %> </td> <td class="num_col"> <%= reading.reading_time %> </td> <td><%= reading.notes %></td></tr>

book_detail.html:<tbody>{% for ro in readingoccasion_list %} <tr> <td class="name_col"> <a href="{{ ro.reader.get_absolute_url }}"> {{ ro.reader.name }} </a> </td> <td class="date_col"> {{ ro.finished|date:"j M Y" }} </td> <td class="num_col"> {{ ro.reading_time }} </td> <td>{% firstof ro.notes "-" %}</td> </tr>{% endfor %}</tbody>

View / Template

Page 62: Rails/Django Comparison

readers/show.rhtml:<%= render :partial => 'readings/list', :locals => { :key_field => "Book" } %>

reader_detail.html:<tbody>{% for ro in readingoccasion_list %} <tr> <td class="name_col"> <a href="{{ ro.book.get_absolute_url }}"> {{ ro.book.title }} </a> </td> <td class="date_col"> {{ ro.finished|date:"j M Y" }} </td> <td class="num_col"> {{ ro.reading_time }} </td> <td>{% firstof ro.notes "-" %}</td> </tr>{% endfor %}</tbody>

View / Template

Page 63: Rails/Django Comparison

And the other bits

Page 64: Rails/Django Comparison

Django Admin application

● Can save a lot of time● Good looking result● Does simple CRUD quite wellbut...● Only does simple CRUD● Only does simple relationships ● Security not fine-grained ● Not intended for public-facing pages

Page 65: Rails/Django Comparison

AJAX

page.visual_effect :fade, dom_id(@tag)page.replace_html “feedback”, “Tag Deleted”page.visual_effect :appear, “feedback”, :queue => :endpage.visual_effect :fade, “feedback”, :queue => :end

Page 66: Rails/Django Comparison

Rails Django

0123456789

1011

Books on Amazon

Page 67: Rails/Django Comparison

Ruby Ruby on Rails Python Django0

10

20

30

40

50

60

70

80

90

100

110

120

Jobs on seek.com.au

Page 68: Rails/Django Comparison

History

● Began Oct 2003● DHH

– in reaction to PHP● Extracted from

Basecamp● Released: July 2004● 1.0 shipped Dec 2005

– Latest is 1.1.6

● Began Fall 2003● Adrian and Simon

– “ditched” PHP● Extracted from

ljworld.com● Released: July 2005● 1.0 not yet shipped

– Latest is 0.95

Page 69: Rails/Django Comparison

Conclusion

Page 70: Rails/Django Comparison

Already using Rails?

Page 71: Rails/Django Comparison

Already using Rails?

Page 72: Rails/Django Comparison

Already using Django?

Page 73: Rails/Django Comparison

Already using Django?

Page 74: Rails/Django Comparison

Already know Ruby?

Page 75: Rails/Django Comparison

Already know Ruby?

Page 76: Rails/Django Comparison

Already know Python?

Page 77: Rails/Django Comparison

Already know Python?

Page 78: Rails/Django Comparison

Private admin pages?

Page 79: Rails/Django Comparison

Private admin pages?

Page 80: Rails/Django Comparison

Simple AJAX?

Page 81: Rails/Django Comparison

Simple AJAX?

Page 82: Rails/Django Comparison

Non-programming web designers?

Page 83: Rails/Django Comparison

Non-programming web designers?

Page 84: Rails/Django Comparison

Evolving Schema?

Page 85: Rails/Django Comparison

Evolving Schema?

Page 86: Rails/Django Comparison

Maturity

Page 87: Rails/Django Comparison

Maturity – product,community, and market

Page 88: Rails/Django Comparison

Maturity – product,community, and market

Page 89: Rails/Django Comparison

Concise or Explict?

Page 90: Rails/Django Comparison

Concise Explicit

Page 91: Rails/Django Comparison

Still can’t choose?

Page 92: Rails/Django Comparison

Thanks!

Page 93: Rails/Django Comparison

With thanks to

● Photos– Sad puppy:

http://www.flickr.com/photos/sookie/108356632/● Software

– David A. Wheeler’s Sloccount● http://www.dwheeler.com/sloccount/

– HTML Template by Andreas Viklund● All of the paper reviewers● Our bosses:

– Cirrus Technologies– Karen Askins

Page 94: Rails/Django Comparison

● “The Builders of Basecamp”– http://www.oreillynet.com/pub/a/network/2005/03/10/basecamp.html

● Snakes and Rubies presentation– http://video.google.com/videoplay?docid=2939556954580527226

● Django FAQ– http://www.djangoproject.com/documentation/faq/

Page 95: Rails/Django Comparison

Why Comparing?

Lots of interest in these two frameworks

Similar in some ways

Different in others

How to choose between them?

Page 96: Rails/Django Comparison
Page 97: Rails/Django Comparison

This is some Ruby code This is some Python code

Page 98: Rails/Django Comparison

Bonus Material

Page 99: Rails/Django Comparison

def standard_view(request, queryset, template_name, template_object_name, **extra_context): """ Wrapper around the object_list generic view. """ return object_list(request, queryset=queryset, allow_empty=True, template_name=template_name, template_object_name=template_object_name, page=get_page(request), paginate_by=PAGE_SIZE, extra_context=extra_context)

def get_page(request): """ Determines the current page number. """ return int(request.GET.get('page', 1))

standard_view

Page 100: Rails/Django Comparison

Rails  Django 0.00

5.00

10.00

15.00

20.00

25.00

30.00

Hours to Implement

Test, tidy Data loading code Amazon interface Admin pages Basic pages Home page Models Project set up Develop Test data HTML Prototype

20:40

10:30