CSC/ECE 517 Fall 2010/ch3 3a LG

From Expertiza_Wiki
Jump to navigation Jump to search

Web Application Frameworks

Introduction

What's a web application framework? What is a framework? A framework is an underlying structure [1], and a web application framework is just that. Commonly web application frameworks are associated with agile/fast development; this characteristic is attached to the Model-View-Controller (MVC) architectural pattern. MVC is, by far, the most popular pattern used in web application frameworks. According to Wikipedia [2] content management systems (CMS) are also considered web application frameworks, but we will leave those aside.

Before web application frameworks, websites that dealt with dynamic content were often written from scratch and a page at a time, each page was responsible for handling its own requests. Websites were rigid and code was repeated everywhere (SQL operations, parameter handling, etc.). One step backwards, websites didn't include dynamic content at all and were written entirely in static HTML files, leaving the responsibility of updating the site to developers.

In this chapter we will study four web application frameworks. This chapter was written in a “new web application frameworks for Ruby on Rails developers” way, showing Rails' way first and comparing the rest of the web frameworks with it. However its knowledge is not necessary to comprehend the topics being discussed.

The first section will present the frameworks being examined, a brief description and a list of key points they show at their websites. Immediately after we'll examine the models, view and controllers of the Cookbook application written in all four web frameworks.

Another Gang of Four… Not Really! Four Web Application Frameworks

I guess they could hang together and have fun, but they usually don't. This is another war, just like the one browsers, operating systems and, more recently, mobile operating systems fight. You either love it, or hate it, but we'll try to give each some love.

Ruby on Rails

Website rubyonrails.org
Latest Version 3.0
Developers Rails Core Team
Slogan Web development that doesn't hurt
Logo Logo can be found in http://commons.wikimedia.org/wiki/File:Ruby_on_Rails_logo.jpg

Ruby on Rails is the oldest of the four web applications frameworks presented; it was initially released in 2004 [3], the rest were released anytime in 2005 [4], [5], [6]. It's so popular that CakePHP was admittedly inspired on it ([7]) and many other web frameworks were also inspired by its success. Rails openly follow the convention over configuration (COC) paradigm as one of its main tenets [3]. Other languages don't mention this, but as far as I'm concerned they all follow this paradigm; it's the COC paradigm that allows writing entire applications in few lines of code.

Key points

Listed as the “basic tenets of Ruby on Rails” [3].

  • Convention over Configuration
  • Don't Repeat Yourself (DRY)
  • Fat Model, Skinny Controller
  • REST Interface
  • Write Good Test
  • Automate tasks

Django

Website www.djangoproject.com
Latest Version 1.2.3
Owners and Distributors Django Software Foundation
Slogan The Web framework for perfectionists with deadlines
Logo

Django is a “high-level [5]” web application framework written in Python. It follows the MVC architectural pattern and focuses on automating and adhering to the DRY principle. It was conceived in an online-news operation to handle two challenges: intensive deadlines and “stringent requirements of the experienced Web Developers who wrote it. [5]

One of the big things in Django is its “automatic admin interface.” Other frameworks can achieve this by including third party components/plugins, but the fact that Django includes it by default is a plus. Authentication and authorization, using access control list (ACL), are added to your application, almost without intervention from the developer.

Key points

Listed in an untitled list on their website [5].

  • Object-relational mapper (ORM)
  • Automatic admin interface
  • Elegant URL design
  • Template System
  • Cache System
  • Internationalization

CakePHP

Website cakephp.org
Latest Version 1.3.4
Releaser CakePHP Software Foundation, Inc
Logo

CakePHP is a “rapid [4]” development framework written in PHP. It uses the design patterns MVC and ORM. As stated before, CakePHP was inspired on the success of Ruby on Rails [7]. One thing not mentioned on the “hot features” is that CakePHP supports dynamic scaffolding [7]. Rails originally included this feature, but as for Rails 2.0 dynamic scaffolding is no longer supported [3]. Dynamic scaffolding allows the user to test its Create, Read, Updated, and Delete (CRUD) functions by adding one line of code in their controller:

var $scaffold;

Its importance relies on allowing the user to test relations and validations on the models before generating the code on the controller (static scaffolding) and that the code generated will take into consideration the changes made to the models during the dynamic scaffolding phase.

Key points

Listed as “Hot Features” on [4].

  • No configuration
  • Extremely Simple
  • Active, Friendly Community
  • Flexible License
  • Clean IP
  • Best Practices
  • Object Oriented

Catalyst

Website www.catalystframework.org
Latest Version 5.80029
Slogan The elegant MVC framework
Logo Logo can be found in http://commons.wikimedia.org/wiki/File:Catalyst_logo3.png

Catalyst is a web application framework written in PERL. It was done with the DRY principle in mind and reuses many PERL modules that performed well on the past.

Key points

Or “What makes Catalyst special?” as they like to call them [6].

  • Keep it Simple, Stupid
  • Don't Repeat Yourself
  • There is More Than One Way To Do It
  • Plugins
  • A self-restarting development server (it self-restarts when source code is changed)

Model-View-Controller

In this section we'll examine each web application framework from a model, view, and controller perspective. Excerpts of the “Cookbook” application will be shown for each element on each framework. To keep a better flow of the lecture controllers will be presented before views, since in all frameworks variables needed by views are set there. We'll discuss code readability, briefness and if they do what they are supposed to do.

Models

The model “Recipe” is shown, with its association to “Category” and a few validations. All frameworks try to keep the model fat and a slim controller, by adding the validations on the model.

Ruby on Rails

Rails does a good job making its code readable, apart from the to_s method. Defaults errors are shown if a validation fails and a dynamic variable is created to hold is parent Category.

This model has no intervention on defining the table on the database. To be fair with Django, additional to this class, the CreateRecipes class (db/migrate) is shown. However that code was written almost entirely automatically by the generator so one could argue that it's not necessarily a fair comparison. The command “rake db:migrate” creates the database on the table based on the contents of the db/migrate folder.

class Recipe < ActiveRecord::Base
	belongs_to :category
	validates_length_of :title, :maximum => 255
	validates_length_of :description, :maximum => 255

	def to_s
		self.login
	end
end

class CreateRecipes < ActiveRecord::Migration
	def self.up
		create_table :recipes do |t|
			t.string :title, :limit => 255
			t.string :description, :limit => 255
			t.text :instructions
			t.integer :category_id
			t.timestamps
		end
	end

	def self.down
		drop_table :recipes
	end
end

Django

Being a neophyte in Python this code looked strange at first sight. While writing the code I had as many indentation errors as semicolons I tried to place in Ruby when I first learned it. The code is not as readable as in Rails, but it's short. Running the command “python manage.py syncdb” synchronizes the database structure with the contents of this file. Related objects and validations are also created. All models are defined in a single file called models.py.

class Recipe(models.Model):
	title = models.CharField(max_length=255)
	description = models.CharField(max_length=255)
	instructions = models.TextField()
	category = models.ForeignKey(Category)
	created = models.DateField(auto_now_add=True)
	updated = models.DateField(auto_now=True)
	
	def __unicode__(self):
		return self.title

CakePHP

CakePHP might look a lot more like Java or other widely known static languages (it's still a dynamically typed language, I'm comparing just in the syntax), just add “$” to each variable an treat arrays as both an Array and a HashTable. When putting the code side by side with Django and Ruby on Rails it looks verbosely. On top of that, there is no built-in database migration to keep a definition of the database inside the project. This is compensated by many components available at the Bakery [8].

<?php
class Recipe extends AppModel {
	var $name = 'Recipe';
	var $belongsTo = 'Category';
	var $displayField = 'title';
	var $validate = array(
		'title' => array(
			'rule' => 'notEmpty',
			'rule' => array('maxLength', 255),
		),
		'description' => array(
			'rule' => 'notEmpty',
			'rule' => array('maxLength', 255),
		)
	);
}
?>

Catalyst

The tables need to be created directly on the database before generating the model. This model is generated by running the following script [9].

script/myapp_create.pl model DB DBIC::Schema MyApp::Schema \
		create=static dbi:SQLite:myapp.db \
		on_connect_do="PRAGMA foreign_keys = ON"

The script reads the database and generates the following code. Neither the script, nor the code is readable. It verboseness is extravagant, which I think is a result of PERL's age.

use strict;
use warnings;

use base 'DBIx::Class';

__PACKAGE__->load_components("InflateColumn::DateTime", "Core");
__PACKAGE__->table("recipes");
__PACKAGE__->add_columns(
	"id",
	{ data_type => "INTEGER", is_nullable => 0, size => undef },
	"title",
	{ data_type => "VARCHAR", is_nullable => 0, size => 255 },
	"description",
	{ data_type => "VARCHAR", is_nullable => 0, size => 255 },
	"instructions",
	{ data_type => "text", is_nullable => 0 },
	"created_at",
	{ data_type => "DATETIME", is_nullable => 0 },
	"updated_at",
	{ data_type => "DATETIME", is_nullable => 0 },
);
__PACKAGE__->set_primary_key("id");

__PACKAGE__->belongs_to(
 );

1;

Controllers

To keep it short, we'll show just one method of the controller: index/list, which list all recipe objects and sends that information to the corresponding view.

Ruby on Rails

Rails does a good job keeping the controller slim. The convention over configuration is also shown here were format.html renders the index.html.erb file by default. The method responds to the GET action under /recipes because of pre-define routes created when scaffolding.

# GET /recipes
def index
	@recipes = Recipe.all
	
	respond_to do |format|
		format.html
	end
end

Django

Just because Rails did a good job doesn't mean that Django wouldn't. They actually have a package named “shortcuts” which holds many DRY-oriented functions that perform common tasks. Something unique in Django is that this functional code is actually defined in the views.py file. And what we know as views is defined in templates. Just as in models, all controller functions are defined in a single file, keeping the file count small.

from django.shortcuts import render_to_response, … …

def index(request): recipes = Recipe.objects.all() return render_to_response('cookbook/recipe.html', {'recipes': recipes})

CakePHP

Using convention over configuration in its minimalist expression CakePHP is a winner. Code is short and completely readable. The variable $posts is made available to the view defined in /recipes/index.ctp

function index() {
	$this->set('recipes', $this->Recipe->find('all'));
}

Catalyst

I must confess that I'm being rough with Catalyst. I left the comments because the code is unreadable and the phrase “glue together” (code from official tutorial) describes exactly what I feel for this framework. The actual code's length is pretty short.

=head2 list Fetch all recipes and pass to recipes/list.tt2 in stash to be shown =cut

sub list :Local { # Retrieve the usual Perl OO '$self' for this object. $c is the # Catalyst 'Context' that's used to 'glue together' the various # components that make up the application my ($self, $c) = @_;

# Retrieve all of the recipe records as recipe model objects and # store in the stash where they can be accessed by the TT template $c->stash(recipes => [$c->model('DB::Recipe')->all]);

# Set the TT template to use. $c->stash(template => 'recipes/list.tt2'); }

Views

All views/templates are very similar. They all have a hierarchy using different keywords: extends, render, include, etc., but at the end they all serve a similar purpose.

Of all CakePHP had the must verbosely way of echoing (print in PHP terms) the values of properties inside the object. Django differs from the rest in the place they store their templates, as they call them. This is usually a folder outside of the project specified in the settings.py file.

Ruby on Rails

<h1>Listing Recipes</h1>
<table>
	<tr>
		<th>Category</th>
		<th>Title</th>
		<th>Description</th>
		<th>Instructions</th>
	</tr>
<% @recipes.each do |recipe| %>
	<tr>
		<td><%= link_to recipe.category.name, categories_path(recipe.category) %></td>
		<td><%= recipe.title %></td>
		<td><%= recipe.description %></td>
		<td><%= recipe.instructions %></td>
	</tr>
<% end %>
</table>

Django

{% extends "base_generic.html" %}
{% block title %}Listing Recipes{% endblock %}
{% block content %}
<table>
	<tr>
		<th>Category</th>
		<th>Title</th>
		<th>Description</th>
		<th>Instructions</th>
	</tr>
{% for recipe in recipe_list %}
	<tr>
		<td>{{ recipe.title }}</td>
		<td><a href="/cookbook/category/{{ recipe.category.id }}/">{{ recipe.category.name }}</a></td>
		<td>{{ recipe.description }}</td>
		<td>{{ recipe.instructions }}</td>
	</tr>
{% endfor %}
</table>
{% endblock %}

CakePHP

<h1>Listing Recipes</h1>
<table>
	<tr>
		<th>Category</th>
		<th>Title</th>
		<th>Description</th>
		<th>Instructions</th>
	</tr>
<?php foreach ($recipes as $recipe): ?>
	<tr>
		<td><?php echo $this->Html->link($recipe['Category']['name'], array('controller' => 'categories', 'action' => 'view', $recipe['Category']['id'])); ?></td>
		<td><?php echo $recipe['Recipe']['title']; ?></td>
		<td><?php echo $recipe['Recipe']['description']; ?></td>
		<td><?php echo $recipe['Recipe']['instructions']; ?></td>
	</tr>
<?php endforeach; ?>
</table>

Catalyst

[% META title = 'Listing Recipes' -%]
<table>
	<tr>
		<th>Category</th>
		<th>Title</th>
		<th>Description</th>
		<th>Instructions</th>
	</tr>
[% FOREACH recipe IN recipes -%]
	<tr>
		<td>[% recipe.title %]</td>
		<td><a href="[% uri_for('/categories/')_ recipe.category_id %]">[% recipe.category_name %]
		</a></td>
		<td>[% recipe.description %]</td>
	<td>[% recipe.instructions %]</td>
	</tr>
[% END -%]
</table>

References

[1] Princeton University. (2010, October) WordNet. [Online]. http://wordnetweb.princeton.edu/perl/webwn?s=framework

[2] Wikipedia. (2010, October) Wikipedia - Web application framework. [Online]. http://en.wikipedia.org/wiki/Web_application_framework

[3] Rails Core Team. (2010, October) Rails Wiki. [Online]. http://wiki.rubyonrails.org/

[4] CakePHP Software Foundation. (2010, August) CakePHP. [Online]. http://cakephp.org

[5] Django Software Foundation. (2010, October) Django. [Online]. http://www.djangoproject.com

[6] (2010, October) Catalyst Web Framework. [Online]. http://www.catalystframework.org/

[7] CakePHP Software Foundation. (2010, October) The Cookbook. [Online]. http://book.cakephp.org/

[8] Cake Software Foundation. (2010, October) The Bakery. [Online]. http://bakery.cakephp.org/

[9] (2010, October) Catalyst Manual. [Online]. http://search.cpan.org/~hkclark/Catalyst-Manual-5.8004/lib/Catalyst/Manual/Tutorial.pod