
There is no arguing that the platform-agnostic nature of web applications is one major advantage they have over their native counterparts. Developers and designers have always aspired to reach users on a multitude of devices and contexts using the same codebase, and we’re almost there thanks to the web technology we have at our disposal today.
On the flip side, the versatility of web applications comes at a price as we transition from the traditional mouse and keyboard input setup to touch-based interactions. Our present day interfaces are optimized for the former, rarely taking into account the rise of touch as a natural interaction that may soon overtake other input methods as the de facto standard. Designing web interfaces that cater to both worlds is not an afterthought; it’s a non-trivial challenge that requires careful planning from the early stages of the design process.
Most web interfaces nowadays are designed based on the premise that users will be interacting with them using a mouse and a keyboard. While that may still hold true for the most part, there is a clear trend where users are increasingly expecting web interfaces to work just as fine on touch-enabled devices. Unless you build a native application and explicitly redirect your users to it, there is little you can do to prevent them from using your web interface on an iPad and getting frustrated along the way.
That is to say that optimizing your web app for touch is critical if you value your users and strive to offer them the best experience regardless of the device they’re using.
Here is a non-exhaustive list of the most essential points to keep in mind when designing for touch.
Hover states are the bread and butter of present day web interfaces, and they do a remarkable job at decluttering the interface and leveraging the mouse as a pointing device. Notwithstanding, the absence of an equivalent state in touch input renders hover interactions ineffective: unless the same interaction can be performed using single taps, avoid using hovers in the key areas of your application.
Unlike the mouse cursor, our fingers were not designed for pixel precise pointing; touch targets (buttons, links, controls, etc) should be large enough to prevent input errors and the frustration they cause users. The rule of thumb (pun intended) is to make your touch targets no smaller than roughly 1cm in either dimension. In pixels, this value would vary depending on the density of the screen. It is roughly equivalent to 60px on the original iPhone and 120px on retina devices. Even though Apple recommends a 44x44pt target size (roughly 7x7mm) in its iPhone HIG , most studies suggest that the average human fingertip is 16-20mm in diameter and a 10-11mm touch target is the absolute minimum. Regardless of these discrepancies, making touch targets large enough without compromising the native feel of the interface is key to a great user experience.
Beside their dimensions, the positioning and spacing of touch targets equally affect the overall usability of the interface. Fitts’ law holds even more true in touch-centric interfaces since moving fingers around to reach dispersed targets may prove more tedious than doing so with a mouse. Place related controls and navigation elements close enough to each other such as they require minimal finger and wrist movement to be reached. For good measure, leave 1-2mm (3-6px on 72dpi screens) between adjacent targets to make them easier to hit, especially when one or more of them break the 1cm rule.
Most touch-optimized browsers force a delay (300ms) on single taps to make sure that the user didn’t intend to double tap or perform a gesture. While this can be useful in interfaces that rely heavily on gestures, it is a nuisance in most cases as it makes the application feel less responsive. Make your UI elements respond to touch events using Javascript as detailed here and here.
It goes without saying that designing web interfaces which work with various input methods calls for significant compromises, which in turn may result in a sub-optimal experience across the board. Lacking a sane way to detect input methods in the browser, there is little we can do besides fine-tuning the interactions on our web apps to preserve their main functionality on touch-enabled devices.
Photo credits: Blake Patterson
The latest big ActiveRecord feature to Rails has been polymorphic associations. Not very clear at first, I found out they’re easier to understand with a couple examples.
A common one:
class Person < ActiveRecord::Base
has_one :address, :as => :addressable
end
class Company < ActiveRecord::Base
has_one :address, :as => :addressable
end
class Address < ActiveRecord::Base
belongs_to :addressable, :polymorphic => true
end
This basically allows the address class to belongs_to any model. Which is nice, the alternative would be to say:
class Address < ActiveRecord::Base
belongs_to :person
belongs_to :company
end
Then you’d have all these foreign keys in your addresses table but you only would ever have a value for one of them because an address can only belong to a person or a company but not both.
OK that was the basics.
Now the rails docs refer to the as keyword parameter to has_one and has_many as specifying a “polymorphic interface.” What is that?
When I think”polymorphic interface”, I think something along the lines of the << message in Ruby. I can send that message to a bunch of different objects like arrays, strings, IO streams, etc. and they all know what to do when they receive it.
I think << as a kind of interface that all those different classes implement. From a statically typed language standpoint, such as Java, it would be as if we had a nice little hierarchy of classes all implementing a common interface.
Pretending Java allowed operator overloading and << was an operator it might look like this.
public interface Collection {
Collection <<(Object anObject);
}
And the classes.
public class Array implements Collection {
public Collection << (Object object) {
// add object to me
}
}
public class String implements Collection {
public Collection << (Object object) {
// add object to me
}
}
Where am I going with this? Stay with me here.
Lets rotate the class diagram for the Person, Company, and Address 90 degrees to the left (I dont know how to draw that here but if you write it out on paper you’ll see what I mean) and make Person and Company inherit from Address.
class Address < ActiveRecord::Base
end
class Person < Address
end
class Company < Address
end
Now neither a Person nor a Company are an Address so lets instead use that “polymorphic interface” as our superclass name.
class Addressable < ActiveRecord::Base
end
class Person < Addressable
end
class Company < Addressable
end
That’s better. A Person and a Company are addressable but what happened to the Address class.
class Addressable < ActiveRecord::Base
has_one :address
end
There we go. Now Person and Company has_one address, they inherit it from Addressable, and no polymorphic associations.
But wait, inheritance? More specifically in the Rails world, “single-table inheritance” (STI) ? Let’s pretend a Person and a Company have very little state in common; what does using (STI) give us? It’s gives us a giant table with a lot of empty columns for the Company attributes when the row is a Person and a lot of empty columns for the Person attributes when the row is a Company.
I don’t like it.
As more Addressable’s come into the system that table is going to get bigger and bigger. To me using Addressable makes sense, inheritance is about behavior and not about state and if I was modeling without thinking about a database I probably would of first came up with using the Addressable class.
What can we conclude? We can say that STI is basically a way to map an inheritance inhierarchy for a bunch of classes that have a lot of common state not behavior.
Now there are other ways to map an inheritance hierarchy to a relational database. In fact there’s 3 commonly used ones. Rails only gives us the simplest one STI.
For the 2nd one it won’t work. But that last one “One Table per Class” is interesting.
Back to our Person, Company, and Addressable example.
If we mapped each of those classes to its own table what would or database look like?
addressables (id)
people (id, name, age, height, weight, addressable_id)
companies (id, size, established_date, addressable_id)
addresses (id, street, city, state, addressable_id)
Hmmm. We get to use the nice heirarchy that uses behavior to model inheritance with Addressable as our superclass and we don’t have to put all the subclasses into their own table. So we got rid of that big ugly STI table with all those empty columns. When reading a Person from the database, we’d do a join to Person’s superclass table addressables on addressable_id. And to read a Person’s address we’d do a join to addresses on addressable_id.
So we eliminated polymorphic associations and replaced them with inheritance, assuming rails supported our inheritance mapping scheme of “One Table per Class”, which it doesn’t but lets keep going. And I like our heirarchy, a Person is Addressable, a Company is Addressable it reads nice and logical. One beef. What’s the deal with that addressables table? A table with one column. That’s weird. For now, mark it down as a disadvantage and some ugliness with this method.
But wait. Here comes another feature. Users now want to be able tag people and companies. We could use the Rails plugin acts_as_taggable, which uses polymorphic associations. Let’s not and keep running with this to see where it takes us.
A Taggable class sounds good. But wait. Ruby doesn’t allow multiple inheritance and it doesn’t have the Java/C# equivalent of interfaces. Ruby uses modules instead. OK so we screwed up. We should of modeled Addressable as a module and not a class. I say we didn’t screw up - we modeled that because that’s what the current requirements were; we didnt know tagging was coming. That’s another agile story.
Anyway, let’s try using modules.
module Addressable
end
module Taggable
end
class Person < ActiveRecord::Base
include Addressable
include Taggable
end
class Company < ActiveRecord::Base
include Addressable
include Taggable
end
There that’s better now Addresses and Companyies are both addressable and taggable.
module Addressable
has_one :address
end
Wait, we can’t do that in Rails. OK how about this.
module Addressable
def self.included(klazz) # klazz is that class object that included this module
klazz.class_eval do
has_one :address
end
end
end
There now, each class that includes the Addressable module has_one Address. Hold up. What would our database look like?
addresses (id, street, city, state, person_id, company_id)
Oh no, we’re back to where we started. An Address can’t belongs_to a Person and a Company at the same time. We need polymorphic associations.
Wow, that was a trip. What did we learn. At first we started out using polymorphic associations. Then we decided to refactor and try modeling in what i’d call “the more natural way” using inheritance and Addressable and Taggable classes. But we eventually got burnt when a Person and a Company both needed to be Taggable as well. So we used Ruby’s version of interfaces/multiple inheritance by using modules. And that got us right back to where we started
The moral of the story is this because Rails only allows you to map inheritance heirarchies using STI plus Ruby’s lack of “interfaces we can’t model using interface like classes like Addressable” and Taggable. Instead we use polymorphic associations and let them use that “polymorphic interface” for the name of the association:
class Address < ActiveRecord::Base
# here's where we'll use Addressable
belongs_to :addressable, :polymorphic => true
end
class Tagging < ActiveRecord::Base
# here's where we'll use Taggable
belongs_to :taggable, :polymorphic => true
end
I like modeling using interfaces such as Addressable and Taggable. I really like the following Java classes.
public interface Addressable {
Address getAddress ();
void setAddress (Address address);
}
public class Address {
private String street;
private String city;
private State state;
private Zipcode zipcode;
private Addressable addressable; // anyone who implements Addressable
// various getters and setters, etc.
}
public class Person implements Addressable {
private Address address;
public Address getAddress () {
return address;
}
public void setAddress (Address address) {
this.address = address;
}
}
public class Company implements Addressable {
private Address address;
public Address getAddress () {
return address;
}
public void setAddress (Address address) {
this.address = address;
}
}
And for Taggable
public interface Taggable {
Collection getTaggings ();
}
public class Tagging {
private Taggable taggable; // anyone who implements Taggable
private Tag tag;
// various getters/setters, etc.
}
public class Person implements Addressable, Taggable {
// Addressable implementation from above
private Collection taggings;
public Collection getTaggings () {
return taggings;
}
}
public class Company implements Addressable, Taggable {
// Addressable implementation from above
private Collection taggings;
public Collection getTaggings () {
return taggings;
}
}
In Object-relational mapping (ORM) libraries in the Java/.Net world they provide all 3 inheritance mapping schemes whereas in Rails you only get STI.
Were the other 2 inheritance mapping schemes too “enterprise” for Rails? Too complicated for DHH to implement? Nah, Ruby’s lack of interfaces make the other 2 schemes not as powerful as in languages that support interfaces e.g. like in the above example Addressable worked fine, but the minute we introduced Taggable i.e. another “interface” we were done for.
And Rails form of “polymorphic associations” aren’t found in Java/.Net object-relational mapping libraries as well. Of course not, Ruby’s use of modules as a form of multiple inheritance required something unique, “polymorphic associations” are that something. Look at the source for the popular acts_as_taggable plugin. It uses polymorphic associations and it uses modules to include in any shared behavior such as instance and classes methods. This is nice. You call acts_as_taggable in your class definition and you get all this behavior for free.
I’m sorry, but I miss my interfaces. Looking at the above Java code, you might say “yeah but look at that Addressable and Taggable implementation in the Person and Company classes its exactly the same, its not DRY. In Ruby with modules you’d only have to implement that once and just include it into the Person and Company classes”. That’s true but if someone decides to change that module it might break classes that include it - that’s another story something called the “brittle base class”. I also like the fact that its explicit, its duplicated but I can see the code in both the Person and Company classes, no messing around in RAILS_ROOT/vendor/plugins.
Well if you made it through that you’re just as crazy as I am. But I’m scoring this one a point for Java/C#. Ruby usually dominates but being able to use those Java/C# interfaces just seem more natural and better to me. And the fact that Rails’ polymorphic associations are a new thing, there’s definitely a source of confusion around them in the Rails community.
Detect emerging problems in your codebase with. We’ll deliver solutions for fixing them, and demonstrate techniques for building a Ruby on Rails application that will be fun to work on for years to come.