Many of the more diligent software developers I know are moving to inversion of control and dependency injection to handle references to objects. Coming from a Flash games perspective I don't know all the ins and outs of AAA studios, so: are these used in the retail game world?

7 Answers
7

You call it 'diligent software development', I call it 'painful overengineering'. That's not to say that inversion of control is bad - in fact, the basic definition of it is good - but the proliferation of entire frameworks and methods of working to achieve all this is little short of insane, especially combined with the way people are trashing perfectly good and clean interfaces in order to be able to inject interchangeable components that 99% of the time you'll never interchange. It's the sort of thing that could only originate from the Java enterprise environment and I'm glad it doesn't have as much of a foothold elsewhere.

Often the argument is that even if you don't interchange components, you want to be able to test them in isolation with mock objects and the like. However, I'm afraid I will never buy the argument that it's worth bloating and complicating an interface in order to be better able to test it. Testing proves one thing only - that your tests work. Clean and minimal interfaces on the other hand go a long way towards proving that your code works.

So, the short answer: yes, but not in the way you're thinking. Sometimes, when you need interchangeable behaviour, you'll pass in an object to a constructor that dictates part of the new object's behaviour. That's about it.

+1 - I agree that the Java community seems to have vastly over-complicated what seems to be a very simple idea.
–
Chris HoweAug 25 '10 at 14:25

4

The idea isn't necessarily that you'll need to swap out different implementations in production, but that you might want to inject special implementations to facilitate automated testing. In that regard, DI/IoC can certainly be useful in games, but you want to keep it reasonably scoped. You shouldn't need more than a few one-time service resolutions at a high level--you don't want to be resolving services for every little object in the game, and certainly not every frame or anything like that.
–
Mike StrobelAug 25 '10 at 14:47

2

@Thomas Dufour: the concept of a test can never prove anything. It's just a data point. You can have a test pass 100000 times without proving that it will pass on run 100001. Proof comes from logical analysis of the subject matter. I would argue that these IoC containers and the like make testing easier at the expense of making proving correctness harder, and I believe that is a bad thing.
–
KylotanAug 26 '10 at 10:16

10

@Kylotan the concept of a test never tries to prove anything. It tries to demonstrate that the behavior with given inputs is as expected. The more behavior is shown to be correct, the greater your belief that overall function is correct but it's never 100%. The statement that a minimal interface proves anything is ludicrous.
–
dash-tom-bangAug 26 '10 at 18:32

4

@Alex Schearer: I'm afraid I can't ever accept that needing to use a formalised IoC container system and typically creating additional constructor arguments or factory classes to facilitate testing is, in any way, making the code better factored, and certainly not making it looser coupled. In fact it pretty much tramples on encapsulation, a key aspect of OOP. Instead of relying on TDD to drive their design and hope that a good result emerges, people could just follow SOLID principles in the first place.
–
KylotanAug 27 '10 at 16:17

Strategy Pattern, Composition, Dependency Injection, are all very closely related.

Since the Strategy Pattern is a form of Dependency Injection, if you take a look at engines like Unity for example they are completely based off this principle. Their use of Components(Strategy Pattern) is deeply embedded into their whole engine.

One of the main benefits aside from reuse of components is to avoid the dreaded deep class hierarchies.

Here is an article by Mick West who talks about how he introduced this type of system into the Tony Hawk series of games by Neversoft.

Up until fairly recent years, game programmers have consistently used a deep class hierarchy to represent game entities. The tide is beginning to shift from this use of deep hierarchies to a variety of methods that compose a game entity object as an aggregation of components...

There seems to be a lot of confusion about the Inversion of Control (IoC) pattern. A number of people have equated it with the Strategy Pattern or a Component Model, but these comparison don't really capture what IoC is about. IoC is really about how a dependency is obtained. Let me give you an example:

In the above it's clear that Sprite.Load has a dependency on a FileReader. When you want to test the method you need the following:

A file system in place

A test file to load from the file system

Ability to trigger common file system errors

The first two are obvious, but if you want to ensure that your error handling works as expected you really need #3, too. In both cases you've potentially slowed your tests down quite a bit as they now need to go to disk and you've likely made your testing environment more complicated.

The goal of IoC is to decouple the use of behavior from its construction. Note how this differs from the Strategy pattern. With the Strategy pattern the goal is to encapsulate a re-usuable chunk of behavior so that you can easily extend it in the future; it has nothing to say about how strategies are constructed.

If we were to rewrite the Sprite.Load method above we would likely end up with:

Now, we have decoupled the construction of the reader from its use. Therefore, it's possible to swap in a test reader during testing. This means that your testing environment no longer needs a file system, test files, and can easily simulate error events.

Note that I did two things in my rewrite. I created an interface IReader which encapsulated some behavior -- i.e. implemented the Strategy pattern. In addition, I moved the responsibility for creating the right reader to another class.

Maybe we don't need a new pattern name to describe the above. It strikes me as a mix of the Strategy and Factory patterns (for IoC containers). That being said, I'm not sure on what grounds people are objecting to this pattern as it's clear that it solves a real problem, and, certainly, it's not obvious to me what this has to do with Java.

Thank you for adding sanity back into the world.
–
hokiecsgradAug 27 '10 at 3:06

2

Alex: nobody is objecting to passing in already-created objects to drive custom functionality where needed. Everybody does it, just like in your example. The problem is where people are using entire frameworks that exist purely to handle this stuff, and religiously code every aspect of functionality to depend on this functionality. They first add IReader as a parameter to Sprite construction, and then end up needing special SpriteWithFileReaderFactory objects to facilitate this, etc. This attitude does originate from Java and things like the Spring IoC containers, etc.
–
KylotanAug 27 '10 at 16:24

2

But we aren't talking about IoC containers -- at least I don't see it in the original post. We're just talking about the pattern itself. You're argument, as best I can tell, is "Because some tools in the wild are bad we should not use the underlying concepts." That strikes me as throwing the baby out with the bath water. Hitting the right balance between simplicity, getting things done, and maintainability/testability is a hard problem likely best treated on a project by project basis.
–
Alex SchearerAug 27 '10 at 17:54

I suspect many people are against IoC because it means :
–
phtrivierMay 4 '11 at 11:33

Gotta agree with Kylotan on this one. "Dependency injection" is an ugly Java solution to an ugly Java conceptual flaw, and the only reason anyone's looking at it in other languages at all is because Java's becoming a first language for a lot of people, when it really shouldn't.

Inversion of control, on the other hand, is a useful idea that's been around for a long time, and is very helpful when done right. (Not the Java/Dependency Injection way.) In fact, you probably do it all the time if you're working in a sane programming language. When I first read up on this whole "IOC" thing everyone was buzzing about, I was completely underwhelmed. Inversion of Control is nothing more than passing a function pointer (or method pointer) to a routine or object in order to help customize its behavior.

This is an idea that's been around since the 1950s. It's in the C standard library (qsort comes to mind) and it's all over the place in Delphi and .NET (event handlers/delegates). It enables old code to call new code without needing to recompile the old code, and it gets used all the time in game engines.

I was also of the "so this is what people are excited about?" when I read about DI, but the fact is that most game programmers could stand to learn about it and about how it would apply to the work that we do.
–
dash-tom-bangAug 26 '10 at 18:39

I would say that it is one tool among many, and it is used on occasion. As tenpn said any method that introduces vtables (and generally any extra indirection) can have a performance penalty, but this is something that we should only worry about for low-level code. For high-level structural code that isn't really an issue, and IoC can have positive benefits. Anything to reduce dependencies between classes and make your code more flexible.

I'm not a professionnal game dev, and only tried implementing IoC in C++ once, so this is just speculating.

However, I suspect game developers's would be suspicious about IoC because it means :

1/ designing lots of interfaces and lots of small classes

2/ having pretty much every function call being lately bound

Now, it might be a coincidence, but both tend to be a little bit more complicated and/or problematic for performances in C++ (which is widely used in game, isn't it ?) than in Java , where IoC became widespread (Probably because it was relatively easy to do, help people design saner object hierarchies, and because some believed it could turn writing an a application in Java into writing an application in XML, but that's another debate :P)

I'm interested in the comments if that does not make any sense at all ;)