Which principle was it? Open-closed or dependency inversion?

In my last blog entry I discussed how Test Driven Development (TDD) lead me to a greater understanding of the Open-Closed Principle (OCP). The general feedback from the post was very positive. However, several readers asked a question that I would like to answer. They pointed out that although I was discussing OCP, my example really displayed the Dependency Inversion Principle (DIP). Was my blog post misleading?

Just to recap, here is the example I used in the previous post:

testDefault(self):
  member = Member("test member")
  membership_list = MembershipList()
  membership_list.add_member(member)
  command = GetMembershipListCommand(membership_list)
  result = command.execute()
  self.assertEqual(["test member"], result)

This is a simple test for my “GetMembershipCommand” function. When I realized that I didn’t like the coupling created between my test function and the other production classes in my project, I altered the test to this:

test Default(self):
  command = GetMembershipListCommand(DummyList())
  result = command.execute()
  self.assertEqual(["test member"], result)

The dependency inversion principle states:

High level modules should not depend upon low level modules. Both should depend upon abstractions.

In my example, I clearly used the dependency inversion principle. My GetMembershipListCommand no longer depends on the lower level Member and MembershipList classes – it only depends on the interface. But does that mean I missed the point of OCP? I don’t think so.

OCP is about the flexibility of your classes, not a specific implementation pattern. Can you construct a class for which the implementation can stay constant, even though you can extend the behavior? What might these techniques be?

  • Most examples I have seen focus on sub-classing the parent class and overriding methods
  • I claim that OCP is achieved in my example above by injecting classes with behaviors to the parent class
  • I have also built classes to which behaviors and extensions are passed directly as functions or command classes

No matter which of these techniques I use, I know one thing to be true: although the base class’ implementation has not changed, its behavior has been extended through these techniques.

In a recent podcast with Scott Hanselman, Robert Martin reviewed the SOLID principles. One point that Martin made is that the dependency inversion principle (DIP) is basically a restatement of OCP with “a 90 degree rotation”.  OCP states the goal of not having to modify a class to extend behavior. DIP provides an implementation guideline that we should depend on abstract classes as much as possible.

I clearly used dependency injection to modify the behavior of the classes being tested. TDD showed me where I wasn’t using techniques like dependency injection to easily and thoroughly test my objects. My effort resulted in classes that satisfy the open-closed principle.  It was very satisfying to see multiple principles converge on the single goal of clean code.

So what do you think? Is my definition of the open-closed principle on the mark or too liberal?

Advertisement

4 Responses to Which principle was it? Open-closed or dependency inversion?

  1. To me, OCP has always seemed like a direct effect of adherence to the other SOLID principles. Kinda the inverse of testability, OCP is a litmus test of the flexibility and extensibility of your design rather than a guide to achieving that flexibility and extensibility.

    I’m probably wrong, but that’s how I see it.

  2. Brian Button recently posited on Twitter:

    OCP in 6 words – Structure systems around abstractions, not concretions

    To which Robert Martin replied:

    That’s also a reasonable definition of DIP.

    So no, you’re not alone in thinking that there’s some heavy overlap here. :)

  3. I’ve been reading Robert Martin’s “Agile software development” book, and found myself struggling over the difference between OCP and DIP. No matter which way I looked at it, they both always seemed to converge on the same solution i.e. use abstractions rather than direct dependence. The statement you posted, i.e. “OCP states the goal of not having to modify a class to extend behavior. DIP provides an implementation guideline that we should depend on abstract classes as much as possible.” clears up a lot. Thanks.

  4. ..and I just had an epiphany, and realized that the STL “for_each” may be another example where OCP seems to apply without the use of base class interfaces; different functors can inject behavior (as you term) it, to perform different tasks, without changing the for_each() library code itself.

    Of course, you could argue that even though dynamic polymorphism through a base class isn’t being used here to adhere to an interface, we are in a sense using static polymorphism to enforce the template contract (i.e. for the functor being passed in), but still….

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s