Dependency Inversion: ‘Abstraction’ Does Not Mean ‘Interface’

A coworker recently asked if we should always abstract every object into an interface in order to fulfill the Dependency Inversion Principle (DIP). The question stunned me at first, honestly. I knew in my head that this was a bad idea – abstracting into interfaces for the sake of abstraction leads down the path of needless complexity. However, I wasn’t able to clearly answer his question with specific examples of when you would not want to do this, at the time. I’ve been thinking about this for a few days now and I think I have a good, albeit very long winded, answer.

Before the question is answered, though, we need to step back and look at what DIP is all about. I’ve previously shown how to implement DIP and talked about why it’s beneficial, so I won’t be repeating that here. Rather, I want to talk about the language that describes DIP and what it really means.

Robert Martin’s original definition of DIP is this:

A. High level modules should not depend upon low level modules. Both should depend upon abstractions.
B. Abstractions should not depend upon details. Details should depend upon abstractions.

The word ‘abstraction’ is used three times in the definition for DIP. So, in order to understand DIP, we have to first understand some of the basics of Abstraction.

Some Background On Abstraction

From Wikipedia (emphasis mine):

“In computer science, abstraction is a mechanism and practice to reduce and factor out details so that one can focus on a few concepts at a time”

I can’t say it any better than this.

Abstraction can very directly lead to a system that is more understandable by helping us ignore the detail and implementation specifics, allowing us to focus on something at a higher level. This reduction in cognitive load can benefit someone that is reading the code by not forcing them to know the detail immediately. Additionally, abstraction is a form of encapsulation or information hiding, which again helps us to reduce cognitive load and produce better systems. From Wikipedia’s entry on Information Hiding:

“In computer science, the principle of information hiding is the hiding of design decisions in a computer program that are most likely to change, thus protecting other parts of the program from change if the design decision is changed.”

At the heart of abstraction and information hiding, we find the ability to change the system. The ability to change is an absolute requirement in software development and produces good design that is easier to work with, modify, and put back together as needed. The inability to change is directly called “bad design” by Robert Martin, in the DIP article.

Applying Abstraction And Encapsulation To DIP

So how does our knowledge of abstraction and information hiding play into DIP?

First and foremost, DIP never states that we should depend on explicit interfaces. Yes, in C# we have an explicit Interface as a form of abstraction. It is a separation of the implementation detail from the publicly available methods, properties, etc, of a class. Some languages, such as C++, don’t have an explicit construct for interfaces, though. From Robert Martin’s original DIP article, again:

“In C++ however, there is no separation between interface and implementation. Rather, in C++, the separation is between the definition of the class and the definition of its member functions.”

A String As An Abstraction

Abstraction does always mean explicit interface constructs, as evidenced in C++. Nor does it always mean an abstract base class, which we also have available in .NET. In fact, languages such as Ruby don’t really need either of these constructs. The duck-type nature of Ruby allows an implementation to be replaced at any point, without any special constructs. In .NET, though, there are a number of abstraction forms that we can rely on, explicitly. We have the obvious interfaces and base classes (abstract or not) – but we also have constructs like delegates and lambda expressions, and even the simple types that are built into the base class library.

Let’s look at a simple string to illustrate abstraction. As I said in my SOLID presentation at ADNUG, we can invert our dependency on database connection information.  Rather than putting a connection string directly into our code that calls the database, we can use the string as our dependency and our abstraction. All we need to do is follow the basic DIP principle and provide the string as a parameter to the class that calls the database. We certainly don’t need (or want, for that matter) to introduce a new interface or base class at this point. Our abstraction is simple enough to use a common type found in the .NET framework.

Other Forms Of Abstraction

Even if we are talking about an object, who says that the interface we are depending on has to be an explicit interface construct or base class? When I write a Domain Service that uses an Entity from my Domain, I don’t create an explicit interface for that Entity. Rather, I use the Entity’s inherent interface – it’s public methods, properties, etc.

I also use delegates on a regular basis. By specifying my abstraction as a delegate, I can further decouple the depending object from the dependant code that it needs to call. I’d be willing to bet you have used delegates as abstractions as well. Have you ever created an event handler for something like a button click? There’s a delegate’s abstraction at work.

Abstract Judgement

The point is, there is not always a need to introduce an explicit interface or base class when inverting our dependencies. We still need to apply dependency inversion and provide our implementation as a constructor parameter (or setter, though I don’t like setter injection). But, that dependency doesn’t have to be anything more than the interface inherent to the object, or a simple type found in .NET.

You do have to be careful when making the call to not use an explicit abstraction with DIP, though. You can quickly turn your system into a ball of mud if you rely on a concrete class that is not intention revealing or well encapsulated to begin with. At the same time, too many abstractions can lead to needless complexity and make it very difficult to see the big picture of a system. Too few abstractions, though, will certainly lead to a rigid, immobile design that is hard to change. All of these problems are equally vicious – and I’ve been bitten by all of them in recent months.  It takes good judgement calls to determine when you do and do not need an explicit abstraction for a dependency. Unfortunately, good judgement comes from experience and experience comes from bad judgement. Don’t be afraid to make bad decisions – make a decision, just be sure you can reverse that decision as easily as possible.


Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Derick Bailey

Derick Bailey is an entrepreneur, problem solver (and creator? :P ), software developer, screecaster, writer, blogger, speaker and technology leader in central Texas (north of Austin). He runs SignalLeaf.com - the amazingly awesome podcast audio hosting service that everyone should be using, and WatchMeCode.net where he throws down the JavaScript gauntlets to get you up to speed. He has been a professional software developer since the late 90's, and has been writing code since the late 80's. Find me on twitter: @derickbailey, @mutedsolutions, @backbonejsclass Find me on the web: SignalLeaf, WatchMeCode, Kendo UI blog, MarionetteJS, My Github profile, On Google+.
This entry was posted in .NET, Agile, Analysis and Design, Domain Driven Design, Lambda Expressions, Philosophy of Software, Principles and Patterns, Refactoring. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://mbrownchicago.spaces.live.com Mike Brown

    Good article, however the idea that C++ does not separate interface from implementation is incorrect. I can define an interface as a class with only pure virtual functions.

    The implementation would be in a separate class that inherits from that base.

  • http://www.lostechies.com/blogs/derickbailey derick.bailey

    @Mike

    That’s an abstract base class in C++, not an explicit interface construct like we have in C#. In a C# interface all methods and properties defined a inherently abstract (pure virtual) and it’s not possible to provide any implementation directly in the definition. We also have abstract base classes that can do exactly the same thing, with the option of providing an implementation in the definition – the same way C++ does it.

    It’s a very minor difference (and is somewhat irrelevant, really), but it is a difference.

  • http://mbrownchicago.spaces.live.com Mike Brown

    Yes I get your point that C# provides an explicit “Interface” construct. But it is possible to separate interface from implementation in C++ (if your base class has only pure virtual functions with no implementation it is in essence defining an interface).

    “In C++ however, there is no separation between interface and implementation. Rather, in C++, the separation is between the definition of the class and the definition of its member functions.”

    Your quote from Robert Martin makes it sound like this is impossible to do in C++ which is false.

  • http://www.infusion.com Kyle Szklenski

    @both of you:

    Actually, Derick has it slightly wrong, and so does Mike. The methods and properties in a C# interface are not pure virtual. Pure virtual in C++ allows any derived class to override it, regardless of where it shows up in the inheritance chain. In C#, you cannot override a method from an interface without also implementing that interface yourself for a derived class. Consider this setup: You have an interface called interface1, an implementing class call class1 which implements interface1, and a derived class called class2, which derives from class1. C# will not let you override the methods from interface1 without explicitly making them virtual in class1. It’s legal to do that, so you CAN achieve something similar with interfaces in C#, but it’s not out of the box, so to speak.

    On the other hand, Derick is correct in that C++ interface is nothing like a C# interface. In C++, even if you make a class with all pure virtual functions, you can still supply a default implementation for those functions. It would be relatively stupid to, but you can do it. Furthermore, as I mentioned before, regardless of which classes implement which methods in between in an inheritance chain in C++, you can always override any inherited method in a derived class, I believe. I haven’t written that kind of C++ code recently, but it seems to my memory that that’s how it works. Basically, a C++ “interface” is an interface in name only, whereas a C# interface truly enforces the idea of the interface.

    Having written that book, I agree that it’s a minor difference and mostly irrelevant!

  • http://www.lostechies.com/blogs/derickbailey derick.bailey

    @Mike

    “Your quote from Robert Martin makes it sound like this is impossible to do in C++ which is false.”

    I agree that this sounds wrong, after re-reading my quote. I think I missed a few of the contextual lines around it. I’ll have to correct that.

    @Kyle,

    Excellent insight! Thank you.

    We can do pure virtual interfaces in C# – though it is limited to the interface construct. Interface1 can be inherited by Interface2, and Interface2 does not have to “forward” the virtualization of Interface1. It happens automatically.

    public interface Interface1
    {
    public void Foo();
    }

    public interface Interface2: Interface1
    {
    public void Bar();
    }

    Interface2 has now two methods: Foo() and Bar()

  • http://www.infusion.com Kyle Szklenski

    Hm, interesting point. I suppose my only recourse would be to say that we can’t really think of that as virtual because you can’t supply overrides of the function in the “derived” interfaces. That recourse sounds a little weak though. I’ll think about it some more. Have a good one!