Trending
Opinion: How will Project 2025 impact game developers?
The Heritage Foundation's manifesto for the possible next administration could do great harm to many, including large portions of the game development community.
Featured Blog | This community-written post highlights the best of what the game industry has to offer. Read more like it on the Game Developer Blogs or learn how to Submit Your Own Blog Post
Dependency Injection practice could be awkward to follow using the framework Unity provides. In this article I will talk about some alternatives and specifically about my implementation of an Inversion Of Control container designed around Unity.
Note: this article is now outdated, if you get here, you should read the updated version:
http://www.sebaslab.com/ioc-container-for-unity3d-part-1/
http://www.sebaslab.com/ioc-container-for-unity3d-part-2/
http://www.sebaslab.com/the-truth-behind-inversion-of-control-part-i-dependency-injection/
http://www.sebaslab.com/the-truth-behind-inversion-of-control-part-ii-inversion-of-control/
http://www.sebaslab.com/the-truth-behind-inversion-of-control-part-iii-entity-component-systems/
Unity is a very good game development tool, although while I like most of the features (and trust me it is very hard to make me happy), the code framework is still awkward to use.
Let me explain why I say awkward. Unity is born as rapid application development tool and due to its nature, it has been soon adopted by many “indie” developers. However Unity is now trying to make a leap forward toward the triple A development, but while the company is mainly focusing on adding new editor features, there aren’t many news about the framework itself, which code design is currently too much “one-man band” oriented.
The considerations in this article do not really apply to simple projects or projects developed by one or two persons. For these specific cases, Unity is perfect. The arguments in this article apply instead to medium-big projects developed by a medium-big size team.
I will not talk about all the flaws I found, but I will focus on specifically one, that is how awkward is injecting dependencies inside Unity entities.
To be clear, a dependency is defined as an object needed to another object to execute its code. If a class A needs the instance of a class B to execute its code, B is a dependency for A.
Unity is based on a modern concept of “Entity Framework”. Out there several implementations of entity framework exist and I am even creating one myself. Entity framework is a very powerful concept and has many advantages: pushes the users to favor composition over inheritance, keep the classes small and clean focusing on single responsibilities, promotes modularity. This is in a perfect world…
In Unity, the Entites are called GameObjects and the Components are based on MonoBehaviour implementations. Personally I have some golden rules I want to follow when I implement MonoBehaviours for GameObjects:
MonoBehaviours should always operate on the GameObjects where they are attached to.
MonoBehaviours are reusable, single responsibility classes.
GameObjects should not be created without a view (that would be a mesh, collider or something that is really an entity in the game, the only exceptions are for empty GameObjects used as “folders” and other specific cases I will illustrate another time).
MonoBehaviours can know other components on the same GameObject using GetComponent.
The behaviour of a GameObject should be extended adding MonoBehaviours instead of adding methods to a single MonoBehaviour.
The problem is, as many of you know already, that Unity does not really allow to follow most of these rules because of the way the dependencies must be solved. In fact what happens if a component needs to communicate with other classes? Let’s say there is a Level class and, for some reasons, this class must know the monsters that are still alive. When a monster dies, how is it possible to communicate the fact to the Level object?
Currently there are 3 simple solutions to this problem:
Level is a Monobehaviour created inside a GameObject that has no view. All the monsters will look for the Level class using the GameObject.Find call inside the Start or Awake functions.
Level is a Singleton.
Like 1, but Level is found through Object.FindObjectOfType.
Howbeit, I reckon there are problems in following all the three possible solutions:
The first solution breaks my golden rules, which would be not a big issue since they are actually more guidelines for good design. Instead the real problem is the use of GameObject.Find. GameObject.Find is one of the example of how awkward the Unity Framework is for big project development.
What happens if someone in the team decide to rename the GameObject? Should be imposed that the GameObjects, once created, must not be renamed (or deleted) anymore? GameObject.Find can lead to several run-time errors that cannot be caught in compiling time. This scenario could be really hard to manage when dozens and dozens of GameObjects are searched through this function.
Singleton is a controversial argument since the pattern has been invented. I am personally against the use of Singleton. However if you ask me why I am against the Singleton I will not answer you with the usual answers (break encapsulation, dependencies hiding, many issues to test the code through unit test, being bound to the implementation of a service instead of its abstraction), but with the hindsight of the practice: your code will become a big pile of crap after a while. This is because Singleton does not involve any design constriction that, while make apparently the coder life easier, will make it a hell later on, when the classes design becomes an incomprehensible blob of code without a structured flow.
How should the Level object be injected inside the Monster class then? There is actually a third solution that is calling the function Object.FindObjectOfType. But, what is FindObjectOfType? Object.FindObjectOfType could be seen as a wrong implementation of the Service Locator Pattern, with the difference that it is not possible to abstract the implementation of the service from its interface. This is another problem of Unity framework, Unity seems to hate the concept of interface. Interface is the most powerful concept at the core of every well designed code. Instead to push the coders to use interfaces, Unity pushes the coder to uses Monobehaviour, even when the use of Monobehaviour is not necessary.
Mainly there are 3 ways to resolve dependencies: using the Service Locator pattern, injecting dependency manually through constructor or setter and using an Inversion Of Control container. I do not like to use the Service Locator Pattern because the SLP itself is a singleton (or a static class) and this could lead to some severe limitations compared to the IoC container solution. However using an IoC container in Unity is not simple because Unity does not specify a place where the application can be initialized.
Explain what an Inversion of Control container is needs probably another article, so I will be simple with it. An IoC container is a…..container that contains the dependencies that must be injected. It is called IoC because the design is created in such a way that the objects are never created by the user (in fact you can also forget the use of the new keyword), but they are lazily created by the container when they are requested.
There are several IoC containers out there, a lot written in c# as well, but practically no one works in Unity and most of all, they are damn complicated. For these reasons I decided to create an IoC container for Unity trying to keep it as simple as possible. Actually creating a basic IoC container is pretty straightforward and everybody can do it, my implementation has just a few tweaks that makes it simple to use with Unity projects.
Before to discuss the example I built on purpose to show the features of the framework, I want to share with you my experience with the IoC containers I used before to write mine.
As pure game developer, IoC container was a weird concept to me, although I probably used Inversion of Control without knowing what it was and what it was called.
When I was introduced to the concept of Dependency Injection and all the problems related to it, the IoC container was among the most used solutions. That’s why, when I shifted from traditional C++ programming to actionscript game development, I started to use Robotlegs. Robotlegs is an actionscript IoC Container.
After I used it for a couple of small personal projects, I decided to abandon it. This is because eventually I ended up convincing myself that manual Dependency Injection through setter and getters was a better practice.
However after some time, when I moved to C#, I started to experiment with Ninject and discuss the practices with its author.
As result of these discussions I realized that I was not appreciating the use of an IoC container because I did not understand its principles.
The most important concept to understand is the Composition Root. The Composition Root often coincides with the application entry point, but in practice it is the place where the IoC container must be initialized before everything else starts to use it. Since an application could use more IoC containers, it could have more composition roots as well.
When your classes design is created (without using singletons), your classes start to form a graph of dependencies. Let’s say that there is a class A and a class B, then there is a class C that uses A and a class D that uses B and C. This waterfall of dependencies is called Object Graph.
Now, as long as the objects do not need to be created after the application has been initialized, all the dependencies can be solved right at the begin of your application, within the Composition Root context.
This is very important to understand, in fact my first error was to inject the container itself inside the objects to be able to fill their dependencies that I used to create explicitly using the new keyword.
The rule instead is that the container should be explicitly used only in the Composition Root. Exceptions, most of the time, mean that there is something wrong in the design.
In our example the Composition Root looks like this:
1 2 3 4 5 6 7 8 9 10 11 | void SetupContainer() { container = new IoC.UnityContainer(); container.Bind< IoC.IMonoBehaviourFactory >().AsSingle< IoC.MonoBehaviourFactory >(); container.Bind< IMonsterFactory >().AsSingle< MonsterFactory >(); container.Bind< IMonsterSystem >().AsSingle< MonsterSystem >(); container.Bind< PathController >().AsSingle(); container.Bind< MonsterSpawner >().AsSingle(); } |
container will not be used in any other part of the example, except for the factories. Factory is a special case and I will explain it later.
What is happening? Inside the SetupContainer method we are not simply registering the classes into the container, but we are actually setting up the flow of our dependencies. Dependencies that are solved lazily (that means only when requested) through the metatag [IoC.Inject].
In our case, the application flow starts from this method:
1 2 3 4 5 6 7 8 | void StartGame() { MonsterSpawner spawner = container.Build< MonsterSpawner >(); TickEngine tickEngine = new TickEngine(); tickEngine.Add(spawner); } |
After the MonsterSpawner is built, it will have the dependency IMonsterFactory injected because it has been declared like this:
[IoC.Inject] public IMonsterFactory monsterFactory { set; private get; }
and because IMonsterFactory has been previously registered (and bound to a valid implementation) inside the container.
In this specific case is simple to understand how the MonsterSpawner dependencies have been explicitly injected by the container. However the container will not be explicitly used anywhere else, so the other dependencies will be injected thanks to the Object Graph.
This means that monsterFactory on its turn will have (automatically) injected the dependencies:
[IoC.Inject] public IoC.IMonoBehaviourFactory monoBehaviourFactory { set; private get; }
[IoC.Inject] public IMonsterSystem monsterSystem { set; private get; }
If monsterSystem had some dependencies too, they would have been injected as well and so on….
In a complicated project scenario this system eventually will give the impression that the [IoC.Inject] metatag becomes a sort of magic keyword that would solve all our dependencies.
Of course there is nothing of magic and, differently than Singleton containers, our dependencies will be correctly injected ONLY if they are part of the Object Graph.
The Object Graph itself is the main difference between the use of an IoC container and a Singleton container. The dependencies are not scattered without any condition among the classes, but they must follow the Object Graph flow.
If, using Singletons and Singleton containers, your code starts to feel like a game of Jinga, than it is probably the time to start to look at the Inversion Of Control solution.
it is called Inversion Of Control because the principle is that the code should not use the keyword new at all. The control (of the creation of the objects) is not anymore on the user, but on the framework that will create and inject the objects for him.
The most powerful benefit behind this concept is that the code will not rely on the implementation of the classes anymore, but always on their abstractions (if interfaces are used).
Relying on the abstraction of the classes gives many benefits that can be fully understood when practices like refactoring and unit testing are heavily used. Regardless these concepts, coders should anyway use interfaces to create clean and well designed code.
all that said, one could ask: if I should not use new, how is it possible to create objects dynamically, while the application executes, like for example spawning objects in my world?
My answer is to use Factories. Factories, in my design, can use the container to inject the object that they create.
your class could have something like:
1 2 3 4 5 6 | public [IoC.Inject] IBulletFactory bulletFactory { set; private get } void OnBulletMustBeCreated() { add(bulletFactory.Create()); } |
Beside, if you wonder why your class should not be able to create objects on its own, remember that this is not over engineering, this is separation of concerns.
Creating bullets and handle them are two different responsibilities and respecting the Interface Segregation Principle (part of the SOLID principles that should be your coding commandments) is one of the most important design rule in order to not have humongous and cluttered classes.
The use of an IoC container, similar to the one I am showing in this article, will help to shift the coding paradigm from an intensive use of Monobehaviour to the use of normal classes that implement interfaces.
However Monobehaviour, on its pure form, is a totally useful tool and its use must be encouraged when appropriate. Still our Monobehaviours need dependencies that must be injected.
Now, if the Monobehaviours are created dynamically through factory, as it should happen most of the times, then the dependencies will be solved through the Object Graph.
However, if monobehaviour are created implicitly, their dependencies cannot be solved within the Composition Root because of the nature of the Unity Framework.
For instance, in my example, the turrets are not created dynamically (they could have been though), as well as the monsters counter shown on the top left corner.
There is no proper way to find a workaround to this limitation. My personal solution has been to create an extension method, called Inject, that can be used with Monobehaviour scripts.
the Monobehavior classes, created implicitly by the framework, that need dependency injected, use the extension in this way:
1 2 3 4 | void Start () { this.Inject(); } |
After this function is called, all the dependencies will be injected. There are conditions though:
The GameObject must be in a hierarchy where one of the parent GameObjects has one valid UnityContext monobehaviour set.
The UnityContext must be initialized before the extension method is used. This can be achieved using Start or changing the Script Execution Order.
IoC container become also very useful when patterns like Model View Controller (or the more recent Model, View, Presenter and Model, View, ViewModel) are used.
Theoretically the triad should not be known outside the triad itself, since the way to communicate outside is to use services or command injected. The explanation of this case is not part of the scope of this article, so maybe I could write about it in another one.
However it is interesting to highlight how I also use these patterns to uncouple the data that we want to be edited through the editor and the logic that must use this data.
Usually what happens is that, just because we want to let the designer edit some public variables of a class, it becomes a Monobehaviour without any other reason. The way to get around this problem is to create a Monobehaviour that just handles this data and so become a sort of Model. This is what happens in our example with the PathModel class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | public class PathModel:MonoBehaviour { [IoC.Inject] public PathController pathController { private get; set; } public GameObject[] placeHolders; void Start() { this.Inject(); pathController.pathDTO = this.placeHolders; GameObject.Destroy(this); } } |
While you can change the way I exploited the idea in several ways, the main concept is that the monobehaviour is totally uncoupled from the logic (pathController) and it could even be destroyed since it is not needed for our purposes anymore.
Often IoC container is associated to Unit Tests. However there is not any direct link between the two practices. In fact very often Unit Tests do not use IoC containers at all.
Instead the point is that the use of an IoC container, against the use of static classes, will help the coder to write Unit Test friendly classes.
In fact Unit tests must test ONLY the code of the testing class and NEVER its dependencies. Using Dependency Injection will make very simple to create dumb mockup to inject valid dependencies that cannot ever break or affect the tests of the main class itself. This can happen thanks to the use of interfaces, where the mockups become just one different (often empty) implementations used for the scope of the tests only.
Unit testing is also outside the scope of this article and maybe I will write one on purpose in future.
before to conclude, I want to quote two answers I found on StackOverflow that could help to solve some other doubts:
from http://stackoverflow.com/a/2551161
The important thing to realize here is that you can (and should) write your code in a DI-friendly, but container-agnostic manner.
This means that you should always push the composition of dependencies to a point where you can’t possibly defer it any longer. This is called the Composition Root and is often placed in near the application’s entry point.
If you design your application in this way, your choice of DI Container (or no DI Container) revolves around a single place in your application, and you can quickly change strategy.
You can choose to use Poor Man’s DI if you only have a few dependencies, or you can choose to use a full-blown DI Container. Used in this fashion, you will have no dependency on any particular DI Container, so the choice becomes less crucial in terms of maintainability.
A DI Container helps you manage complextity, including object lifetime. Used like described here, it doesn’t do anything you couldn’t write in hand, but it does it better and more succinctly. As such, my threshold for when to start using a DI Container would be pretty low.
I would start using a DI Container once I get past a few dependencies. Most of them are pretty easy to get started with anyway.
and from http://stackoverflow.com/a/2066827
Pure encapsulation is an ideal that can never be achieved. If all dependencies were hidden then you wouldn’t have the need for DI at all. Think about it this way, if you truly have private values that can be internalized within the object, say for instance the integer value of the speed of a car object, then you have no external dependency and no need to invert or inject that dependency. These sorts of internal state values that are operated on purely by private functions are what you want to encapsulate always.
But if you’re building a car that wants a certain kind of engine object then you have an external dependency. You can either instantiate that engine — for instance new GMOverHeadCamEngine() — internally within the car object’s constructor, preserving encapsulation but creating a much more insidious coupling to a concrete class GMOverHeadCamEngine, or you can inject it, allowing your Car object to operate agnostically (and much more robustly) on for example an interface IEngine without the concrete dependency. Whether you use an IOC container or simple DI to achieve this is not the point — the point is that you’ve got a Car that can use many kinds of engines without being coupled to any of them, thus making your codebase more flexible and less prone to side effects.
DI is not a violation of encapsulation, it is a way of minimizing the coupling when encapsulation is necessarily broken as a matter of course within virtually every OOP project. Injecting a dependency into an interface externally minimizes coupling side effects and allows your classes to remain agnostic about implementation.
The framework and the example can now be found on GitHub (I use bitbucket only for temporary or personal projects) at: https://github.com/sebas77/Lightweight-IoC-Container-for-Unity3D. You are very welcome to modify it and share your improvements to the other users.
Note: you can add more turrets if you want using the Editor, thanks to the IoC everything will work without touching code.
Sebastiano Mandalà is currently lead programmer at Climax working on a Unity based social game. He can be followed on twitter (@sebify) and on his blog (blog.sebaslab.com)
Read more about:
Featured BlogsYou May Also Like