4 Principles of Object-Oriented Thinking

June 9th, 2008

Great coding is an art. As with any art, one cultivates it primarily through practice, and only incidentally through instruction and training. Painters don’t achieve greatness simply by reading books on composition and auditing lectures on technique. They have to paint. Period. Coding is no different.

Still, it doesn’t hurt to have principles to guide practice. I stated in my last post that such principles, while sparse in the Ruby literature, are readily found in the Smalltalk canon. One example is Alec Sharp’s concise Smalltalk By Example. This book is not a manual on Smalltalk, as the title might suggest, but more a series of meditations on good coding. In a mere six pages, the chapter Object-Oriented Thinking conveys a number of essential principles. Here are some of my favorites:

1. Write Down the Concepts

Sharp advises us to “think in conceptual terms rather than worrying about the details.” He goes on: “Someone should be able to easily read the method to see what it’s doing (short methods, very descriptive names), without actually seeing any of the work done.” This is the same idea that Kent Beck communicates through his Composed Method pattern (from SBPP). Write methods that read like documentation:

def start_baseball_game
  sing_star_spangled_banner
  populate_infield_and_outfield
  send_batter_to_plate
  pitch
end

2. Put Off The Work

A related principle is that methods should be short (fewer than seven lines). One way to keep methods short is to put off the work. “Smalltalk might be considered the procrastination language - procrastinate as long as possible and maybe you won’t need to do anything.” This helps to assure that each method expresses just one concept, leading to a more object-oriented system.

3. Tell, Don’t Ask

If we want to write good, object-oriented code, we have to focus on sending messages. “Procedural code gets information then makes decisions. Object-oriented code tells objects to do things.” Instead of writing this:

def move(vehicle)
  if vehicle.is_a?(Car)
    vehicle.drive
  elsif vehicle.is_a?(Helicopter)
    vehicle.fly
  elsif vehicle.is_a?(Bicycle)
    vehicle.pedal
  end
end

We simply write:

vehicle.travel

Each vehicle knows how it’s supposed to move. Each class (Car, Helicopter, Bicycle) defines travel in the appropriate way. We don’t make decisions for the vehicle; we just tell it what to do.

4. Don’t Check the Results of Doing Things

Similarly, good object-oriented code should not check the results of sending a message. “In a Smalltalk OO system, it’s much more appropriate to just tell an object to do something, then forget about it.” How do we handle errors, then? Exceptions, of course! Writing code that elegantly raises and handles exceptions is one of the keys to clean, object-oriented code.

Conclusion

Are these observations groundbreaking? No. But they’re fundamental, and, as I said before, they don’t often appear in Ruby books. Heeding them will yield readable - even elegant - code. And in the long term, they may help us on our way in the art of coding.

One response

  1. Ramon Leon comments:

    Smalltalk didn’t originally have exceptions, they’re rather modern. It was, and still is much more common to see the error handler as part of the method call itself. Returning a dictionary lookup for example…

    ^someLookup at: #someKey ifAbsent: [ nil ]

    Thus making the error condition part of the message rather than something to be wrapped and caught. You could do something more modern like catch an exception…

    ^[someLookup at: #someKey ] on: KeyNotFoundException do: [ nil ]

    But that’s a bit ugly in comparison. Of course, both are very common and useful in different contexts.

Leave a comment