Dependency Injection with JavaScript

Dependency InjectionWhen looking through design patterns that help to decouple objects in your applications, one of the simplest techniques to use is dependency injection. This is a common practice in Backbone.js, most notably when assigning models to views, but I haven't seen it as much as I think I should. Here I'll be examining what dependency injection is, how it helps, and how I'm putting it to good use in my latest project.

What is Dependency Injection?

Dependency injection is a design pattern (often also known as Inversion of Control), where a object is given a dependency – whether through a setter method or through the constructor – rather than the object it depends on being created within itself. This technique can be used in many different situations, as evidenced by the fact that there are books written entirely about dependency injection.

In a book I recently read (Clean Code: A Handbook of Agile Software Craftsmanship – which is an amazing book to read for keeping your code clean, readable, and maintainable) it took a look at dependency injection from the point of view of constructing a hotel.

First, consider that construction is a very different process from use. As I write this, there is a new hotel under construction that I see out my window in Chicago. Today it is a bare concrete box with a construction crane and elevator bolted to the outside. The busy people there all wear hard hats and work clothes. In a year or so the hotel will be finished. The crane and elevator will be gone. The building will be clean, encased in glass window walls and attractive paint. The people working and staying there will look a lot different too.

Software systems should separate the startup process, when the application objects are constructed and the dependencies are “wired” together, from the runtime logic that takes over after startup.

Dependency Injection is one of the mechanisms we can use to create the separation that is being talked about in that quote. But how is it done, exactly? Simply create an object that something else will depend on, then create the object that will depend on it, and pass the first object to it. That wording is a bit difficult to make sense of, so let's just take a look at a quick code example that includes how it was previously done, and how to change it to use dependency injection

// Without Dependency Injection
var Foo = function() {
this.bar = new Bar();
}

var foo = new Foo();

// With Dependency Injection
var Foo = function(bar) {
this.bar = bar;
}

var bar = new Bar();
var foo = new Foo(bar);

Pretty simple. You'll notice that dependency injection requires more code. Well, pretty much anything you do to decouple code will end up with more code in the end, but it's the maintainability and flexibility that's really important. What you don't see in the example is that we don't need to use Bar. We can send in any object that follows the same interface that Foo needs it to have. If Foo doesn't use every single method from Bar, you don't even need to have the entire interface that Bar has, you just need the parts that Foo uses, thanks to the flexibility of JavaScript.

Why Dependency Injection is Useful

There are a few pretty decent reasons to use dependency injection, which I touched on a little bit already. Let's look a little more in-depth at three of the biggest reasons: Flexibility, Reusability, and Testability.

Flexibility

As I already mentioned, this method makes your objects more flexibile. They are no longer bound to that one specific class; now you can supply whatever object you want, as long as it has an interface that matches the requirements of the object that depends on it.

One thing that might not be obvious about this is that you can actually inject object that have different behaviors and/or return values from their methods, which could ultimately change the behavior of the dependent object. For example, the dependent object could be an array sorter. The object that you inject may provide the means to determine which order the array elements should be in (by telling the sorter which elements are greater/less than others), which would completely change what the sorted array would look like.

You may not need all of that flexibility, but you can never know what changes will need to be done in the future, and this setup allows you the flexibility to change more easily should this object, or the object it depends on need to change.

In Backbone, views use dependency injection to receive their models. This allows a view to show the data from any model assuming it has the same interface (some properties to display and same methods to call). The view also doesn't have to depend on a collection to pull the model from because we pass the model in ourselves.

Reusability

One of the biggest reasons object-oriented programming was created was for reusability of components. We have the ability to create objects that aren't very reusable, though, when we create them to fill very specific purposes instead of generalizing them to fit broader needs. Dependency injection can help with that.

By moving the specifics of implementations to an object that we inject, we can broaden the scope and usefulness of the object. It can be used for multiple situations depending on the injected object, rather than using a single implementation that can only fit a single purpose. Then, when we need an object to serve other similar purposes, you would end up repeating a lot of code creating a new object rather than being able to reuse the code built into the original object.

Also, since it is not fully dependent on any one class, it can be reused in a situation where the objects it would have depended on are not present. Independent objects are more portable.

Testability

I've actually been trying to get a small series on unit testing going, but I'm still learning it myself. Mike M Lin – one of the other contributors to this blog – is working on a draft for an introduction to unit testing already. But that doesn't mean we can't touch on it a bit here.

When you unit test, you want to test a single unit (hence the name), and in object-oriented programming, that generally refers to a single type or object. Without dependency injection, if a test fails, we won't know whether the problem is related to the object we are testing or one of its internal dependencies. Also, if a test passes, it might still not be working correctly, because the internal dependency may have given us the wrong answer, and then the object we're testing may have done something wrong with it, but still ended up with the correct answer due to 2 wrongs somehow making a right. Granted this is incredibly unlikely, but we don't have any real confidence that this can't happen.

If we have an object that we can inject a dependency into, we can inject a mock object (created with the unit testing framework) that can give static answers that apply to that test so that we can know that we're getting the correct answers from the internal dependency, meaning we can know for sure whether the dependent object is working correctly.

This also allows us to insert spies to make sure that the mock object is used correctly internally. Though this isn't really necessary, it can give you reassurance that everything is working exactly as you planned.

How I'm Using Dependency Injection

You may have learned a lot already, but sometimes a real-world example can really help to wrap your mind around a concept and help you understand how and when it can be used. Recently I've been working on a project. If any of you have been following me for a while you may have seen me demo my Minecraft Server Manager a while back, which I've decided to completely rebuild. The version that I showed was largely just a proof of concept. Right now, I'm working on a new version with greater capabilities, which actually required me to rewrite the majority of the application because the previous one wasn't built to scale well (like I said, it was a proof of concept). I also wanted to take advantage of a few libraries I had been introduced to since the original was made (mostly Twitter Bootstrap and Backbone.Marionette).

Anyway, on to the point: I had decided to make this application communicate between components almost entirely via global events fired from the central application object (App.vent). Because of this, nearly every single component was dependent directly on the main application object. This meant that for every component I'd test, I would have to create the actual application object and instantiate it. This caused a couple problems: tight coupling, so there's practically no way I could walk away from Marionette if I ever chose to, and testing required me to pull in the same App I was using in the actual application, which I shouldn't need to do.

So now, rather than depending directly on App, I decided that I'd pass App.vent into the constructors of the components. This allows me to pass in a mock EventAggregator for testing and allows me to make changes to the application – even removing the Event Aggregator from App entirely – without any change to the components that use it.

Conclusion

Dependency Injection is a great way to decouple objects. It creates flexibility, reusability, and easier testability and it's not difficult to do. Setting up the object may take a little more work, but that's why they invented factories. Obviously, this isn't the only way to accomplish these things, but it's definitely a great weapon to have in your arsenal. God bless and happy coding!

About the Author

Author: Joe Zim

Joe Zim

Joe Zimmerman has been doing web development ever since he found an HTML book on his dad's shelf when he was 12. Since then, JavaScript has grown in popularity and he has become passionate about it. He also loves to teach others though his blog and other popular blogs. When he's not writing code, he's spending time with his wife and children and leading them in God's Word.


  • Paul

    Joe, I am right on the verge of fully understanding everything you are talking about here… it’s exciting for me. And I am thankful that you write these articles in a way that I feel more knowledgeable after reading them.

    I am a PHP developer, and just learning js. Thanks a lot

    • http://www.joezimjs.com Joe Zimmerman

      I’m so glad that I can help. I hope you can take some of this knowledge and apply it to your knowledge of PHP too.

  • http://twitter.com/TyroneMichael Tyrone Michael Avnit

    Awesome. Been following all your tutorials on testing with Jasmine and its so refreshing to see a real-world example. Your testing and explanations are clear and concise. Thank you.

    • http://www.joezimjs.com Joe Zimmerman

      I’m glad I can help out.

  • pixelBender67

    Good stuff as always Joe!

  • http://blog.amwmedia.com Andrew Worcester

    nice write up! If anyone is interested in making use of DI and IoC in their JavaScript projects, i wrote a simple library that is available on GitHub https://github.com/amwmedia/infect.js