The Dependency Inversion Principle is part of the SOLID principles. If you want a formal definition of DIP, please read the articles written by Martin[1] and Schuchert[2].

We explained that, in order to invert the control of the flow, our specialized code must never call directly methods of more abstracted classes. The methods of the classes of our framework are not explicitly used, but it is the framework to control the flow of our less abstracted code. This is also called (sarcastically) the Hollywood principle, stated as “don’t call us, we’ll call you.”.

Although the framework code must take control of less abstracted code, it would not make any sense to couple our framework with less abstracted implementations. A generic framework doesn’t have the faintest idea of what our game needs to do and, therefore, wouldn’t understand anything declared outside its scope.

Hence, the only way our framework can use objects defined in the game layer, is through the use of interfaces, but this is not enough. The framework cannot know interfaces defined in a less abstracted layer of our application, this would not make any sense as well.

The Dependency Inversion Principle introduces a new rule: our less abstracted objects must implement interfaces declared in the higher abstracting layers. In other words, the framework layer defines the interfaces that the game entities must implement.

In a practical example, RendererSystem handles a list of IRendering “Nodes”. The IRendering node is an interface that declares, as properties, all the components needed to render the Entities, such as GetWorldMatrix, GetMaterial and so on. Both the RendererSystem class and the IRendering interface are declared inside the framework layer. Our specialised code needs to implement IRendering in order to be usable by the framework.

Designing layered code

So far I used the word “framework” to identify the most abstracted code and “game” to identify the least abstracted code. However framework and game don’t mean much. Limiting our layers to just “the game layer” and “the framework layer” would be a mistake. Let’s say we have systems that handle very generic problems that can be found in every game, like the rendering of the entities, and we want to enclose this layer in to a namespace. We have defined a layer that can be even compiled in a DLL and be shipped with whatever game.

Now, let’s say we have to implement the logic that is closer to the game domain. Let’s say that we want to create a HealthSystem that handles the health of the game entities with health. Is HealthSystem part of a very generic framework? Surely not. However while HealthSystem will handle the common logic of the IHaveHealth entities, not all these entities will be of the same type. Hence HealthSystem is more abstracted than more specialised entity behavior implementations. While this abstraction wouldn’t probably justify the creation of another framework, I believe that thinking in terms of layered code helps designing better systems and nodes.

Putting ECS, IoC and DIP all together

As we have seen the flow is not inverted when, in order to find a solution, a bottom up design approach is used to break down the problem or in other words when the specialized behaviors of the entities are modeled before the generic ones.

In my vision of Inversion of Control, it’s needed to break down the solutions using a top down approach. We should think of the solutions starting from the most abstracted classes. What are the common behaviors of the game entities? What are the most abstracted systems we should write? What once would have been solved specializing classes through inheritance, it should be now solved layering our systems within different levels of code abstraction and declaring the relative interfaces to be used by the less abstracted code. Generic systems should be written before the specialized ones.

I believe that in this way we could benefit from the following:

  • We will be sure that our systems will have just one responsibility, modeling just one behavior
  • We will basically never break the Open/Close principle, since new behaviors means creating new systems
  • We will inject way less dependencies, avoiding using a IoC container as a Singleton alternative
  • It will be simpler to write reusable code
  • We could potentially achieve real encapsulation

In the next article I will explain how I would put all these concepts together in practice

References:

  1. http://www.objectmentor.com/resources/articles/dip.pdf
  2. http://martinfowler.com/articles/dipInTheWild.html

I strongly suggest to read all my articles on the topic:

7
Leave a Reply

avatar
3 Comment threads
4 Thread replies
0 Followers
 
Most reacted comment
Hottest comment thread
4 Comment authors
Daniel SagenschneideruchlabSebastiano Mandalàheretique Recent comment authors
  Subscribe  
newest oldest most voted
Notify of
heretique
Guest
heretique

Really nice series of posts. I can hardly wait for the fifth one…

heretique
Guest
heretique

If there’s any way I could help, I’ll gladly spare some time. I’m preparing a “Best practices in Unity” small training in our company for the games department soon and part of it is inspired by your posts.

uchlab
Guest
uchlab

I’m reading a lot about game architects in Unity lately and this series are really good. I’m have a really good experience using IoC and MVC in other projects, but I feel that MVC play really great on UI based apps but not in games (simulations at the end of the day), and the other way around with ECS. I really will like to see the next post. IMHO a combination of both systems, using MVC for the UI bit (popups, handling complex UI components, etc) and ECS (for the game itself) is the winner combo, but I need to… Read more »

Daniel Sagenschneider
Guest
Daniel Sagenschneider

May I just say that you are confusing Inversion of Control to be only Dependency Injection. A paper recently published identifies a bottom up approach to Inversion of Control, which goes beyond Dependency (State) Injection to include Continuation Injection (inversion of behaviour) and Thread Injection (inversion of performance). The paper is available at http://doi.acm.org/10.1145/2739011.2739013 (or for a free download a link off http://www.officefloor.net/mission.html ). I hope this helps you realise your vision of a bottom up approach is actually available now 🙂