According to Wikipedia the Dependency Inversion Principle (popularized by Robert Martin) states that:

  • High-level modules should not depend upon low-level modules. Both should depend upon abstractions.
  • Abstractions should not depend upon details. Details should depend upon abstractions.

In traditional architecture “Higher” level modules depend on “lower” level modules. If we think in terms of an application with a presentation layer, an application layer, a business layer, and a data layer. The Presentation layer is the highest layer and traditionally depends directly upon and may communicate directly with the Application layer. The application layer is a higher level layer than the Business layer and traditionally depends upon and communicates directly with the business layer and so on.

Dip 1

 

When the Dependency Inversion Principle is applied this relationship is reversed. The presentation layer defines the abstractions it needs to interact with an application layer. The application layer defines the abstractions it needs from a business layer and the business layer defines the abstractions it needs from a data access layer. That is a key departure from the more classic approach, the higher layer defines the abstractions it needs to do its job and the lower layers implement those abstractions.

A strict application of the Dependency Inversion principle may even put the abstractions in the layer defining them, for example the presentation layer contains the presentation logic and application layer abstractions (abstract classes or Interfaces), and the Application assembly contains application logic and business layer abstractions and so on. In this application of the principle the Data access layer depends upon the business layer, the business layer depends upon the application layer and the application layer depends upon the presentation layer. The dependencies (references) have been inverted thus the name of the principle.

Dip 2

 

That structure above feels a little bit funky to me so in all of my projects with any complexity I usually end up with something like the following image.  Presentation, Application, Business, and DataAccess are in different assemblies.  The interfaces will be in a different assembly or assemblies as well.

Dip 3

The second part of the principle stating that abstractions should not depend upon details rather details should depend upon abstractions historically solved a potential problem with C++ whereby header files could contain both the public and private functions and member variables so in c++ this meant use a pure abstract class. In C# – a “pure” abstract class is an interface or an abstract class with zero implementation.

What I like about this principle is that if I have followed the principle throughout my code base I can test each layer in isolation by using Mocks, Fakes, test doubles etc.  Here is a super simple example.  My company is in the business of building widgets.  As a part of designing the application I have decided that I need to log information and my first requirement is that I need to be able to interact with a list of widgets transactionally.  I create an Interface assembly and add the following interfaces:

namespace Dip.Interfaces
{
    public interface IWidget
    {
        int Length { get; set; }
        int Width { get; set; }
        bool DoWork();
    }
}


namespace Dip.Interfaces
{
    public interface ILogger
    {

        //LoggingConcerns
        bool LogMessage(string message);
        bool LogMessage(string message, string callStack);

    }
}

using System.Collections.Generic;

namespace Dip.Interfaces
{
    public interface ICoordinatingService
    {
        void CoordinateTransaction(IList<IWidget> widgets);

    }
}

 

For My data access layer I will only consider logging for brevity.  I decide I need to be able to log to a database or a file so I add a new project and create 2 classes as follows:

using Dip.Interfaces;

namespace Dip.Storage
{
    public class FileLogger:ILogger
    {
        public bool LogMessage(string message)
        {
            //write to file
            return true;
        }

        public bool LogMessage(string message, string callStack)
        {
            //write to file
            return true;
        }
    }
}

using Dip.Interfaces;

namespace Dip.Storage
{
    public class DbLogger:ILogger
    {

        public bool LogMessage(string message)
        {
            //write to Database
            return true;
        }

        public bool LogMessage(string message, string callStack)
        {
            //write to Database
            return true;
        }
    }
}

So far so good, Data access only Depends on the interface assembly.

Now we add a business layer – this is typically the most important layer in that it is the layer that brings the most value to the company, tends to have the most logic, and tends to end up having the most bugs.  We again start by adding a new project then add a widget class:

using Dip.Interfaces;

namespace Dip.Business
{
    public class Widget:IWidget
    {
        ILogger log;
        //xtor injection
        public Widget(ILogger logger)
        {
            log = logger;
        }

        public bool DoWork()
        {
            //Execute business rules and log an entry
            log.LogMessage("Hello World");
            return true;
        }
        public int Length { get; set; }
        public int Width { get; set; }
        public string OtherStuffNotPersisted { get; set; }
    }
}

Notice that to construct the widget I need to supply an ILogger – this is called constructor injection.  If the entire class doesn’t need to use a logger we could only add the ILogger parameter to the methods that do need a logger – this is method injection.  Again note, the business does not reference the DataAccess layer directly – it only references the Interfaces assembly.  When I go to test the business layer I can use a mock implementation of ILogger rather than rely on a database or the file system.  This is the poer of the dependency inversion principle.

Continuing on we add our application layer.  This layer tends to coordinate interactions between existing business objects and maybe take care of transactions:

using Dip.Interfaces;
using System.Collections.Generic;

namespace Dip.ApplicationService
{
    public class CoordinatingService : ICoordinatingService 
    {
        ILogger log;
        public CoordinatingService(ILogger logger)
        {
            log = logger;
        }

        public void CoordinateTransaction(IList<IWidget> widgets)
        {
            //Begin Transaction
            foreach(var item in widgets)
            {
                item.DoWork();
            }
            //Commit...
        }

    }
}

Again, we are using constructor injection to get our ILogger.  In fact we are only relying on IWidget and ILogger so this layer can be tested with mock versions of those objects and thus be tested in isolation

Now we move to the UI – I just used an MVC 4 project for this.  Add a controller and I am breaking the dependency inversion principle on purpose here:

using Dip.ApplicationService;
using Dip.Business;
using Dip.Interfaces;
using Dip.Storage;
using System.Collections.Generic;
using System.Web.Mvc;

namespace Dip.UI.Controllers
{
    public class WidgetController : Controller
    {
        //
        // GET: /Widget/

        public ActionResult Index()
        {
            
            //Call the service layer for this
            var service = new CoordinatingService(new DbLogger());
            //Normally this would be Extracted from the request
            service.CoordinateTransaction(new List<IWidget>{
                new Widget(new DbLogger()){Length=3,Width=4},
                new Widget(new DbLogger()){Length=5,Width=6}
            });

            var model = "success";

            //Send model to view   
            return View(model);
        }

    }
}

How did I break the rule here?  Several ways – I am referencing Application, business, and the data access assemblies directly and instantiating those items right in the controller.  Why did I do this?  Because the dependency Inversion Principle does not tell us how to resolve dependencies it is used to guide us in a design that allows us to better test our software in isolation.  The above solution will allow us to test the application and business layers in isolation.  If we want to test our data access layer in isolation we would need to refactor and better use interfaces or we would have to rely on the Microsoft Shim framework to intercept calls to the database and file system and return some predictable and repeatable results.  With this design we have basically said “the UI layer is untestable in isolation” and that may be good enough or that may be considered a fatal flaw.  How might we change the design of the UI layer to follow the dependency inversion principle?  That is a topic for another post but here is a hint, use a dependency injection container.  With this solution we will add a constructor to the controller that accepts an ILogger and ICoordinatingService parameter.  Additionally we will want to use a creational pattern which will (using interfaces) expose a method that returns a Widget via the IWidget interface and add that “factory” interface as a parameter to the constructor of the controller as well.