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

by michael on January 29, 2009 · 4 comments

in Editorial

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:

   1: testDefault(self):
   2:     member = Member("test member")
   3:     membership_list = MembershipList()
   4:     membership_list.add_member(member)
   5:     command = GetMembershipListCommand(membership_list)
   6:     result = command.execute()
   7:     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:

   1: test Default(self):
   2:     command = GetMembershipListCommand(DummyList())
   3:     result = command.execute()
   4:     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?

{ 4 comments }

Zac January 29, 2009 at 1:57 pm

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.

Matt Campbell January 29, 2009 at 2:57 pm

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. :)

zyle May 10, 2009 at 11:32 am

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.

zyle May 10, 2009 at 11:56 am

..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….

Comments on this entry are closed.

Previous post: (Unintentional) Startup Humor – or – It Seemed Like a Great Idea

Next post: Clouds for the Military – A Linchpin Technology