It’s About Sending a Message - A Focus on Scalable Object Oriented Design

A junior developer, seeing his dependent-laden classes exposed to constant changes and anticipating the cascading debugging to follow, decides it’s better to start from scratch.

It’s one thing to learn how to create an application using an object-oriented framework like Ruby on Rails.

It’s quite another to know how to create an application well, and by that, I mean that the code within an application is scalable, reusable, and flexible to change with minimal cost.

When constructing simple apps, developers new to OOD, myself once included, tend to have a class-based perspective. “I know I need this class, what should it do?” is the foundation of this mindset.

Adopting a message-based perspective, however, changes the question to, “I need to send this message, who should respond to it?”

As a concrete example, if I were to create an app for a cycling store that arranged bike trips, my initial programming might create a Trip class that responded to a customer inputting the date of the trip, the difficulty of the course, and if they needed a bike, and if so, what type of bike and to check if that bike was ready to ride.

Instead of cramming many responsibilities into a single class, focus on the message, “Should Trip class be receiving the message about the availability of bicycles? Should Trip class be receiving the message about the condition of the bicycle?” Now the idea of creating a Bicycle class or a Mechanic class becomes a logical choice.


Having a message-based perspective in OOD doesn’t make you anti-class, rather it allows you to create the appropriate amount of single-responsibility classes based on the messages passed between objects.


It’s important to delegate responsibilities in OOD. If your Trip class has methods for having a bicycle’s frame cleaned by the mechanic, tires pumped by the mechanic, chain lubed by the mechanic, and brakes checked by the mechanic, you’ve overloaded your Trip class with dependencies.

class Trip
....
def clean_bike_frame
Mechanic.new.clean_bike_frame
end
end

Trip class is dictating how your Mechanic class should act. The message Trip is telling Mechanic here is “I know what I want and I know how you do it.” Not only that, if Mechanic class were to ever change its preparation methods, Trip class would break.


A key concept in OOD is to keep the messages as abstract as possible through “Duck Typing”. For example, instead of writing such concrete methods crammed into a single Trip class, find the overarching simple message, in this case, “I want to prepare a trip.” From there, objects (i.e. classes) can collaborate without binding themselves to context and new objects can be introduced without re-tweaking every class created.

class Trip
....
def prepare(preparers)
preparers.each {|preparer|
preparer.prepare_trip(self)}
end
end
class Mechanic
def prepare_trip(trip)
trip.bicycles.each {|bicycle|
prepare_bicycle(bicycle)}
end
.... #More methods
end
class Medic
def prepare_trip(trip)
stock_medicine(trip.customers)
end
.... #More methods
end
class Driver
def prepare_trip(trip)
vehicle = trip.vehicle
gas_up(vehicle)
fill_water_tank(vehicle)
end
.... #More methods
end

As opposed to the first example, this example has Trip class telling every other class “I know what I want and I trust you to do your part.” This is a key component in OOD as there is more room for growth and for change.

If this example looks familiar, it’s because it was adapted from Sandi Metz’s work Practical Object-Oriented Design in Ruby — An Agile Primer. I read this book outside of my usual regimen of coding exercises, algorithms, and Git commits because I wanted to move beyond focusing on the quantity of my coding. Rather my focus now is on the quality of my coding; coding that is scalable, reusable, and flexible to change — coding that adheres faithfully to object oriented design.