Skip to content

Instantly share code, notes, and snippets.

@nateberkopec
Created January 11, 2013 15:50
Show Gist options
  • Save nateberkopec/4511691 to your computer and use it in GitHub Desktop.
Save nateberkopec/4511691 to your computer and use it in GitHub Desktop.
sandi metz from parley
.....................
First, the setup:
What problem are we're trying to solve? I'd call it coupling and I'll use the example from poodr to describe my take on it.
When Gear knows the name of Wheel, Wheel is a bit glued into Gear. Imagine that Gear has a gear_inches method that needs to get a Wheel's diameter.
def gear_inches
ratio * Wheel.new(rim, tire).diameter
end
In this example, Wheel is coupled to Gear.
When is this bad?
Most obviously, if Wheel's name changes you have to change the reference to it in Gear. (very small deal)
However, consider this. Imagine another class of round things appears, say Cylinder. Cylinders have a diameter so in some kind of role-playing Diameterizable way they should be substitutable for Wheels. However, Gear cannot calculate the gear_inches of a Cylinder because it is stuck to Wheel. Gear knows about the Wheel class AND about the diameter message, but it could do its job just fine if it knew only the message.
That ends the code example, but before I start voicing an opinion, I'll add one more idea to the setup. I proposed the rule 'Don't refer to the name of a class inside another class". Really? How seriously do I mean that?
.....................
Now, on to opinion.
As I understand the ongoing discussion, there are two schools of thought:
a) Leave the code as it is, allowing the coupling between Wheel and Gear until such time as Cylinder appears.
b) Inject Wheel into Gear right now, loosen the coupling from the start.
If both Wheel and Cylinder currently exist, I imagine that everyone would agree that the object should be injected into Gear. My perception is that this dispute is not about dependency injection, it's about when it's use saves money.
I see a lot of strong opinions but they all seem to boil down to something like ... Well, I've had this personal experience when writing the code I write for the applications I work on, and it leads me to say that you should always|sometimes|never inject dependencies in this situation.
Please don't be offended by that characterization, I freely admit that I am biased by my background and experience and stand firmly in the camp of 'you should sometimes inject the dependency' in case b above. Why do I say this? Well, I certainly don't have any scientific proof, my experience just tells me this is so, and I use my judgement on a case by case basis to make the call. If I choose to inject this dependency in this case at this time for this app, it's not because I'm enamored with DI, it's because my experience tells me it will save me money.
When I choose to inject the dependency, it's usually because the specification sounds something like this: Well, we're sure we'll have gears, and definitely wheels, and the back office is kicking around the idea of other round things. We don't really know what we want so we'd like for you to write the app and show us, and then we'll tell you how to change it.
While only you know your application and your customers, to me this specification cries out for loose coupling. I have lived to regret ignoring this kind of information. I don't 'make up' the need for flexibility but when my customers tell me they need it, I've learned to write code that can flex.
I love science and could be swayed by data and I wish we had some to guide our behavior around this issue. Till then, we're stuck with our opinions.
My clearest take-home from this discussion is that it's definitely worth knowing what DI is and how to use it, and that you should both listen to the 'experts' and pay attention to your own experience, and develop your own opinion about how early to reach for decoupling. There is no universal right or wrong here.
Ok, although I have failed miserably in keeping the length of this email to that of a reasonable method, I'll say one final thing about "Don't refer to the name of a class inside another class". I originally meant something more like "Don't refer to the name of one of your application's classes inside another of your application's classes". This would force you to always inject dependencies on your own object (though I must admit that now I want to inject CSV). There are applications for which this makes sense, but even if you're not working on one, it's an experiment from which you can learn things that give you a more informed, and more defensible, opinion.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment