When 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.
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 ﬁnished. 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
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
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.
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.
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.
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.
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.
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!