Label Your Checkboxes and Radio Buttons to Ease Your User's Woes
Posted by: François Beausoleil on 2009-04-30
Whenever I build forms, I'm very careful to always label all my fields. After all, it's good for accessibility, right? Well, it turns out it's also good for usability. Very, very good.
I'm getting older, and as I'm getting older, I get lazier. I like things to be bold and easily reachable. Small targets annoy me these days. Let's take for example Campfire's login page:
Let's say you login and want to be remembered. Nothing easier, right? Simply click the checkbox. But you're lazy, and there's this huge label right next to it. Go ahead, click the label. What? Nothing happens? You're right: nothing happens. Here's their code:
<dd> <input type="checkbox" name="remember" value="1" /> Remember me </dd>
Do you see the problem? I do. The label is not a label. It's not attached to the checkbox. For fun, let's count the number of pixels available to click on: 12×12, or 144 pixels.
Compare that to the following image:
In this particular image, we have an area that's 325×21, or 6825 pixels available for clicking on. But this picture is a lie. The full width of my browser's window is availble for clicking on.
To be clear, don't do this:
<form action="#" method="get"> <div class="row"> <!-- Don't do this! --> <p>Name</p> <input id="name" name="name"/> </div> </form>
Instead, correctly set the field's id and label's for attributes:
<form action="#" method="get"> <div class="row"> <label for="name">Name</label> <input id="name" name="name"/> </div> </form>
If you want to know how significant this is, please have a look at a toy page I made: example labelling versus clickable area.
Very important note: I did not select Campfire out of spite. I contacted Campfire's support department and was told that I should simply click the checkbox. To be fair, all other 37signals applications have correctly attached the label to the input. Other applications and websites have the very same problem:
- Jakob Nielsen's UseIt.com search page
- eBay.ca Sign in page
- Desjardins' AccèsD
- RubyForge's delete a project form, although in this instance it might be argued that this is a security feature… Pointed out by John Trupiano through Twitter.
This list was compiled in April 2009, after 20 minutes of searching.
More Information on the LABEL element and its use
- Accessible Forms, specifically Labelling Form Elements.
- Checkboxes vs. Radio Buttons, specifically look for #11 titled Let users select an option by clicking on either the button/box itself or its label.
- What Makes a Web Form Usable or Unusable
- HTML 4.01 Specification, particularly Section 17.9: Labels
- Fitts' Law on Wikipedia, which states that the bigger and closer an object is, the faster it is to use
Acceptance Test Driven Development (ATDD)
Posted by: James Golick on 2009-03-15
Test Driven Development (TDD) is this idea that you should write a unit test before you write the code. You run the test to make sure that it fails. Then, you implement the code necessary to make it pass. Rinse and repeat until the software is finished.
One of the most popular themes among TDD nay-sayers is the ad-absurdum argument. They don't know what they building. They're agile. So, how can they write their tests first?
As any test-driven developer knows, though, you don't write all your tests first. I know this. But, yet, when I first heard about ATDD, I, too, fell in to this fallacious trap.
So, what is ATDD?
It's rather simple, really. Before you implement a feature (or piece of a feature), you write an acceptance test. Then, you drop down to lower level tests (unit, functional) to TDD the code necessary to make the acceptance test go green.
I've only been ATDD'ing for a short while, but I'm already seeing a huge improvement in the quality of the stuff that I'm putting out. Much in the same way that unit testing can be looked at as a design practice for your code, ATDD can be looked at as a design practice for your high level functionality.
Starting with an acceptance test forces you to think at the level of the user before you think about your code. What is the workflow going to be? What should the user see? What buttons, fields, or other functional elements will be necessary and how will they be labeled? In my experience, these are often questions that are asked after the models and controllers (or equivalent units) are already built for that feature.
Answering those questions first seems to be a great way to better understand what you're building. Those are the only relevant issues in the eyes of your users. The answers to those questions are the application. Everything else, including the unit tests, is just the implementation.
Oh yeah, and a comprehensive set of acceptance tests is pretty useful too.
4 Core Competencies of Great Hackers
Posted by: Daniel Haran on 2009-03-10
At giraffesoft we do a lot of pair-programming collaborative development, both internally and when hired to coach or audit teams. After working closely with dozens of programmers, it's time to draw some conclusions.
Here are 4 traits that appear to be universal amongst great hackers:
Typing over 60 wpm
Thousands of hours spent on IM and IRC make you a faster typist. It's a skill that can be learned in school or with specialized software in 20 to 40 hours. So why are so many programmers glancing at their keyboards for common symbols?
Bringing up typing speed in conversation meets some resistance amongst some programmers. I've tried arguing that the micro-interruptions to your programming can knock you out of your flow and kill your productivity. For those that do not listen, I offer the example of people that google hotmail. It seems noobish, doesn't it?
Owning the command-line
Some developers need a pretty GUI or IDE to wrap every command-line utility. During one audit at a consulting company I saw a programmer wrestle with his IDE for 10 minutes in front of two CTOs. Verdict? His IDE didn't yet have support for the last version of Ruby on Rails, which we needed for specific functionality (ActiveResource). He was stuck.
In contrast, every great hacker we know has a customized environment, and they routinely compose unix commands. Even those stuck on Windows because of corporate policy still run Linux at home or on their servers.
Knowing your editor
Let's not pick editor fights: the only 3 editors we know to be used by great hackers are TextMate, vim and emacs. The most productive hackers will often customize their editor heavily.
We haven't met a single great hacker that relied on an IDE, although we hear they exist.
Reading code: owning your tools
We've noticed more people ignoring documentation and going straight to the source code. It's a great start.
Diving into a large code base to quickly understand what it does is a skill that can be practiced. People do get much faster at it with a little bit of practice. So fast that using a debugger to step through code seems slow by comparison; I've been chided by one hacker for using a debugger. "It's slow and it doesn't help you understand the code." Ouch.
Most hackers we know routinely read the source of plugins and frameworks before using them. By choosing better architected tools it's easier to add new functionality or discover security flaws. They also appear rather nonchalant about modifying framework code. They understand what it does, and feel free to modify it as if it was their code.
But, but...
The list isn't final or perfect, just the result of observations and discussions. A check-list for self-improvement.
I don't pretend to fit the description of "great hacker" that I've offered up: I don't read enough code, haven't done much work customizing my editor and barely know some CLI utilities like awk or sed. While I won't claim that learning these 4 skills will make you a great hacker, it seems unlikely you can become one without them.
How to Use TimelineFu: Building an activity feed for a social application
Posted by: François Beausoleil on 2009-02-26
In this article, I would like to show how to use TimelineFu to build a timeline. This is the kind of list of events that we often see on dashboards, such as on GitHub:

I will assume you already know your way around Rails, so I won't describe the basic steps in excruciating details.
Let's start by making the application and models (I'm using Rails 2.2.2). This is a social application, with people and relationships between people as the basic entities in the domain.
$ rails myfriends $ cd myfriends $ git init $ echo "*.log" > log/.gitignore $ echo "*.sqlite3" > db/.gitignore $ echo "*" > tmp/.gitignore $ git add . $ git commit --message "Initial commit" $ script/generate scaffold person name:string $ script/generate scaffold relationship person_id:integer friend_id:integer $ rake db:migrate $ git add . $ git commit --message "Scaffolded models"
Time to write a minimal set of tests.
class PersonTest < ActiveSupport::TestCase should_have_valid_fixtures should_require_attributes :name should_allow_mass_assignment_of :name should_not_allow_mass_assignment_of :relationships, :friends, :relationship_ids, :friend_ids should_have_many :relationships should_have_many :friends end
And make those pass:
class Person < ActiveRecord::Base validates_presence_of :name attr_accessible :name has_many :relationships has_many :friends, :through => :relationships end
Turning to relationships:
class RelationshipTest < ActiveSupport::TestCase should_have_valid_fixtures should_require_attributes :friend_id, :person_id should_allow_mass_assignment_of :friend, :person should_not_allow_mass_assignment_of :friend_id, :person_id should_belong_to :person, :friend end
class Relationship < ActiveRecord::Base belongs_to :person belongs_to :friend, :class_name => "Person" validates_presence_of :person_id, :friend_id attr_accessible :person, :friend end
All pretty standard stuff, really.
Installation
Installation is pretty straightforward:
$ script/plugin install git://github.com/giraffesoft/timeline_fu.git
TimelineFu comes with a generator that will do the basics for you. The generator is completely optional. See the README for details.
$ script/generate timeline_fu
exists db/migrate
create db/migrate/20090225144815_create_timeline_events.rb
create app/models/timeline_event.rb
Let's see what TimelineFu generated for us:
class CreateTimelineEvents < ActiveRecord::Migration def self.up create_table :timeline_events do |t| t.string :event_type, :subject_type, :actor_type, :secondary_subject_type t.integer :subject_id, :actor_id, :secondary_subject_id t.timestamps end end def self.down drop_table :timeline_events end end class TimelineEvent < ActiveRecord::Base belongs_to :actor, :polymorphic => true belongs_to :subject, :polymorphic => true belongs_to :secondary_subject, :polymorphic => true end
TimelineFu's glossary / terminology
A basic timeline event looks like this:
François added you as a friend
The actor is the person or thing that did an action. The subject is what was acted against. The secondary subject is supporting documentation about the subject. And the event type is pretty self-explanatory. The example above looks like:
- Actor: François
- Subject: You (a Person instance)
- Secondary Subject: the Relationship instance
- Event Type: "added you as a friend" (friended)
Another example:
François posted a new comment on "How to use TimelineFu to build timelines"
- Actor: François
- Subject: Comment
- Secondary Subject: the Post
- Event Type: "posted a new comment" (commented)
Let's begin by writing a failing test.
class RelationshipTest < Test::Unit::TestCase context "Adding another person as a friend" do setup do @francois = person(:francois) @james = person(:james) @francois.friends << @james end should_change "TimelineEvent.count", :by => 1 end end
Run and see the test fail. Open up TimelineFu's README and look at how timeline events are created. Hint: it's called #fires.
class Relationship < ActiveRecord::Base fires :friended, :on => :create end
If you were to look at the attributes of the timeline_event as it was created, here's what you would find:
--- !ruby/object:TimelineEvent attributes: id: "1" event_type: friended actor_type: actor_id: subject_type: Relationship subject_id: "1" secondary_subject_type: secondary_subject_id: created_at: 2009-02-25 15:39:54 updated_at: 2009-02-25 15:39:54
Notice that actor and secondary subject are nil. This is because we haven't specified any options to the #fires call. Let's remedy the situation with a new set of failing tests:
class RelationshipTest < ActiveSupport::TestCase context "Adding another person as a friend" do context "the timeline event" do setup do @event = TimelineEvent.last end should "set the actor to be the person who created the friendship" do assert_equal @francois, @event.actor end should "set the subject to the relationship" do assert_equal @francois.relationships.first, @event.subject end should "set the secondary subject to the new friend" do assert_equal @james, @event.secondary_subject end should "set the event type to be 'friended'" do assert_equal "friended", @event.event_type end end end end
class Relationship < ActiveRecord::Base fires :friended, :on => :create, :actor => :person, :subject => :friend, :secondary_subject => :self end
It's nice to know when someone friends you, but isn't it even better to know when they don't want you as friends anymore? This way, you'll know not to give them gifts when it's their birthday. A new failing test:
class RelationshipTest < Test::Unit::TestCase context "Deleting the relationship" do setup do relationships(:james_to_francois).destroy end should_change "TimelineEvent.count", :by => 1 context "the timeline event" do setup do @event = TimelineEvent.last end should "set the actor to the person who destroyed the friendship" do assert_equal people(:james), @event.actor end should "set the subject to the relationship" do # It's been deleted... Oops! end should "set the secondary subject to the old friend" do assert_equal people(:francois), @event.secondary_subject end should "set the event type to 'unfriended'" do assert_equal "unfriended", @event.event_type end end end end
And the implementation:
class Relationship < ActiveRecord::Base fires :unfriended, :on => :destroy, :actor => :person, :secondary_subject => :friend end
Rendering the events feed
We need a way of getting recent events for any person. Let's analyze what we want to achieve. If someone adds me as a friend, I want that event to appear in my timeline (timeline_events WHERE subject == self). I also want to see events of my friends, such as "James added Mat as a friend" (timeline_events WHERE actor IN (my friends)). Let's write a first failing test:
class PersonTest < ActiveSupport::TestCase context "A new person" do context "where James friends self" do setup do people(:james).friends << @person end should_change "@person.recent_events.count", :by => 1 end end end
Let's do the simplest thing that could possibly work:
class Person < ActiveRecord::Base has_many :recent_events, :as => :subject, :class_name => "TimelineEvent", :order => "timeline_events.created_at DESC" end
That works just fine. But how do I get to the events of my friends? My friends events are the ones where actor_id is one of my friends. Let's write another failing test:
class PersonTest < ActiveSupport::TestCase context "A new person" do context "where James friends self" do context "where James friends someone else when James is my friend" do setup do @person.friends << people(:james) people(:james).friends << Person.create!(:name => "Daniel") end should_change "@person.recent_events.count", :to => 2 end end end end
And since we want both where subject = X or actor = X, we must use the :finder_sql option of has_many:
class Person < ActiveRecord::Base RECENT_EVENTS_CONDITION = '(subject_id = #{id} AND subject_type = \'Person\') OR (actor_type = \'Person\' AND actor_id IN (SELECT friend_id FROM relationships WHERE relationships.person_id = #{id}))' has_many :recent_events, :class_name => "TimelineEvent", :finder_sql => 'SELECT timeline_events.* FROM timeline_events WHERE ' + RECENT_EVENTS_CONDITION + ' ORDER BY timeline_events.created_at DESC', :counter_sql => 'SELECT COUNT(*) FROM timeline_events WHERE ' + RECENT_EVENTS_CONDITION end
Now we turn our attention to the user interface. How do we present this information in a nice way to the user? At giraffesoft, we do not write view tests. Views change too often for the tests to be useful. We do use Cucumber though. Anyway, do the simplest thing that could possibly work:
<%= render_timeline @person.recent_events %>
Since TimelineEvent has a field called event_type, let's use that to render a different partial.
module RenderHelper def render_timeline(events) events.map do |event| render(:partial => "timeline_events/#{event.event_type}", :object => event) end.join end end
I cannot use render :partial => events here, because all the events have the same type, namely TimelineEvent. I want to render a different partial depending on the value of event_type.
Introducing the timeline_fu Example App
The code for this article is available on github, as the timeline_fu-example application. It is a sample / starter application for rendering event feeds. Fork away!
[FLOSS Week]: timeline_fu: activity feeds made awesome
Posted by: James Golick on 2009-02-20
This release announcement is part of FLOSS week.
If you're working on a webapp these days, chances are you've needed to build an activity feed or two. There are a few approaches floating around — mostly involving observers. Not a fan of observers and needing something reusable, we built our own.
To get started with timeline_fu, run the generator.
script/generate timeline_fu && rake db:migrate
You'll get a model called TimelineEvent and the necessary migration. Then, anywhere you need to fire a timeline event, simply declare it.
class Post belongs_to :creator, :class_name => "User" fires :created, :actor => :creator, :on => :create end
This will fire a TimelineEvent called :created in an after_create callback on the Post model. It's properties will be as follows.
@post = Post.create(:creator => current_user, ...) @timeline_event.event_type #=> :created @timeline_event.actor #=> @post.creator @timeline_event.subject #=> @post
Then, to display the timeline_events, you'll need an association on your User model. We've frequently defined this as a has_many :through followed items, like how you might imagine it's implemented in the github activity feed. Then, in your dashboards/show.html.erb, you'd have something like this.
<% @user.timeline_events.each do |e| -%> <%= render :partial => "dashboards/timeline_events/#{e.event_type}", :object => e %> <% end %>
That's it! Just add fires declarations wherever you need to add something to the activity feed and the necessary templates and you're good to go.
Get It!
$ sudo gem install giraffesoft-timeline_fu
Or fork it on github.
This release announcement is part of FLOSS week. If you're interested in more open source software, consider subscribing or following us on twitter to get the next announcements asap.
[FLOSS Week]: Cliaws: Easy Command-Line Access to EC2, SQS and S3
Posted by: François Beausoleil on 2009-02-19
This release announcement is part of FLOSS week.
What if you didn't have to find and setup X.509 certificates to quickly use Amazon's EC2, SQS and S3 from your applications? Or from the command-line for that matter? Well, search no more.
$ clis3 list BUCKET BUCKET/file0 BUCKET/file1 BUCKET/file2 $ clis3 put localfile BUCKET/newfile # Get a secure URL valid for a couple of hours $ clis3 url BUCKET/newfile # Gets the content of the file, unmodified $ clis3 get BUCKET/newfile # Gets the contents of the file, but appends a single newline at the end $ clis3 cat BUCKET/newfile
$ cliec2 list DNS Name State Groups ------------------------------------------------------------------------------------------------------------------------ ec2-97-162-23-218.compute-1.amazonaws.com running app, web ec2-73-121-216-98.compute-1.amazonaws.com running db
# Create a named queue $ clisqs create giraffesoft_power Queue giraffesoft_power was created. # Push a single message to the queue $ clisqs push --data "message" giraffesoft_power Pushed 7 bytes to queue giraffesoft_power # Retrieve one message from the named queue $ clisqs pop giraffesoft_power message
Of course, this library wouldn't be complete if it wasn't also available from your Ruby code.
# Returns an array of the files available in this bucket Cliaws.s3.list "BUCKET" # Puts the File, IO stream or String to the named file Cliaws.s3.put "localfile", "BUCKET/newfile" # Retrieves the contents from S3 Cliaws.s3.get "BUCKET/newfile" # Returns an Array of Cliaws::Ec2::Instance objects Cliaws.ec2.list # Instances have interesting methods such as #running? # Push a new message to the named queue Cliaws.sqs.push "giraffesoft_power", {:adapter => "mysql", :username => "root", :password => "tada!!!"}.to_yaml # Get said message from the queue Cliaws.sqs.pop "giraffesoft_power"
Get It!
Installation could not be simpler:
$ gem install cliaws
Cliaws depends on 2 environment variables: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. Set them to the correct values before calling into the library. I have mine setup in my ~/.bashrc.
Fork Cliaws on github.
This release announcement is part of FLOSS week. If you're interested in more open source software, consider subscribing or following us on twitter to get the next announcements asap.
[FLOSS Week]: is_taggable: Tagging That Isn't on Drugs
Posted by: Daniel Haran on 2009-02-18
This release announcement is part of FLOSS week.
At last! A simple tagging implementation.
There are several others — many far more featureful. If you absolutely need a tag cloud and writing one sounds scary, is_taggable may not be for you. At least, not yet.
is_taggable is just over 100 lines of code (plus tests). It's simple and well-tested. So, extending it is easy.
So, why did we write it? We needed support for tag 'kinds'. Let's take our polyglot user example:
class User < ActiveRecord::Base is_taggable :tags, :languages end User.new :tag_list => "rails, giraffesoft", :language_list => "english, french, spanish, latin, esperanto, tlhIngan Hol"
Of course, it also supports the simplest case:
class Post < ActiveRecord::Base is_taggable end Post.new :tag_list => 'simple, sane defaults'
Get it
$ sudo gem install is_taggable
As a rails gem dependency:
config.gem 'is_taggable'
Or get the source from github:
$ git clone git://github.com/giraffesoft/is_taggable.git
(or fork it at http://github.com/giraffesoft/is_taggable)
This release announcement is part of FLOSS week. If you're interested in more open source software, consider subscribing or following us on twitter to get the next announcements asap.
[FLOSS Week]: enum_field
Posted by: Mathieu Martin on 2009-02-17
This release announcement is part of FLOSS week.
At GiraffeSoft, we love DRY code. That's why we're very quick at creating small plugins that encapsulate the way we code.
Today I'll unveil one such plugin. It's a very simple one that lets you specify an enum field for an ActiveRecord model.
The plugin of course encapsulates a standard validates_inclusion_of
class Computer < ActiveRecord::Base
validates_inclusion_of :status, :in =>
['on', 'off', 'standby', 'sleep', 'out of this world']
#...
end
But then it adds a few nifty extras that just make sense. So using the enum_field plugin:
class Computer < ActiveRecord::Base
enum_field :status,
['on', 'off', 'standby', 'sleep', 'out of this world']
#...
end
gives us a bunch useful things:
- add a validates_inclusion_of with a simple error message ("invalid #{field}")
- define the following query methods, in the name of expressive code:
- on?
- off?
- standby?
- sleep?
- out_of_this_world?
- define the Computer::STATUSES constant, which contains all acceptable values
This plugin has been known to work very well with other plugins. For example, we've used it successfully with Phusion's excellent default_value_for plugin.
class Computer < ActiveRecord::Base
enum_field :status,
['on', 'off', 'standby', 'sleep', 'out of this world']
default_value_for :status, 'off'
#...
end
If you don't like the default error message, you can of course override it with an additional :message option.
enum_field :status,
['on', 'off', 'standby', 'sleep', 'out of this world'],
:message => "incorrect status"
Get it
You can install it inside your app either as a plugin:
$ script/plugin install git://github.com/giraffesoft/enum_field.git
or as a gem, add the following line in you config/environment.rb:
config.gem "giraffesoft-enum_field", :lib => "enum_field",
:source => "http://gems.github.com"
or of course, fork it on GitHub
Conclusion
This is a good general purpose plugin to include in one's customized Rails app generator. We may add it to blank in the future, if we find we're frequently adding it to new projects.
This release announcement is part of FLOSS week. If you're interested in more open source software, consider subscribing or following us on twitter to get the next announcements asap.
[FLOSS week]: classy_resources - resource_controller for sinatra
Posted by: James Golick on 2009-02-16
This release announcement is part of FLOSS week.
Sinatra is awesome. Lightweight web services have never been easier. But, even sinatra can get a little bit tedious when you have to build three or four full resources for consumption with active resource. Not anymore, though.
Introducing Classy Resources
Classy resources adds a tiny declarative API to sinatra for building active_resource compliant REST APIs. Exposing a model is as simple as:
define_resource :posts, :member => [:get, :put, :delete],
:collection => [:get, :post],
:formats => [:xml, :json, :yaml]
The above declaration gets you a REST API, with all of the actions that active resource expects, in as many formats as you list. You can customize which actions get created by changing the contents of the :member and :collection arrays.
It's also possible to override nearly all of classy_resources' behaviours by simply overriding methods. If you're familiar with resource_controller, you'll recognize this pattern.
For example, if your classes were namespaced in a module, you'd need to override the way that resource names, like :posts, are translated in to classes. It's easy.
def class_for(resource)
MyModule.const_get(resource.to_s.singularize.classify.constantize)
end
For more overrides, see the README.
Get It
$ sudo gem install giraffesoft-classy_resources
Or fork it at github.
This release announcement is part of FLOSS week. If you're interested in more open source software, consider subscribing or following us on twitter to get the next announcements asap.
FLOSS week
Posted by: James Golick on 2009-02-16
We went over a year without even having a website. Then, we lasted a few months with a website, but no blog. That ends today, hopefully with something of a bang.
At giraffesoft, we're big believers in extracting functionality sooner rather than later. This practice has resulted in a ton of code that we use in all of our projects — nice and DRY.
Only problem is, we never get around to releasing this stuff. Starting a blog seemed like a good excuse to spend some time polishing up some code and, you know, writing READMEs.
So, starting today, we'll be releasing an open source project every day this week. They'll probably be mostly rails plugins. But, you never know. Something else might float in.
If you're interested in following along, subscribe to giraffesoft, the blog. Or, if like me, you don't really use your feed reader anymore, follow @giraffesoft on twitter or github! See you later with the first project.

