How did I Get Here?

My original introduction to the Dependency Inversion Principle came from Robert (Uncle Bob) Martin around 1994. It, along with most of the SOLID principles, is simple to state but deep in its application. What follows are some recent applications I've used on real projects; everything I discuss is in production from June 2012 and as of mid 2013 is still in production. Some of these go further back in time, but keep coming back, which is a reminder to me that the basics remain important.

Synopsis of the DIP There are many ways to express the dependency inversion principle: Abstractions should not depend on details

Code should depend on things that are at the same or higher level of abstraction

High level policy should not depend on low level details

Capture low-level dependencies in domain-relevant abstractions The common thread throughout all of these is about the view from one part of your system to anther; strive to have dependencies move towards higher-level (closer to your domain) abstractions.

Domain Analysis: Problem with Platonic Idealism I was formally introduced to domain analysis in the early '90s. The first source that strongly influenced me was Object-Oriented Development: The Fusion Method. Back then, I did domain analysis independent of the problem under consideration. Later that decade I slowly came to the conclusion that domain analysis works better if you consider the problem. Why? Because ultimately everything is related to everything else in multiple ways. Domain analysis is a form of Modeling. A key thing about modeling, at least for me, is that you are only considering details that are important. How do you decide what is important? Only consider parts of a domain that are relevant to what you need to accomplish. There's a chicken-egg problem here. The domain is informed by the problem and vice versa. The system boundary also comes into play. To handle these all of these interdependencies, we triangulate. As we start to get a better idea of the problem, the domain and the system boundary, we're in a better position to consider the appropriateness of any particular abstraction. Throughout this article, when I mention domain, I mean a domain limited by some feature set rather than a mythical domain that exists outside of such context. In a sense, this is YAGNI applied to domain analysis.

Why care about dependencies? A dependency is a risk. For example, if my system requires a Java Runtime Environment (JRE) to be installed and one is not installed, my system will not work. My system also probably requires some kind of Operating System. If users access the system via the web, it requires the user to have a browser. Some of these dependencies you control or limit, others you can ignore. For example, In the case of the JRE requirement, you could make sure the deployment environment has an appropriate version of the JRE installed. Alternatively, if the environment is fixed, you might adjust the code to match the JRE. You could control the environment using a tool like Puppet to build up an environment from a simpler, known starting image. In any case, while the consequence is severe, it's well understood with several options to mitigate it. (My personal preference leans towards the CD end of the spectrum.)

When your system uses the String class, you probably do not invert that dependency. You could, for example if you think of String as a primitive (strictly not, but close enough), then manipulating a number of Strings starts to resemble Primitive Obsession. If you introduce a type around the Strings, and add methods that make sense to your use of the those Strings, rather than simply exposing String methods, that starts to look like a kind of Dependency Inversion, so long as the resulting type is closer to your domain than a String.

In the case of browsers, if you want a modern experience it will be hard to support all browsers. You can try to allow all browsers and versions, limit support to relatively modern browsers or introduce feature degradation. This kind of dependency is complex and probably requires a multi-faceted approach to solve. Dependencies represent risk. Handling that risk has some cost. Through experience, trial and error, or the collective wisdom of a team, you choose to explicitly mitigate that risk, or not.

Inversion compared to what? Inversion is a reversal of direction, but reversal compared to what? The design part of Structured Analysis and Design. In structured analysis and design, we start with a high-level problem and break it up into smaller parts. For any of those smaller parts that are still "too big", we continue breaking them up. The high-level concept / requirement / problem is broken up into smaller and smaller parts. The high-level design is described in terms of these smaller and smaller parts and therefore it directly depends on the smaller, and more detailed, parts. This is also known as top-down design. Consider this problem description (somewhat idealized and cleansed, but otherwise something found in the wild): Report Energy Savings Gather Data Open Connection Execute Sql Translate ResultSet Calculate Baseline Determine Baseline Group Project Time-sequence Data Calculate Across Date Range Product Report Determine Non-Baseline group Project Time-sequence Data Calculate Across Data range Calculate Delta from Baseline Format Results The business requirement of reporting on energy savings depends on gathering data, which depends on executing Sql. Notice that the dependencies follow how the problem is decomposed. The more detailed something is, the more likely it will change. We have a high-level idea depending on something that is likely to change. Additionally, the steps are extremely sensitive to changes at the higher levels, which is a problem since requirements tend to change. We want to invert dependencies relative to that kind of decomposition. Contrast that to bottom-up composition. You could find the logical concepts that exist in the domain and combine them to accomplish the high-level goal. For example, we have a number of things using power, we'll call those Consumers. We don't know much about them, so we'll get to them via a Consumer Repository. We have something called a Baseline in our domain, something needs to determine that. Consumers can calculate their Energy usage and then we can compare the energy used by the Baseline versus all of the Consumers to determine Energy Savings: Figure 1: Bottoms Up While the work we do could initially be the same, in this re-envisioning there's an opportunity, with a little more work, to introduce different ways to accomplish the details: Switch out the repository for a different storage mechanism, there's no mention of SQL in its interface so we can use an in-memory solution, a NoSql solution or a RESTful service.

Instead of constructing a baseline, use an Abstract factory. That will provide support for multiple kinds of baseline calculations, which actually reflects the reality of a particular domain. As you read this you might notice that there's some notion of the Open Closed Principle in all of this. It's certainly related. Initially, break your problem into logical blocks suggested by your domain. As your system grows, use these blocks or extend them in some way to accommodate additional scenarios.

What Does That all Mean? Pragmatics on Principles Before getting into examples, I want to give you my current (circa mid 2013) perspective on design principles, the following of which are is often considered a "best practice": I am not a fan of "best practices", but I do like good ideas for a given context

I think design principles Should be "violated" sometimes Are often at odds with each other Often mix together for something even better than when used in isolation Often overlap with other ones

There are no free lunches, all abstractions have a cost In fact, like the term "best practices" I wonder if "design principles" even makes sense as a moniker. In the case of the SOLID principles, I think of them more as up front ideas that I often come back to due to familiarity. I often fall back into the basics like cohesion and coupling, adding another level of indirection. By calling something a principle, when I'm pragmatic I will probably violate a principle. A colleague prefers to replace "principle" with guideline. That fits for me as well. Whether we call something a principle or a guideline, the ability to make an informed decision to disregard a design principle (a so-called Journeyman behavior according to The Seven Stages of Expertise in Software), is a good place to strive towards. Where the DIP refers to abstractions, I've noticed many people confuse abstraction with: An interface

An abstract base class

Something given as a constraint (e.g., external system architecture)

Something called a requirement, which is stated as a solution In fact, any of these can be misleading: An interface — Have a look at java.sql.Connection, compare your business domain to methods like getAutoCommit() , createStatement() and getHoldability() . While these might be reasonable for a database connection, how do these relate to something a user of your system wants to do? The connection is tenuous at best.

, and . While these might be reasonable for a database connection, how do these relate to something a user of your system wants to do? The connection is tenuous at best. An abstract base class — An abstract base class has the same problems as an interface. If the methods make sense to your domain, it might be OK. If the methods make sense to a software library, maybe not. For example, consider java.util.AbstractList. Imagine a domain with an ever-increasing ordered listing of historical events. In this hypothetical domain, it never makes sense to remove() an item from the historical record. The List abstraction, because it solves a general problem and not your problem, offers at least this one feature that does not make sense for your domain. You can subclass AbstractList (or some other List class), but doing so still exposes a method (probably several) that does not make sense for your use of that class. As soon as you give in and allow clients to see unnecessary methods, you probably violate both the DIP and the Liskov Substitution Principle.

an item from the historical record. The List abstraction, because it solves a general problem and not your problem, offers at least this one feature that does not make sense for your domain. You can subclass AbstractList (or some other List class), but doing so still exposes a method (probably several) that does not make sense for your use of that class. As soon as you give in and allow clients to see unnecessary methods, you probably violate both the DIP and the Liskov Substitution Principle. A constraint/requirement — When we are given work to do, does that work provide the motivation and goals or does it talk about how to solve the problem? Does your requirement talk about having to use message oriented middle-ware for integration, or which database fields to update to finish the work? Even if you are given a description of the goals for an actor, do those goals simply restate the current as-is process, where you could build a system that obviated the need for those processed in the first place?

You mean Dependency Inversion, Right? Refactoring versus factoring When Martin talks about refactoring, he is talking about a practice done after the fact. YAGNI dictates doing as little as possible until you know you need something. When you do know, e.g., it's given as a constraint, then instead of refactoring, we can factor it using these design principles. Is there a place for factoring in addition to refactoring? Does YAGNI suggest no? I think there is some place for factoring to avoid refactoring. As I start looking into a problem, I am doing classical analysis. Breaking down a complex domain into something I can digest, guided by design principles such as SRP or DIP, is factoring. Where the domain is not well understood, I'd do well to follow YAGNI. YAGNI is about avoiding speculative design. Unnecessary factoring will lead to unnecessary work. When you do apply design principles earlier, strive to do so in the context of your problem's domain to avoid YAGNI violations. In 2004, Martin Fowler published an article on Dependency Injection (DI) and Inversion of Control (IoC) . Is the DIP the same as DI, or IoC? No, but they play nice together. When Robert Martin first discussed the DIP, he equated it a first-class combination of the Open Closed Principle and the and the Liskov Substitution Principle, important enough to warrant its own name. Here's a synopsis of all three terms using some examples: Dependency Injection Dependency Injection is about how one object knows about another, dependent object. For example, in Monopoly a player rolls a pair of dice. Imagine a software player that needs to send the roll() message to a software pair of dice. How does the player object get a reference to the dice object? Imagine the game tells the player to takeATurn(:Dice) and gives the payer the dice. The game telling a player to take a turn and passing the dice is an example of method level dependency injection. Imagine a system where the Player class expresses a need for Dice instead and it gets auto-wired by some kind of so-called IoC container like Spring. A recent example of this is in the system I'm working as of Q1, 2013. It involves the use of Spring profiles. We have 4 named profiles: demo, test, qa, prod. The default profile is demo, which brings the system up configured with 10 simulated devices and certain test points enabled. The test profile brings the system up with no simulated devices and the test points enabled. Both qa and prod bring the system up such that the system connects to real devices over a cellular network and test points are not loaded, meaning if a production component attempts to use the test point, the system will fail to start. One more example comes from an application that involved mixing Java and C++. If the system is started via a JVM, then it is configured to simulate the C++ layer. If it is instead started via C++, which then starts the JVM, then the system is configured to hit the C++ layer. These are all kinds of dependency injection.

Inversion of Control Inversion of control is about who initiates messages. Does your code call into a framework, or does it plug something into a framework, and then the framework calls back? This is also referred to as Hollywood's Law; don't call me, I'll call you. For example, when you create a ButtonListener for Swing, you provide an implementation of an interface. When the button is pressed, Swing notices that and calls back into the code you provided. Imagine the Monopoly system created with a number of players. The game orchestrates interaction between players. When it's time to have a player take a turn, the game might ask the player if it has any pre-movement actions such as selling houses or hotels, then the game will move the player based on the roll of the dice (in the real world, a physical player rolls dice and moves his or her token, but that's an artifact of the board game not being a computer - that is, it's a phenomenological description of what's going on rather than an ontological description). Notice that the game knows when a player can make decisions and prompts the player accordingly, rather than the player making the decision. As a final example, a Spring Message bean or a JEE Message Bean is an implementation of an interface registered with the container. When a message arrives on a Queue, the container calls into the bean to process the message, the container will even remove the message or not based on the response of the bean.

Dependency Inversion Principle Dependence Inversion is about the shape of the object upon which the code depends. How does DIP relate to IoC and DI? Consider what happens if you use DI to inject a low-abstraction dependency? For example, I could use DI to inject a JDBC connection into a Monopoly game so it could use a SQL statement to read the Monopoly board from DB2. While this is an example of DI, it is an example of injecting a (probably) problematic dependency as it exists at an abstraction level significantly lower than the domain of my problem. In the case of Monopoly, it was created several decades before SQL databases existed, so to couple it to a SQL database introduces an unnecessary, incidental dependency. A better thing to inject into Monopoly is a Board Repository. The interface of such a repository is appropriate to the domain of Monopoly rather than described in terms of a SQL connection. As IoC is about who initiates a calling sequence, a poorly designed callback interface might force low-level details (framework) details into code you write to plug into a framework. If that's the case, try to keep most of the business stuff out of the callback method and in a POJO instead.

DI is about how one object acquires a dependency. When a dependency is provided externally, then the system is using DI. IoC is about who initiates the call. If your code initiates a call, it is not IoC, if the container/system/library calls back into code that you provided it, is it IoC. DIP, on the other hand, is about the level of the abstraction in the messages sent from your code to the thing it is calling. To be sure, using DI or IoC with DIP tends to be more expressive, powerful and domain-aligned, but they are about different dimensions, or forces, in an overall problem. DI is about wiring, IoC is about direction, and DIP is about shape.