2007 / August 7th/ Skeleton Classes
Here’s a quick tip to help you keep your OO code clean and modular: create skeleton classes as you work through your projects. Most people that start off with OO really just end up putting a giant procedural function in a class initialization method and call it good.
I understand the frustration because when separating out your methods, you’ve got two choices:
- Put it all in one method, re-factor at a later time.
- Try and juggle the cascade of methods in the air and hope you catch them all
The old way
Here’s a quick example. We want to create a Dog class, and upon initialization the dog should learn a few tricks when he’s clicked.
The HTML
<a href="fido.html" id="fido" title="Fido loves bones">Fido</a>
Procedural Class
var Dog = new Class({
initialize: function(element){
this.element = $(element);
if (!this.element) return;
// Set his name and description
this.name = this.element.innerHTML;
this.description = this.element.getAttribute('title');
// Teach him how to sit and speak
// SIT
this.element.addEvent('mouseover', function(){
$(this).setOpacity(0.5);
});
this.element.addEvent('mouseout', function(){
$(this).setOpacity(1.0)
});
// SPEAK
var name = this.name;
this.element.addEvent('click', function(){
alert(name + ": Bark!");
});
}
});
var fido = new Dog('fido');
Now this code does exactly what we want it to do, functionally. But it’s not very elegant, and it certainly isn’t modular. What if we wanted to call fido.sit()? We couldn’t how it is currently written. What we really want to do is separate out this functionality so we can call specific tricks, and have them separate from the events (mouseover, click).
But we face a problem when we’re first authoring this class: how do we add in all the architecture for all these methods we want to write: initialize, sit, stand, bark, learn? In order to write the initialize method, we need sit, stand, speak, learn to be written: and to write these, we need the initialize method to be written. The solution is skeleton out the methods.
The new way
Step 1: Create a skeleton
var Dog = new Class({
initialize: function(element){
this.element = $(element);
if (!this.element) return;
// Set his name and description
this.name = this.element.innerHTML;
this.description = this.element.getAttribute('title');
// Teach him how to sit and speak
this.learn('mouseover', this.sit);
this.learn('mouseout', this.stand);
this.learn('click', this.speak);
// After we type these, go ahead and fill in skeleton methods shown below
// Do 50 more lines of initialization stuff
},
learn: function(eventName, trick){
// TODO: fill in Dog#learn
},
sit: function(element){
// TODO: fill in Dog#sit
},
stand: function(element){
// TODO: fill in Dog#stand
},
speak: function(element){
// TODO: fill in Dog#speak
}
});
var fido = new Dog('fido');
Now we have a nice structure for our class, with clean methods that we can fill in later. We know we need to fill them in: but maybe we need to do some more initialization actions for the time being. (We’re also using the TODO bundle in TextMate. More info on that here).
Step 2: Work your way through the skeleton
var Dog = new Class({
initialize: function(element){
this.element = $(element);
if (!this.element) return;
// Set his name and description
this.name = this.element.innerHTML;
this.description = this.element.getAttribute('title');
// Teach him how to sit and speak
this.learn('mouseover', this.sit);
this.learn('mouseout', this.stand);
this.learn('click', this.speak);
// Do 50 more lines of initialization stuff
},
learn: function(eventName, trick){
this.element.addEvent(eventName, trick);
},
sit: function(e){
$(this).setOpacity(0.5);
},
stand: function(e){
$(this).setOpacity(0.5);
},
speak: function(e){
alert(name + ": Bark!");
if (e) (new Event(e)).stop();
}
});
var fido = new Dog('fido');
Wrap up
Using skeletons to outline your code can help you create much better architected code. You can sit back and worry about the structure, then worry about the functionality. I’ve also found it’s a great way to get your hands dirty with a project. Creating a skeleton is a lot less commitment than writing actual code, but once you get going, you’ll see lots of little tasks instead of one impossible one.
Once you get comfortable with this method, you can start writing comments on what these skeleton methods should accept as input, and what they should output too. For example:
// Input should be the anchor element being clicked, title of pop up, and description of pop up
var test = function(element, title, description){
// TODO: fill in test
// output: should return true or false depending on success
}
Don’t forget this doesn’t just apply to Javascript or OO — it can be used in any coding out there. Enjoy!
3 Comments
Make a Comment
don’t be afraid, it’s just text

Warpspire is the place that web professional Kyle Neath writes about the web. 



August 8th | #
Very nifty. Also using the same naming structure for all your classes helps in the long run so when you are up to your knees in classes and you need to figure out what the “getter/setter” for this specific object is without going back to the source file itself.
August 8th | #
I would suggest, when writing skeletons, that you also take the opportunity to heavily document the functions, even if it’s just with comments above the signature. It will keep the code readable and keep you from forgetting exactly what the function needs to take care of.
August 9th | #
Caleb’s point is an excellent one, and in fact I’d argue it’s probably the biggest advantage of skeleton classes. By documenting beforehand, you can have a clear outline of what your method is supposed to do before you even write it, so that if you have to expand what it does, you can critically look at your original intentions and decide whether another method is needed.
Moreover, bear in mind that skeleton classes are basically the level right above the UML class diagram — the difference being that you’re looking at it in code rather than as a drawing. Test-first strategies, by the way, bring some similar advantages, namely in allowing you to exercise your API before you write it so you get a better feel for how it will work.