Skip to content

Instantly share code, notes, and snippets.

@arwagner
Created March 26, 2012 01:28
Show Gist options
  • Save arwagner/2202072 to your computer and use it in GitHub Desktop.
Save arwagner/2202072 to your computer and use it in GitHub Desktop.
Recumbent bicycles
class Recumbent < Bicycle
attr_reader :flag
def post_initialize(args)
@flat = args[:flag]
end
def local_spares
{flag: flag}
end
def default_chain
'9-speed'
end
def default_tire_size
'28'
end
end
@arwagner
Copy link
Author

I'm hoping I reproduced this faithfully; I apologize if not.

At one point in your talk, you refactored the Bicycle base class so that you could rewrite Recumbent this way instead of the previous revision. The key point here was to eliminate the call to super, so that Recumbent didn't have to have that knowledge about its base class.

What I can't get my head around is this: I feel like having to define post_initialize, and know the particular signature and semantics it should have, is also knowledge about the base class. It seems like trading one dependency for another, and I haven't grasped why this is better than the other.

@skmetz
Copy link

skmetz commented Mar 26, 2012

Imagine that when you stand inside of any class you can't see out, ie, you can only know things about the class you're in. What follows thinks of MountainBikes from this point of view.

Ask yourself, 'What does MountainBike know". In the case above, MountainBIke doesn't explicitly know anything about any object outside of itself. It sends no messages so it doesn't even know that any other objects exist. It's passive; it offers up its own specializations when asked but requires no external context.

The only thing MountainBike needs from it's environment is a Bicycle class to inherit from, but even that dependency is fairly loose. If MountainBike were changed to be a subclass of Object this class would still be useable, exactly as it is, by some other object that wanted to know about MountainBike specializations.

BIcycle contains two things. An algorithm (feeble though it may be) and the template methods (hook methods are just a kind of template method). Bicycle should own (be in sole control of and be the only object that has knowledge of) the algorithm. We want to be able to change this algorithm and have subclasses magically inherit the new behavior. Bicycle sends template methods to invite subclasses to fill in specializations.

In the code above Bicycle and MountainBike are coupled, you are right, but the coupling is very loose. Bicyclish things (ie, subclasses) have an api, an agreed upon way to share their specializations. The BIcycle class uses this api to ask for specializations. This api is that only thing that can change in such a way as to force a change on MountainBike, and it is very stable, so it might never actually change.

The coupling between Bicycle and MountainBike is this close.
Bicycle................................................MountainBike

Contrast this with the previous example that overrode spares and within it, sent super. In that version of the code
MountainBike knew:

  • It's own specializations
  • a part of the algorithm (the spares method)
  • that it has some kind of relationship with another object such that its own spares method needs to invoke the other object's spares method.
  • that super spares returns a hash

In this case
The coupling between Bicycle and MountainBike is this close.
Bicycle......MountainBike

If Bicycle changes the name of the spares method or it's return type, MountainBike (and every other subclass) will be forced to change.

It all boils down to how much an object knows about other objects. In the code above, MountainBike knows very little about Bicycle. If Bicycle is written such that MountainBike has to override spares and send super, it's forced to know a lot more. It is this knowledge that couples the objects and raises risks.

@arwagner
Copy link
Author

Ok, I think I get this now. I like the idea of thinking about what you can see from inside a class. And also the way you describe the "space between objects". You have an excellent way with words!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment