A Brief History of Dependency Injection

Reading Time: 10 minutes

If your new to Dependency Injection and wondering what it is and why so many use it in their projects, then it might help to start from the beginning with a brief history of Dependency Injection. It all started with the new keyword a long long time ago …

A Brief History Of Dependency Injection

Renowned theoretical physicist/cosmologist Stephen Hawking wrote a best selling book called “A Brief History Of Time” where he actually wrote only one equation throughout the entire book; the famous e=mc^2. I have been inspired to attempt something similar in which I will from my perspective, give a historical overview of how we got to where we are today in regards to Dependency Injection.

I will lean heavily on the Spring Framework for the latter part of this post since it is the most widely know and documented Dependency Injection Framework out there (no hating please).  Some would agree that history is written by the victors – however honorable mentions to Google Guice are made (and yes there are more but that’s not the point of this post).

If you want to know more about how Google Guice works, you can check my Google Guice YouTube Playlist Tutorial Below…

Java Before Dependency Injection

We all know the new keyword, it’s what breaths life into our applications by actually creating the objects we know and love. Let me take an example were we instantiate a Satellite Object and pass in its name to the constructor.

It’s obviously easy to create such an object but we’re not just creating something as simple as a Value Object here, we’re creating something much more complex. Whether its a Satellite, Car, House, Company etc … the point is that we still have much more work to do to ensure the Object is properly constructed in order for it to be useful.

We should definitely add some useful sub-systems to our Satellite like Power, Attitude Control, Communications, Thermal etc … Lets take it just one step further by adding some of the those sub-systems.

Notice how it’s starting to get much more involved to create our Object? We haven’t even covered all the sub-systems yet. Not only that but we haven’t really properly constructed the sub-systems either. I simplified each sub-system in order to make the example fit nicely over a few lines – there goes my only 1 equation – sorry Mr. Hawkings.

The point I’m trying to make is that although you can create all your objects yourself, you may get to a point that its just too complex of an object to create more than once across your application. Don’t forget that you’ll need to create other instances for your tests as well.

Although you have full control, you also have full responsibility (insert spiderman catchphrase here). The other thing to notice is that every time you use the new keyword, you are tightly coupling your code to an implementation.

Nothing says “implementation” more than the new keyword

Also, the responsibility of object creation is now mixed throughout your code base therefore making it much harder to maintain it. If ever you change the way your object gets created in the future, you’ll have to track down every place you created the object and change it – that goes for your tests as well.

Don’t worry though, it didn’t take long until the next evolutionary stage in the timeline took place to address this.

Creational Design Patterns

Design patterns had already been around for some time and the most popular book at the time (The Bible if you will) about them was published in 1994 called “Design Patterns: Elements of Reusable Object-Oriented Software” by these 4 Gurus which went by the name of the GoF (Gang of Four) – I always wanted to be part of a gang with a intimidating  name.

These patterns were used to alleviate the pain points mentioned above and best practices were implemented in Java which followed this advice. Although there are several categories of design patterns, the Creational category is the one which relates the most to the topic at hand. It includes the …

  • Singleton Pattern
  • Factory Pattern
  • Abstract Factory Pattern
  • Prototype Pattern
  • Builder Pattern

Each  pattern addresses a different use case for creating objects but in the end all of them aim to do it in a way that limits that responsibility of creating objects to a Factory Class.

This permitted  us to remove the  new keyword from the client code and displace it into these factories. We created  a separation of concern which improved …

  • Our ability to change the implementation past into out client code, thus making it more maintainable and flexible
  • The testability of our application (much easier to mock out the dependencies). More on this latter

If we were to use our Satellite example with a Factory Pattern, it would in concept look something like this (shorthand code for concept sake).

Using The Factories in Client Code

With all these Factories, we had to find a way to use them in our client code. Several ways were devised, some instantiated them directly via the new  keyword – but aren’t we suppose  to stop using new in the Client code? Hmm, well doing this in the main() method is acceptable but your on the right track!

Many others used static methods like getInstance off the factories instead which did not require you to use new on the Factory.

Factories were springing up everywhere and many developers didn’t fancy creating lots of factories and passing them over to their client code as declared dependencies in Constructors and/or setters.  Sure we had a better abstraction but maintaining all these factories and manually injecting them everywhere was sooo late 90’s – boring!

Thus the timeline moves on but in my opinion we moved one step back before moving two steps forward. We still had to learn some important lessons and were missing a bit of glue to truly separate the object creation graph and the execution call graph.

Godzilla Context Factories to the Rescue

In the very early 2000’s we started being introduced to Huge factories with names similar to Context, Locator, Registers  etc .. (J2EE was famous and mostly responsible for this). This allowed us to get a hold of many objects via just one of these factories – kind of like a genie in a bottle.

But it was not just J2EE but many of us that took this route in our own development since after all, they we setting the standard to follow.

J2EE (Today known as Java EE) pretty much had the monopoly on the Java Enterprise space and so we really didn’t have lots of options. Learning J2EE was really difficult and confusing, even writing a simple “hello world” example was challenging – I’m serious. Today, things are very much improved in Java EE, thanks to the many competing frameworks that sprung out throughout 2002-2007.

J2EE influenced many of us to follow suit in our own designs (live and learn). All you had to do was find a way to get a hold of the massive ‘know-it-all‘ factory and your Class had pretty much global access to many other Objects – most of which you didn’t need.

This  made it easier to instantiate the Object which many choose to do via an empty Constructor but secretly they were using the great big Godzilla Factory internally (no one wants to see Godzilla right?). This caused the following problems …

  • Testability suffered because there were no seams which allowed you to mock out your dependencies. Testing was not the big priority on everyone’s mind as it is today and it showed in the API designs.
  • No transparency on what the Object’s Collaborators were since they were secretly accessed in Constructors and/or methods. Javadoc was useless, you had to dive into the code to see the ugly truth.
  • Re-usability of a Class in another Project was a nightmare as you had to bring in every dependency theses factories referenced on the class path, even if you didn’t need them.

Here’s an example of an Objects constructor accessing this global accessible state (was and still is common to see this)  …

The issue was the we were still interacting with the Factory too much and asking for the wrong thing. Instead of asking for things directly (i.e: CollaboratorZ), we were asking for them indirectly via these massive Factories. We didn’t have an easy to use, lightweight framework in place to facilitate all that – yet. However, some smart people got sick of all this and things started to change.

The Dawn of The Dependency Injection Frameworks

Lightweight solutions started cropping up to fill the gap in about 2003. I’m sure you’ve at least heard about the Spring Framework. Google Guice was another but it was not made public until around 2007 (used internally at Google before).

In a nutshell, these and other DI frameworks act as factories, meaning that you don’t code or maintain the factory code anymore. Great! this was one less responsibility to be concerned about – dull and repetitive code to write anyways.  All you had to do was register the objects you wanted instantiated with  the DI framework so that it would know how to produce it. Then you simply asked the framework to inject it for you in your client code where ever you requested it.

From here on in, I’ll put specific emphasis on the Spring Framework (DI capabilities).

First Swing at it via XML

The first way many of us registered our objects was with XML. Spring facilitated this via the <bean> XML element to define the objects we wanted it to manage for us in its Factory. This configuration was external from your client code.

The above XML registers the Radarsat2 Class as a Spring Bean (now under Springs control) and provides the instructions on how to instantiate the Radarsat2 Object and its collaborators via the constructor – known as Constructor DI. The client code would eventually ask the framework to inject the dependency. It looked something like this (requesting it by id) ..

It wasn’t perfect but it was a huge step forward because it was a lightweight solution as compared to the alternative at the time (yes J2EE, I’m talking about you!). This now could be done with POJO’s (Plain Old Java Objects) which had no dependencies to any heavy weight Container infrastructure and could be re-used in other projects – it was non intrusive and it caught on like wild fire.

The issue with XML was that eventually it became too verbose, boilerplate’ish (that a word?) and you ended up with too many XML files – for a real project. Don’t get me started on the whole human-readable thing either. Finding out how things were wired via XML became a challenge for complicated object graphs, visualization tools did help however I ran into some visualizations that I had a good laugh at over the years.

Second Swing at it via Annotations

Annotations officially come out in JDK 1.5 and frameworks like Spring started incorporating them into their next generation design of DI. Finally, we now had  a level of indirection between the client code and the Context Object. Now we simply asked for things we wanted without going through the factory (the glue had arrived).

The @Autowired annotation from Spring (or @Inject from Guice) helped speed up the development process. It was a clean and self documenting way to declaratively have your dependencies injected in your Constructor, setters or even fields. The example above is asking the Spring DI Framework to provide the constructor with an object of Type Power which had already been registered as a Spring Bean.

Although we were still free to use XML to register them we now had another way via Annotations. All you had to do was sprinkle the  @Component annotation on your POJO and boom! it was scanned by the Spring Container and registered as a Spring Bean.

Inversion of Control

So you see, here the DI framework codes the factory for you and also performs the new on the Object you are requesting via @Autowired. Then it hands it over to you, fully constructed and initialized – that in short is Dependency Injection. You have a dependency on something and the DI framework provides it.

You are not in control of performing these responsibilities anymore, something else is … the DI framework. The control has been inverted from you to it,  hence where the term IoC comes from- Inversion of Control. That’s the way I like to explain it.

The way I see it, adhering to the Law Of Demeter was also easier. This helped out immensely with testing and having a clear indication of who the Objects Collaborators were.

Nothing is perfect for everyone though. Some  preferred to have all their DI configuration separated from their code base (like the XML was) instead of scattered throughout the code base with annotations everywhere -fair game. Also the ability to make programmatic decisions on what was injected was not available (i.e: On Tuesday inject this implementation).

Third Swing at it via pure Java Code

Eventually we were able to instruct Spring how to build our Objects via pure Java code – this was coined JavaConfig (Google Guice went this route from the start). I remember being surprised at first because it felt that we had gone 360 degrees right back to were we started from! What was the point of going back to coding all this stuff again? I didn’t know about Google Guice at the time and so this was really a new way of thinking for me.

Defining your dependencies via Java Code actually turned out to be a great idea. You were still not writing the factory code but just expressing how to construct your Objects to the DI Container in plain Java code which was really natural. The big idea was that this code was external to your client code (just as the XML was) so that solved the first issue.

The other issue it solved was that you could make programmatic decisions based on what ever criteria you had in mind because it was Java code – just add an if statement.

Here’s a small example using JavaConfig – which needs the @Configuration annotation. Your Spring Beans (the objects you wanted Spring to instantiate/manage) went in methods annotated with @Bean who’s id by default was the name of the method.

The next time you used @Autowired on a dependency of Type Satellite in your client code, you would get the object created by the radarsat2 method since the DI container provided that type. It was nice to be back in Java World were we were free to express ourselves, escape XML hell and externalize the DI configuration.

I have to admit, I resisted it at first but now I almost exclusively just use JavaConfig when using Spring for DI.

Summary

What’s important to notice is that almost all the new operators now belong in the factories maintained by these DI frameworks – they take care of the Object creation graph. Once your application starts, the DI framework injects/wires the dependencies your client code has requested.

Now that the application has been wired up, it then starts its execution call graph. If you keep those two graphs separated,  you’ll be better off for it as you’ll be able to change the wiring/behavior of your application easily and improve its testability.

There you have it, a history lesson from my point of view on how we started off and came to the dependency injection world. Although there are many other small details that’s the gist of it.

2 Replies to “A Brief History of Dependency Injection”

Comments are closed.