Thursday, December 30, 2010

Review of Crafting Rails Applications, by José Valim

José Valim is one of the newest members of the Rails core team. Apart from this he has also developed some good gems, Devise, Responders, and SimpleForm, that I use for almost every project.

And now he has written a book, a really good book, about advanced Rails programming techniques, called Crafting Rails Applications.

The book is only 180 pages long, and contains 7 chapters. I wish more books was this thin. The books is written in a clear concise way. José's lightweight test-driven approach clearly introduces every problem it intends to solve, and then solves the problem by introducing a new concept in the Rails framework. Most of the solutions are only a few lines of code, showing the power of Rails and also showing the power of having intimate knowledge of the framework. By hooking into the framework at appropriate places, José is able to provide elegant solutions to a range of problems.

I highly recommend the book to anyone interested in Rails.

If this was an ordinary book, this review could have ended here, but since the book is full of things I really wanted to know but didn't take the time to learn I decided to internalize them by describing parts of the book in my own words.

Chapter 1, Creating our own renderer

In this chapter we learn how to add a new renderer Rails. We add a renderer that handles generating PDF files with Prawn, allowing us to write code that looks like this.

class HomeController < ApplicationController 
  def index
    respond_to do |format| 
      format.html
      # This is the new capability, pdf rendering.
      format.pdf { render :pdf => "contents" }
    end 
  end
end

To allow the following we first have to register pdf as a mime type. We can do this with:

require "action_controller"
# Register a new mime type
Mime::Type.register "application/pdf", :pdf

# Registering the type allows us to write
respond_to do |format|
  format.pdf
end

With that out of the way all we have to do is to register a renderer, that will handle the actual rendering of the registered mime type. This is done with:

require "prawn" 

# Adds a new renderer to ActionController.Renderers
ActionController::Renderers.add :pdf do |filename, options|
  pdf = Prawn::Document.new pdf.text render_to_string(options) 
  send_data(pdf.render, :filename => "#{filename}.pdf",
      :type => "application/pdf", :disposition => "attachment")
end

This is all that is needed to add a rendering of a new type to Rails. José also goes into details about other points of interest where the rendering stack can be customized.

Chapter 2, Easy models with Active Model

Active Model is a Rails module that abstracts common behavior needed by different kinds om models such as Active Record, Active Resource and third party modules like Mongoid. Apart from giving developers of new models utility functionality. Active Model also provides tests for being Active Model compliant. To be compliant means to play well with the Rails view and controllers.

José implements a model for creating sending mail. In doing so he introduces us to a bunch of Active Model modules that will do our work for us.

Here are the modules in alphabetical order:

ActiveModel::AttributeMethods

When you include ActiveModel::AttributeMethods in your model, you get access to helper methods that will help you define additional methods for dealing with the attributes of your model. An example

class Tapir
  include ActiveModel::AttributeMethods
   
  # Define the attributes 
  attr_accessor 'name', 'color'

  # We want to create clear methods for every attribute
  attribute_method_prefix 'clear_'

  # We also want to have query methods for every attribute
  attribute_method_suffix '?'

  # Define the attribute methods that will call the protected methods below
  define_attribute_methods ['name', 'color']

protected
  # The name of this method corresponds to the prefix above
  def clear_attribute(attribute)
    send("#{attribute}=", nil)
  end

  # The name of this method corresponds to the suffix above
  def attribute?(attribute)
    send(attribute).present?
  end
end

   t = Tapir.new
 => #<Tapir:0x00000102769b90> 
> t.name?
 => false 
> t.name= 'kalle'
 => "kalle" 
> t.name?
 => true 
> t.clear_name
 => nil 
> t.name?
 => false 
> t.name

This is the gist of attribute methods, there is also an affix method that will allow you to add both a suffix and a prefix to your attributes. It is also worth taking a look inside the implmentation of this module, since the methods are defined on first usage through method_missing.

ActiveModel::Callbacks

ActiveModel::Callbacks provides methods for creating before_, after_, and `around_' callbacks to your model methods. An example:

class Tapir
  extend ActiveModel::Callbacks

  define_model_callbacks :snort

  def snort
    _run_snort_callbacks do
      snort_snort_snort
    end
  end

end

Then in inheriting classes I can use the callbacks as such:

class MountainTapir < Tapir
  before_snort :do_before_snort

  def before_snort
    i_am_so_cold
  end
end

ActiveModel::Conversion

This module assists with converting to, and representing a specific model instance. It contains three methods.

  • to_model, used for converting to an active model compliant model, in the default case it just returns self.
  • to_param, used for representing a model in routing.
  • to_key, used for representing a model from in a dom page.

ActiveModel::Naming and ActiveModel::Translation

ActiveModel::Naming contains one method model_name, that returns a subclass of String, that handles pluralization, etc. It has methods such as plural, human.

ActiveModel::Translation deals with I18N by adding functionality to human that handles the name lookup by keys using the preferred I18n.backend.

ActiveModel::Validations

The last, but not least of the models, ActiveModel::Validations, deals with validations. José demostrates how naming convetions and Rails constant lookup allow us to add new validators to Rails with ease. An example:

module Validators
  class TapirKindValidator < ActiveModel::EachValidator 
    def validate_each(record, attribute, value)
      unless [:baird, :mountain, :malayan, :lowland].include? value
        record.errors.add(attribute, :invalid, options) 
      end
    end
  end
end


If I now include my new validator wherever I want to use it. I can write code like:

class Tapir
  include Validators
  
  attr_accessor :kind
  validates :kind, :tapir_kind => true
end

t = Tapir.new :kind => :mexican
t.valid? 
# => false
t.errors[:kind] 
# ["is invalid"]


This example is unnecessarily complicated, since the validation could be fixed with:

class Tapir
    attr_accessor :kind
    validates_inclusion_of :kind, :in =>  [:baird, :mountain, :malayan, :lowland]
end

append_view_path

There is one more interesting thing in this chapter, append_view_path. It can be used to add a directory inside a gem to the view lookup path. This is essential to be able to deliver custom Rails components, Railties, with default views.

Chapter 3, Building a template management system

In the third chapter of the book,José takes on view resolvers. A resolver is responsible for looking up the appropriate template for a given request. The traditional resolver looks up the templates by path in the file system, but José guides us through creating a resolver that looks up the template in a database. Perfect for the core of a CMS system. I'm going to alter José's resolver to do the lookup in MongoDB instead.

# Most of this code is borrowed directly from Jos&eacute; Valim
# Only the Mongoid Part is written by me :)
require 'mongoid'
require 'singleton'

class MongoTemplate
  include Mongoid::Document
  field :body
  field :path
  field :locale
  field :format
  field :handler
  field :partial, :type => Boolean
  field :updated_at, :type => Date
    
  validates :body, :path, :presence => true
  validates :format, :inclusion => Mime::SET.symbols.map(&:to_s) 
  validates :locale, :inclusion => I18n.available_locales.map(&:to_s) 
  validates :handler, :inclusion => 
    ActionView::Template::Handlers.extensions.map(&:to_s)

  class Resolver < ActionView::Resolver 
    include Singleton
  protected
    def find_templates(name, prefix, partial, details)
      conditions = {
        :path => normalize_path(name, prefix),
        :locale => normalize_array(details[:locale]).first, 
        :format => normalize_array(details[:formats]).first,
        :handler.in => normalize_array(details[:handlers]), 
        :partial => partial || false
      }
   
      MongoTemplate.where(conditions).map do |record| 
        initialize_template(record)
      end 
    end
    
    # Normalize name and prefix, so the tuple ["index", "users"] becomes 
    # "users/index" and the tuple ["template", nil] becomes "template". 
    def normalize_path(name, prefix)
      prefix.present? ? "#{prefix}/#{name}" : name
    end
   
    # Normalize arrays by converting all symbols to strings.
    def normalize_array(array)
      array.map(&:to_s)
    end

    # Initialize an ActionView::Template object based on the record found.
    def initialize_template(record) 
      source = record.body 
      identifier = "MongoTemplate - #{record.id} - #{record.path.inspect}" 
      handler = ActionView::Template.registered_template_handler(record.handler)
      details = { 
        :format => Mime[record.format], 
        :updated_at => record.updated_at, 
        :virtual_path => virtual_path(record.path, record.partial)
      }
      ActionView::Template.new(source, identifier, handler, details)
    end
    
    # Make paths as "users/user" become "users/_user" for partials.
    def virtual_path(path, partial) 
      return path unless partial 
      if index = path.rindex("/")
        path.insert(index + 1, "_")
      else
        "_#{path}"
      end 
    end
  end
end

A Resolver is implemented by extending ActionView::Resolver and implementing the method find_templates(name, prefix, partial, details) There are a lot of extra information in the book, about caching etc. Obviously Rails caches the templates since it would be too slow to create a template every time. That is why we have the template as a singleton and that is why we clear the cache in the after_save hook above. The hook in Mongoid works exactly the same as in Active Record. Thank you Active Model!

Chapter 4, Multipart Emails with Markdown and Erb

In this chapter José walks us through three topics. The template handler API, Rails generators and Railties. I'm going to skip over the last two in this chapter. Generators are a large topic and they deserve a blog post of their own. José does a great job desribing how they work. The same goes for Railties and Rails Engines, they are definitely worthy of a blog post of their own.


# 
# Again most of the code is stolen from Jos&eacute; :)
#
module ScrambleHandler
  
  # Lookup the ERb handler
  def self.erb_handler
    @@erb_handler ||= ActionView::Template.registered_template_handler(:erb)
  end

  def self.call(template)
    # Call the erb handler, then call the new scrambler method.
    source = erb_handler.call(template)
    if template.formats.include?(:html)
      "Scrambler.from_html(begin;#{source};end).to_s"
    else
      "Scrambler.from_text(begin;#{source};end).to_s"
    end
  end

end

# Register our new handler, it handles index.html.scramble, show.html.scramble, ...
ActionView::Template.register_template_handler :scramble, ScrambleHandler

# This module scrambles text.
# Scrambler.from_text('Once upon a time a beautiful tapir came.')
# -> Ocne upon a time a baeuuitfl tpiar came.
module Scrambler
  def self.from_html html
    doc = Nokogiri::HTML(html) 
    doc.xpath('//text()').each do |node|
      node.content = from_text(node.content)
    end
    doc.to_html
  end

  def self.from_text text
    tokenize(text).map{|token| scramble(token)}.join('') 
  end

  def self.tokenize text
    return nil unless text
    text.scan(/(\p{Word}+|\W+|)/um).flatten
  end

  def self.scramble word
    return word if word =~ /\W/
    return word if word.size < 4
    arr = word.split(//)
    arr[0] + arr[1...-1].shuffle.join('') + arr[-1]
  end
end

Chapter 5, Publishing and subscribing to your applications events

In this chapter José uses the Notifications API to store notifcations in a MongoDB. He also shows how to use Rack middleware to configure what request to log. In order to configure the middleware he uses a Rails Engine. I'm just going to show how the Notifications API works here, and I'll let you read the rest in the book.

# Subscribe to all events and print them to the console
ActiveSupport::Notifications.subscribe do |*args|
  p ActiveSupport::Notifications::Event.new(*args)
end

# Instrument the rendering of Foo
ActiveSupport::Notifications.instrument(:render, :extra => :information) do
  render :text => "Foo"
end


Chapter 6, DRY controllers with Responders

In this chapter José goes through the implementation of responders. This implementation allows you to DRY up your controllers by factoring out common behavior.

def index
  @users = User.all
  respond_to do |format| 
    format.html # index.html.erb 
    format.xml { render :xml => @users }
  end
end

# becomes

def index 
  @users = User.all 
  respond_with(@users)
end


# and
def create 
  @user = User.new(params[:user])
  respond_to do |format| 
  if @user.save
    format.html { redirect_to(@user, :notice => 'User was successfully created.') }
    format.xml { render :xml => @user, :status => :created, :location => @user }
  else
    format.html { render :action => "new" } 
    format.xml { render :xml => @user.errors, :status => :unprocessable_entity }
  end 
end

# becomes
def create 
  @user = User.new(params[:user]) 
  flash[:notice] = 'User was successfully created.' if @user.save 
  respond_with(@user)
end

In this chapter we also learn how to replace the default generators with our own customized generators.

Chapter 7, Translatable app with I18n and Redis

In the final chapter José shows us how the I18N backed system works. He does this by creating a backend the uses Redis instead of the default YAML files. He also developes a simple Sinatra application that he hooks into the Rails routing with the mount method.

# Mount the Sinatra Translator::App at the /translator path.
mount Translator::App, :at => "/translator"

Rack applications normally get the full path inside ENV['PATH_INFO'], but when Rails mounts an application it removes the prefix before it sends it on /translator/en/pt/ becomes /en/pt/. The additional path is sent on in ENV['SCRIPT_NAME'] = '/translator'.

We also get a brief overview of Devise, the state-of-the-art authentication solution written by José himself.

Conclusion

One last thing, the book I have reviewed is a beta book, but the quality of it is higher than most published books I have seen. Congratulations to José and to the pragmatic bookshelf! There is not much more to say, get the book.

Monday, October 04, 2010

Choices, Habits and Awareness

Every second, the human brain is bombarded with information, the conscious part of the brain is only able to handle a tiny percentage of this. The rest is handled by our unconscious.

A habit is an automatic reaction to a given situation. Habits allow us to do things automatically, without being consciously aware of what we are doing. But, to form a new habit takes time, and during that time we must choose to do what we want to make a habit of. And, to be able to make this choice we must be aware of the choice in the first place. We must be aware to be able to become unaware!

Here is an algorithm to illustrate this:

# Sequential
if not habit?(choice) or aware_of?(choice)
  make_decision(choice)
else
  automatic_response(choice)
end

Of course, it is not that simple. The brain is not sequential.

The brain is massively parallel and almost everything in it happens unconsciously. Every second our senses are fed with more than 11 million bits of information, while the conscious part of our brain is only able to process less than 50! All other information is filtered out by our unconscious. Scary! But, here comes the cool part, we can consciously change our filters by creating new habits.

Here is parallel version of the code above.

# Parallel, unconscious
if habit?(choice)
  automatic_response(choice)
end

# Parallel, conscious
if aware_of(choice)
  make_decision(choice) # Practice
end

Choices

Every single moment of our life, we are given choices. Some choices are obvious (the choices are, the answers may not be) such as:

  • Should I use Ruby or Python for my next project?
  • Do you take this woman to be your lawfully wedded wife?
  • Should I learn a new programming language that I have no hope, whatsoever, to use in a live project?
  • Are the kids allowed to play with fire?

Other choices are not so clear, such as:

  • Do I get up now or press snooze another time?
  • Should I step on the white lines when crossing the street?
  • Do I put the right foot in front of the left or jump on the left?
  • Should I remove the hand from the hot stove or not?
  • Should I react by being angry or not?

What's cool, and scary, with choices is that every time we make one, our brain changes. It literally changes physically every time. It actually changes every time we think a thought.

Every time we make a certain choice, that path through the brain gets wider, and thus the choice gets easier to make. It is easier to make the same decision, over and over, than it is to make new decisions all the time.

Another thing about choices is that it is often painful to make them. The reason for this, I believe, is that we often know, intuitively, what the right choice is, but that choice involves more work. This is why we should form good habits, because habits free us from the agony to choose.

Habits

When we have made a decision many times; when a path through the brain has become wide enough, we don't have to make a choice any more! We have formed a habit. Psychologists say that it takes 21 days. We have both good habits and bad ones. And most of the habits we have, we are unaware of.

A great thing about good habits is that they are performed by the unconscious part of the brain. They allow us to do things without consciously thinking about them. And since we are not consciously thinking about them, it is almost as if they do themselves. :D

A sad thing about bad habits is that they are performed by the unconscious part of the brain. We do things without consciously thinking about them. And since we are not consciously thinking about them, it is almost as if they do themselves. :(

That is why we should nurture our habits. We should create habits of things that we want to do, like writing our tests first, and complimenting people when they do good. We should make habits of boring things, that we have to do, like doing the dishes and writing documentation. Once they become habits they are not boring anymore.

This is also why we should be grateful when someone points out our bad habits, because they help us become aware of something that we may want to change.

Awareness

The key to forming new good habits and getting rid of bad ones, is awareness. We cannot change what we are not aware of. We cannot train what we are not aware of. But what are we aware of? We are aware of things we are trained to be aware of. Our awareness is learned, it is dependent on our habits! Ah, recursion!

When we are creating habits, we define ourselves.

Are you aware that there is a programming language designed for programmer happiness?

Are you aware that touch typing is a habit? That sitting in front of a computer eight hours a day without being able to touch type sucks? If you're not, read this blog post by blogger extraordinaire, Steve Yegge. I wasn't aware two years ago but now I type 50 WPM (which is not great, but I get better every day).

Are you aware of that your habits form your thoughts, that they form you?

We are what we repeatably do. --Aristotele

Conclusion

Can you imagine a day without googling for code-related things? When you don't have to think at all about the signatures of methods, the key combinations that moves you to the right position, or the inner workings of the authentication library. Can you imagine how good you would feel, and how fast you would work? Can you imagine eight hours of continuous flow?

Linus Torvalds, allegedly, wrote the bare bones of Git in two weeks. How could he do this? Because he has been living and breathing C and Linux, for the last 20 years!

So, where am I going with this? I want flow! I want eight hours of continuous flow while I'm working. In order to achieve this, I have to train my brain to know, really know, unconsciously know, the tools of my trade.

I am going to select a small number of tools that resonates with the way I am and want to work.

I have previously been a generalist when it comes to programming. I am proficient in many programming languages, but I have yet to become a true expert in one. With a true expert I mean someone who doesn't have to lookup anything. Everything, the language constructs, the built-in libraries, the major third-party libraries, the tools, should be intuitively known, habitual.

I aim to become an expert in the languages Javascript and Ruby.

This doesn't mean that I'll give up other programming languages. I will still dabble with interesting programming languages like Clojure, Scala, Mirah, etc., but my main focus will be on Ruby and Javascript.

Why Ruby and Javascript? Because they are languages that resonates with my brain. They are dynamic, interpreted and give lightning-fast feedback. They also allow me to express my concepts clearly and succinctly.

Wednesday, September 29, 2010

Why Ruby?

Emancipate yourself from mental slavery, none but ourselves can free our minds. --Bob Marley, Redemption Song

There are a number of reasons to love Ruby and I will share some of them here. Ruby is influenced by some of the greatest languages ever invented: Perl, probably the most pragmatic language in the world, hell, even God used it :)

Lisp from XKCD

Ruby is also influenced by Smalltalk and Lisp. Both these languages are still living, vibrant languages despite their respectable age, 40 and 60 years respectively.

When Matz chose parts from the above programming languages his primary design goal was Programmer Happiness. He succeeded.

Here are some features that I love about the language.

Parallel Assignment

You can assign many values on the same line by separating them by commas. They are assigned in parallel. No need for temporary variables.

# Swap a and b, without a temporary variable
a, b = b, a

Multiple Return Values

If you want to return more than one value in Ruby all you need to do is to wrap it in an array. Then you can get the values by using commas. Also note, that return is not required in Ruby, the last evaluated expression is returned.

def div(a, b)
  [a/b, a%b]
end

a, b = div(5, 2)
# a = 2, b = 1

String Interpolation

Double-quoted strings can be interpolated.

kid = 'Kid'
"Hello #{kid} ##{1+3}"
# => Hello Kid #4

Here documents

You have seen them in other scripting languages and they are as good as they look. No need for String concatenation or embedded newlines (\n).

sql = <<-SQL
SELECT allocations.project_id as project_id, year, week, allocations.id as allocation_id
  FROM weeks
  LEFT OUTER JOIN allocations ON allocations.start_date < weeks.end_date
    AND allocations.end_date > weeks.start_date
    AND allocations.project_id = ?
  WHERE weeks.start_date >= ? AND weeks.end_date <= ?
SQL

Higher Order Functions

Higher order functions are easily expressed with Ruby blocks.

# Map converts an array of values to a new array of values
["a", "b", "c"].map { |item| item.upcase }
# => ["A", "B", "C"]

# Zip zips arrays together
[1, 2, 3].zip([10, 20, 30])
# => [[1, 10], [2, 20], [3, 30]]

# Zip with a function applies the function to the results
[1, 2, 3].zip([10, 20, 30]) {|arr| arr[0] + arr[1]}
# => [11, 22, 33]

Simple Command Line Access

The command line is always readily available in Ruby

# Backticks invokes the command and returns the result as a string
`ls`
# => "Scripts\nStylesheets\nbin\nget_destinations.scpt\nlib\nnibs\n"
`ls`.split
# => ["Scripts", "Stylesheets", "bin", "get_destinations.scpt", "lib", "nibs"]

# System invokes the command, prints the result to stdout, and return a boolean
system('ls -l')
total 64
drwxr-xr-x  3 andersjanmyr  admin    102 Aug 29  2009 Scripts
drwxr-xr-x  3 andersjanmyr  admin    102 Aug 29  2009 Stylesheets
drwxr-xr-x  5 andersjanmyr  admin    170 Aug 29  2009 bin
-rw-r--r--  1 andersjanmyr  admin  12312 Aug 29  2009 get_destinations.scpt
drwxr-xr-x  3 andersjanmyr  admin    102 Aug 29  2009 lib
drwxr-xr-x  3 andersjanmyr  admin    102 Aug 29  2009 nibs
# => true

system('ls tapir')
ls: tapir: No such file or directory
# => false

Open Classes

Open classes mean that it is possible to add new methods to already existing classes. This is very powerful.


class String
  def vowels
    self.scan(/[aeiouy]/i)
  end
end

"A tapir is beautiful".vowels
# => ["A", "a", "i", "i", "e", "a", "u", "i", "u"]

There are two common reactions to this.

  • Wow! This is really cool, this will allow me to put everything in the right place.
  • What! That is too dangerous, our programmers will create an unmaintainable system.

I'm in the first camp!

Class Inheritance

In Ruby the classes are objects and follow the inheritance rules of objects. No statics are needed.

class Mammal
  # This is a class method, that returns all mammals of this kind
  def self.all
    mammals.select do |m|
      m.kind_of? self
    end
  end

  # Another class method that gives access to the class varibable
  def self.mammals
    # @@ is a class variable prefix
    @@all_mammals ||= []
  end

end

class Tapir < Mammal
end

# Add some mammals and a tapir
Mammal.mammals << Mammal.new << Mammal.new << Tapir.new

Tapir.all
# => [#<Tapir:0x000001010fc1a0>]

Mammal.all
# => [#<Mammal:0x000001010fc218>, #<Mammal:0x000001010fc1c8>, #<Tapir:0x000001010fc1a0>]

Meta Programming

When the classes are parsed, Ruby is already running and since it is possible to create methods and classes on the fly you can do some very powerful meta-programming with Ruby. Here is a simple example.

class Tapir

  [:sniff, :eat].each do |method_name|
    send :define_method, method_name do |thing|
      "I'm #{method_name}ing #{thing}!"
    end
  end

end


t = Tapir.new
t.eat 'bananas'
I'm eating bananas!

t.sniff 'glue'
I'm sniffing glue!

This type of meta-programming is what enables the simplicity of Rails' has_many, and belongs_to methods for declaring relationships.

Method Missing

The last feature of Ruby that I want to share is method_missing. method_missing is a feature that Ruby inherited from Smalltalk. If an object is invoked with a method that is not defined by its class or ancestors, method_missing(method, args) is called instead. By implementing this method you can effectively create all sorts of cool stuff such as proxies, prototypes, etc.

# Simple implementation of a Javascript-like structure without inheritance
class Prototype

  def props
    @props ||= {}
  end

  def method_missing(method, *args)
    m = method.to_s.sub('=', '') # Strip the trailing '=' to allow setters
    if args.empty?
      props[m]
    else
      props[m] = args[0]
    end
  end
end

prot = Prototype.new
prot.age
# => nil
prot.age 14
# => 14
prot.age
# => 14
prot.age= 16
# => 16
prot.age
# => 16

Inside method_missing it is of course also possible to define new methods and classes dynamically, but I'll leave that for another day.

Ruby is a supreme dynamic language that lets you do almost anything. Try it!

When you can do anything, you have to become more responsible. You own your fate. And, that, I think, is a situation which promotes responsibility. -- Michael Feathers, author of Working Effectively with Legacy Code

Saturday, September 18, 2010

Webkit CSS Transitions and Transformations

This blog is best viewed in Safari or Chrome since it uses Webkit-specific functionality.

Transitions

transition, the process or a period of changing from one state or condition to another

Transitions are usually performed using jQuery or some other Javascript framework to animate the changes to a property. When using Webkit (Safari, Chrome, iPad, iPhone) Javascript is not necessary anymore.

In Webkit the transitions are described using four different properties. It is worth noting that the properties only define how the transitions will work when the values on the element is changed. They don't actually do anything until the values are changed!

/* This sets up a transition property on all divs on opacity.*/
div {
  -webkit-transition-property: opacity;
  -webkit-transition-duration: 2s;
}
/* The fade-in class, changes the opacity when set on an element.
  And thus triggers the transition defined above if the element is a div. */
.fade-in {
  opacity: 1;
}
// Adds the class 'fade-in' on all divs, via jQuery.
$("div").each(function() {
  $(this).addClass('fade-in');
});

-webkit-transition-property

This is the property that will be affected by the transition, this can be any valid property, and it defaults to all. What this means is that a change to any attribute on an element will be affected by the transition and occur according to the specification.

/* only width should be affected */
-webkit-transition-property: width;

/* multiple comma-separated properties are supported */
-webkit-transition-property: opacity, width, height;

/* all properties should be affected, this is the default */
-webkit-transition-property: all;

-webkit-transition-duration

How long the transition should take? Valid units are s and ms.

/* Set the duration to 400 milliseconds */
-webkit-transition-duration: 400ms;

/* Multiple values are supported here too, in combination with
multiple -webkit-transition-property's */
-webkit-transition-property: opacity, width, height;
-webkit-transition-duration: 400ms, 1s, 3s;

-webkit-transition-delay

How long should we wait before the transition starts. Valid units are s and ms.

/* Set the delay to 1 second */
-webkit-transition-delay: 1s;

/* Multiple values are supported here too, in combination with
multiple -webkit-transition-property's */
-webkit-transition-property: width, height;
-webkit-transition-delay: 1s, 3s;

-webkit-transition-timing-function

The timing function is a function that changes the speed of the transition over its duration. It is described with a cubic-bezier curve, but it has some predefined values, ease (default), ease-in, ease-out, ease-in-out, and linear. In none of those values are to your liking you can define your own with the cubic-bezier function.

/* Transition with the default timing*/
-webkit-transition-timing-function: ease;
/* Multiple values are supported here too, in combination with
multiple -webkit-transition-property's */
-webkit-transition-property: opacity, -webkit-transform;
-webkit-transition-timing-function: ease-out, cubic-bezier(0.5, 0.2, 0.3, 1.0);

Thats it for transitions. But wait, what was that -webkit-transform in the end?

Transformations

transformation, a thorough or dramatic change in form or appearance

Webkit supports some really cool transformations, that allow you to animate the pages in remarkable ways.

rotate()

<div style = "width: 12em;
  margin-top: 5em;
  -webkit-transform: rotate(45deg)">
I am rotated!
</div>
I am rotated!

Rotate accepts the units deg, rad, and grad

It also comes in 3D forms, rotateX, rotateY, rotateZ, and rotate3d.

scale()

<div style = "width: 12em;
  margin: 2em 0 2em 18em;
  -webkit-transform: scale(4)">
I am Scaled!
</div>
I am Scaled!

Scale can take an additional parameter scale(x, y) If you want to scale un-proportionally. It also comes in 3D versions, scaleX, scaleY, scaleZ, and scale3d.

translate()

<div style = "width: 12em;
  margin: 2em;
  -webkit-transform: translate(4em, -2em)">
I am Translated!
</div>
I am Translated!

Translate takes one or two parameters and moves the element to the new location. It, too, comes in 3D forms, translateX, translateY, translateZ, and translate3d.

Additional Transforms

Apart from the translations above, Webkit also supports skew, perspective, and matrix. Read more in the Safari Reference Library

I'll finish up with a composite transform combined with transitions, best viewed with Safari. This transformations are initiated by changing the style from Javascript.

<div style="width: 4em; height: 4em;
  margin: 2em; background-color: blue;
  color: white;
  -webkit-transition-duration: 5s;
  -webkit-transition-function: ease-out;"
  onclick='style.webkitTransform="translate(16em, -16em) scale(6) rotate(720deg)"; style.backgroundColor="red";'> Click Me!
</div>
Click Me!

Thursday, September 02, 2010

Using Git with Subversion

I had the unfortunate experience of having to use Subversion again after using Git for a long time. It is amazing how fast I can forget. After renaming a directory at the prompt, and the agony that goes with it, I decided to switch back to Git.

$ mv requester sampler
# svn agony after renaming a directory
$ svn st
?       sampler
!       requester
!       requester.rb
A       sampler.rb

The tool to use when using Git with Subversion is, of course, git svn.

git svn works very well as long as you remember that Subversion is not Git. It does not handle merging well, and it will bite you if you don't respect that. So what does this actually mean? It means:

Always keep the Git master in sync with Subversion

To do this you have two commands you can use.

# Rebases the commits from the upstream Subversion server with your local master.
$ git svn rebase

You should only git svn rebase in your Git master, and you should ALWAYS do it before you git svn dcommit anything to the subversion repository. git svn rebase keeps the upstream subversion in sync with your local master by pulling down the changes, kind of like svn update.

# Commits the changes you have in your local master to the upstream Subversion server.
$ git svn dcommit

When you have changes ready to commit, you commit them to subversion with git svn dcommit. You should ALWAYS git svn rebase before you do the update, or it will fail.

That's it! As long as you follow these two simple rules, your life with git svn will be easy. If you forget to follow them, you will be bitten. When you get bitten, the cool thing about Git is that even if you screw up, it is always possible to sort it out.

It that was all there was to it, there would be no reason to use Git instead of Subversion. Git really shines when it comes to branching and merging. You may create as many local branches as you like with git branch branch_name or git checkout -b branch_name. You can hack around in these local branches as much as you want and merge them together. But, before you merge them into the master branch, you must rebase with master! Not merge, rebase! Rebase means replay the commits on top of the named branch. It creates new commits, the same content, but with a different SHA-1.

# Example session

(master)$ git svn rebase
(master)$ git checkout -b dev
hack, hack, hack, ...
(dev)$ git commit -am 'Commit the changes' 

(dev)$ git checkout master
(master)$ git checkout -b bugfix
hack, hack, hack, ..., done

(bugfix)$ git checkout master
(master)$ git svn rebase
(master)$ git checkout bugfix
$ git rebase master
(bugfix)$ git checkout master
(master)$ git merge --ff bugfix # --ff only fast-forwards, merges that don't need to merge. 
(master)$ git svn dcommit
(master)$ git branch -D bugfix # delete the branch it is not needed anymore

(master)$ git checkout dev
hack, hack, hack, ..., done

(dev)$ git checkout master
(master)$ git svn rebase
(master)$ git checkout dev
(dev)$ git rebase master
(dev)$ git checkout master
(master)$ git merge --ff dev # --ff only fast-forwards, merges that don't need to merge.
(master)$ git svn dcommit

Another thing to be aware of is that git svn dcommit creates an extra commit, so even if you haven't changed anything in the master you need to rebase the local branch with the master. This is only needed if you don't delete the branches after you are done with a commit.

In the example above, I ended with a git svn dcommit and I didn't remove the dev branch.

(master)$ git svn dcommit # from above
(master)$ git co dev
(dev)$ git rebase master # rebases the extra commit created by git svn dcommit

If you forget to rebase or something else happens that hinders a clean merge into the master. You can always back out of it with git reset --hard.

(master)$ git svn dcommit
... failed miserably, because I failed to git svn rebase, bollocks!
(aa..88dd|MERGING)$ git reset --hard
(master)$ git svn rebase
(master)$ git svn dcommit # Nice and clean commit

To get started you need to clone a subversion repository.

$ git svn clone http://svn.example.com/project/trunk
$ cd trunk
(master)$ git ...

Now, is a good time to start using Git. Get yourself anything by Scott Chacon, such as the book or the screencasts.

Thursday, August 26, 2010

The Ruby Toolbox

One of the great things about Ruby is the community. When something is not working out as well as it could, someone figures out a way to improve it.

It used to be difficult to select what gems, Ruby libraries, to use when solving a task that I was not familiar with. This is not the case anymore. Christoph Olszowka decided that he wanted to solve this problem and created The Ruby Toolbox.

The Ruby Toolbox, Know your options!

Ruby developers can choose from a variety of tools to get their job done.

The Ruby Toolbox gives you an overview of these tools, sorted in categories and rated by the amount of watchers and forks in the corresponding source code repository on GitHub so you can find out easily what options you have and which are the most common ones in the Ruby community.

This is surprisingly powerful. In my latest project I used the following libraries (among others).

Rails

Rails need no introduction, it is one of the best frameworks for creating dynamic web applications. With best, I mean most productive and fun to work with!

Haml

Haml (HTML Abstraction Markup Language) is a layer on top of XHTML or XML that's designed to express the structure of XHTML or XML documents in a non-repetitive, elegant, easy way!

Typhoeus

Typhoeus is a http client library, a thick wrapper around curl, just like curl it works like a charm.

Capistrano

Ahh, Capistrano, deployment scripting done right! The simplicity of the structure is worth showing since it should be copied by other lesser tools.

# Create the basic structure
$ cap deploy:setup
mkdir -p /var/rails/rsvc 
/var/rails/rsvc/releases 
/var/rails/rsvc/shared 
...

# Deploy from the repo into a timestamped release directory and symlink current
$ cap deploy
svn checkout -q  -r5454 https://svn.neo4j.org/qa/matrix-framework/rsvc/trunk/rsvc /var/rails/rsvc/releases/20100826122450 
echo 5454 > /var/rails/rsvc/releases/20100826122450/REVISION
....
rm -f /var/rails/rsvc/current && ln -s /var/rails/rsvc/releases/20100826122450 /var/rails/rsvc/current

It's so simple and powerful, that it makes me cry.

God

God, a wonderfully named, server monitoring tool written in Ruby. God aims to be the simplest, most powerful monitoring application available.

RSpec

RSpec, only code can do it justice.

describe Request do
  
  before do
    @sample = Sample.create(:name => 'my_sample', :method => "post")
  end
    
  context '#old' do
    it "should not return any" do
      Request.old.should be_empty
    end
    ...
  end

  context '#delete_old_non_failing' do
  
    it "should delete old non failing requests" do      
      create_old_request :response_status_code => 0
      create_old_request :response_status_code => 200
      expect {
        Request.delete_old_non_failed
      }.to change { Request.count }.by(-2)
    end
    ...
  end
  
  ...
end

Does your language have a Toolbox? Perhaps it is time to create one, or to switch to another language?

Monday, August 16, 2010

Good Practices for Rich Web Applications

Use jQuery

jQuery is the best thing that has happened to Javascript since it got first class functions in version 1.2. The library is elegant, powerful and has exactly the right level of abstraction for working with the DOM. There is nothing more to say. Learn it and use it. Good resources are: the jQuery API, my view of the jQuery API

Learn Javascript

Javascript is the programming language of the web. Learn it! Javascript is different from most other programming languages. It is dynamic, it has prototypical inheritance, and works more like Scheme than any of the languages that you are probably used to. If you want to learn Javascript you should get the following books, The Little Schemer, The Seasoned Schemer, Javascript, the Good Parts, and possibly High Performance Javascript

Learn CSS

Many programmers think that CSS is the language of designers and not programmers. This is not the case at all. If you are lucky enough to have a designer on your team (most people don't), CSS is the language with which you communicate. It is the interface between designers and programmers and as a programmer you should know it better than the designers. By knowing CSS well you will reduce the misunderstandings between you and your designer.

Unfortunately, many designers don't care about how code looks, as long as the design looks good on the surface. It will be up to you to make sure that the CSS doesn't get out out of hand. It will also be up to you to keep the HTML clean, and a good way to do this is to use semantic HTML, combined with CSS. You have no idea what the designers can come up with.

<!-- 
  Old School rounded corners, invented by a GOOD designer. 
  All this code was actually needed to achieve the purpose.
  -->
<style>
.t {background: url(dot.gif) 0 0 repeat-x; width: 20em}
.b {background: url(dot.gif) 0 100% repeat-x}
.l {background: url(dot.gif) 0 0 repeat-y}
.r {background: url(dot.gif) 100% 0 repeat-y}
.bl {background: url(bl.gif) 0 100% no-repeat}
.br {background: url(br.gif) 100% 100% no-repeat}
.tl {background: url(tl.gif) 0 0 no-repeat}
.tr {background: url(tr.gif) 100% 0 no-repeat; padding:10px}
</style>
<div class="t">
  <div class="b">
    <div class="l">
      <div class="r">
        <div class="bl">
          <div class="br">
            <div class="tl">
              <div class="tr">
                Lorem ipsum dolor sit amet consectetur adipisicing elit
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

As an additional benefit you will become better at jQuery. Not only is CSS the query language of the browsers it is the query language of jQuery. Jariba!

Bulletproof Web Design is a good book web design, including CSS.

Decide how "Rich" your application should be

How rich should your application be? The scale varies from no Javascript to only Javascript, but you will probably want to land somewhere in between. Here are a few suggestions.

  • No Javascript, everything is server generated.
  • Slightly enhanced pages, simple validations, but no Ajax.
  • Ajax enhanced pages, but every page still reloads frequently.
  • Single page per area, entire area is handled by Javascript.
  • Only Javascript, Ajax interaction with the server
  • Only Javascript, no interaction with the server.

The important thing is to make a decision. If you don't make the decision, everyone will do different things on different parts of the application and you will loose consistency. In GUI, consistency is king. Make a decision and move on, you can always change your decision later.

Organize your code

Javascript

Make sure that all your Javascript code is namespaced properly. It is impolite to pollute the global namespace and it will bite you in the end. A simple variable declaration will do.

// Common namespace for your entire application
// This declaration lets you split your code of multiple files.
// If MyNamespace is defined use it, otherwise declare it.
MyNamespace = MyNamespace || {};

But, of course, it is also possible to get fancy and encapsulate the functions that you don't want to expose, if that is your cup of tea.

MyNamespace = MyNamespace || {};

MyNamespace.Tournament = function() {
 // Private stuff
 var tournamentCount = 0;
 function addTournament(tournament) {
  tournamentCount++;
 }
 
 return {
  //public stuff
  numberOfTournaments: function() {
   return tournamentCount;
  }
 }
}();

You should also separate your Javascript code into different files. The namespace idiom above helps to have the same namespace across multiple files. The same principles as with other type of code is valid with Javascript, organize the code by area, when it changes, where it is used, etc. Don't be afraid of the additional load time, splitting the files will give you. The files can easily be concatenated with tools like Rake, SCons, Ant or even a simple:

$ cat file1.js file2.js file3.js > all.js

They can also be compressed with JSMin or YUI Compressor.

Optimize your environment for development, not for production!

HTML

HTML is code! Divide your pages into partials by responsibilities. It allows you to keep your pages DRY and readable. The Single Responsibility Principle applies to HTML too.

Make sure you keep the Javascript with the code that it manipulates. If you, for example, have a calendar partial that uses jQuery DatePicker, you have to make sure that the partial includes all the necessary Javascript to configure the calendar. Don't keep Javascript code in the page away from the partial. Things that change together should be together.

CSS

Stylesheets are code too. They should also be split into areas that allow you to easily find and navigate them. Use Sass or SCCS to keep your CSS files DRY. Sass is good for designers to. It gives them the ability to use variable names, mixins, etc. and simplifies their usage of semantic names such as notice, and sidebar instead of yellow and left.

Optimize your environment for development, not for production!

Separate your Javascript from your HTML

All too often I see generated HTML pages with Javascript code in them. Don't do it. Keep the HTML free from Javascript.

<!-- DON'T DO THIS!  -->
<button id='update-button' onclick="MyNamespace.updateList();">Update List</button>

// In the Javascript file for the page.
MyNamespace.updateList = function() {...}


<!-- DO THIS! -->
<button id='update-button'>Update List</button>

// In the Javascript file for the page.
MyNamespace.updateList = function() {...}

$(function() {
  $("#update-button").click(function() {
    MyNamespace.updateList();
  });
});

It may seem like there is a lot more code in the good example, but notice the symmetry. The code that attaches the listener is in the same file as the code that uses the listener. This is good. Symmetry is good.

Use clone()

Separating the HTML and the Javascript goes both ways. Don't generate HTML code in Javascript. It doesn't matter that it is super simple to do it using jQuery.html(). Keep them separate, use jQuery.clone() instead.

// DON'T DO THIS
$("<li data-id='123'>My new item</li>").appendTo("ul");
// OR THIS
$("ul").append("<li data-id='123'>My new item</li>");


<!-- DO THIS -->
<ul>
<li id="list-template" class="template">All .template are hidden (display: none) in the CSS</li>
</ul>

// AND THIS
var $clone = $("#list-template").clone();
$clone.attr("data-id", "123").text("My new item").removeClass("template");
$("ul").append($clone);

The point of this is, again, to keep the HTML separate from the Javascript.

Decide how content flows between, the page, Javascript and the Server.

Once you have decided how rich your application should be, you have to decide on a method for moving the data between the HTML Page, Javascript and the Server. My preferred choice is to have every page that is served from the server include a context object with all the static data for the page and to have additional data that belongs to parts of the page be sent as data-attributes on the elements concerned.

The context object will contain all the data that is commonly needed in the page.

// Sample context object that is generated with the page.
MyNamespace = MyNamespace || {};
MyNamespace.Context = {
  user: {
    id: "28",
    name: "Anders Janmyr"
  },
  tournament: {
    id: "78344",
    name: "Fifa World Cup"
  }
};

I use the context object(s) to keep state on the client to. If it is important that the page looks exactly the same, even if the user reloads the page, I make sure that the state I stick into my context object is synched back to the server. This can easily be done, asynchronously, with Ajax and does not affect performance noticeable.

Elements specific data is sent along with the element it defines.

<!-- Element specific data attached to the elements with data-attributes -->
<ul id="tournament-menu">
  <li data-id="78344" data-participant-count="64">Fifa World Cup</li>
  <li data-id="666"  data-participant-count="44">Americas Cup</li>
  <li data-id="1464" data-participant-count="32">Rugby World Cup</li>
</ul>

The same argument as with the context object applies, as soon as I change an element in the GUI i need to feed that information back to the server. With elements I usually send the information to the server before updating the GUI, since element specific data is usually permanent data and not just session data.

An alternative solution to the context object above is to use the body element as the data-container, like this:

<body data-user-id="28" data-user-name="Anders Janmyr" data-tournament-id="78344" data-tournament-name="Fifa World Cup">

I tend to use the context object because I find it easier to add functionality to it than to the DOM element.

Only send the data that is needed to the client with the page. The rest of the data should be loaded on demand, with Ajax. Both JSON data and HTML templates can be loaded on demand. There is no need to deliver the entire page at once. Experiment and do what gives the best user experience.

Use file watchers to speed up feedback

If you compare the feedback cycle of Javascript and HTML development to Java and C# development, you are probably very happy with the short, tight feedback loop. This doesn't mean that you should be content. A feedback cycle cannot be too short.

xrefresh for Firefox and IE, and LiveReload for Safari and Chrome, are a couple of tools that will tighten your feedback loop even more.

Both tools are file watchers that listen to changes for files and refresh the browser when they change. If you combine this with two screens, you will have one screen for the browser, that updates continuously, while you edit your code on the other screen. Fabulous!

Conclusion

Rich web applications are very close to the traditional client-server model. We have to keep state on the client side to give the user a good experience. At the same time the application state, and indeed the entire application, can be swept away by a click of a button or a page reload.

This puts new demands on us as developers. We have to realize that we are responsible for the entire application, not just the business logic, but the HTML and CSS too. More that anything, we have to realize that Javascript is a first class programming language with its own programming techniques, which we need to master to be able to develop good web applications.