Inversion of Control
This is a concept in software architecture which describes how a shared code (framework, base class..) and user code (in our case, this is the "applications") interact with each other, how the flow of control bounces between them.
In short:
- With traditional code, we have library methods or functions called by the user code.
- With inversion of control, the user code is called by the library / framework / shared code. Mostly when we talk about frameworks, we mean libraries working this way. The same goes if we extend an existing CMS using its extension hooks.
The trick is that at some point the user code needs to tell the framework when it wants to be called. This can happen in different ways:
- The user code actively subscribes to framework hooks or events.
- The user code implements a naming scheme that the framework can recognize.
- The shared code knows about the user code, and chooses a method.
- The user class derives from the framework class.
- We have an additional piece of code (or config file) which tells the framework about the user component (or vice versa). This could be one big central configuration for the entire project, or decentralized config files for each component. Our alias.ini and autoload.ini (or previously, build.xml do something in this direction.
See also
- http://martinfowler.com/bliki/InversionOfControl.html
- http://en.wikipedia.org/wiki/Inversion_of_Control
- It's also interesting to see the wikipedia discussion page! There is some controversy and confusion going on.
What is on which side?
Above we were talking about framework/library vs user code. Sometimes this definition is sufficient, sometimes not. To be
Who knows What?
Knowing is assuming. Ignorant components are easier to reuse.
...
Reusable User Components
Software reuse is not a myth - it actually works! This is quite obvious for libraries and frameworks, but what about our applications? What is difficult about reusing them in another project?
- They rely on our infrastructure of global symbols: singletons, classes (for explicit construction, and for inheritance), global-scope functions and global variables and constants.
- They rely on our database structure. Even if for instance a 3rd party forum would bring its own DB, it has to be connected to our user table, our user avatars, etc.
- They rely on a being called in a specific way by the framework.
- They are all written in PHP. Bam! Show-stopper for all Python or Ruby friends.
Examples:
- Our searchmembers app does only work in our project.
- WordPress? addons do only work in WordPress? (usually).
- MediaWiki addons do only work in MediaWiki (usually).
- MediaWiki is a pain to integrate in other projects.
etc.
How can we nevertheless reuse our components somewhere else? Reuse in the sense of using the original unmodified application!
- It doesn't help, but all the explicitly used global symbols have to be copied or simulated in the other project. To make this possible, we have to take care that these global things can be copied without making trouble like nameclashes with the other project, or messing with global variables like $_POST. The fewer global dependencies, the better!
- This can be really tricky.. the solution can be to make our application model customizable by subclassing or parameterization, or by injecting an exchangeable object to represent the "rest of the DB".
- This is actually easy. If the other project's framework does not already support our applications, we can write an adapter for it and place it in between. This is where IoC / Dependency Injection gives us a bonus.
- No easy way to get something from one language to another.
Conclusion: If we would find a forum or ajaxchat written with these things in mind, we would not have to code our own!
Never Touch the Framework?
Usually with IoC we talk about the framework code calling the user code. Framework in this sense means different things:
- The code that gives control to the user code.
- The code that knows most about the environment, which is server setup, configuration files, etc.
- The code which knows all the shared services, be it rights management, logging, database connections, etc, and which wires these services to the applications.
- The code we don't touch, because it's 3rd party and we want to update it from time to time.
The last point now raises some questions: If we can't touch this code, doesn't that totally kill flexibility? The answer is: yes, it would be totally unflexible.
What we need is a way to customize the framework to our needs, without messing in the original framework code. A good framework will allow to make subclasses and override some methods, and/or have some other ways of customization. So, what we would end up with is
- application code (a few of them could be 3rd party)
- shared services (some of them could be 3rd party)
- framework code (often 3rd party)
- framework customization
How do the different parts talk to each other?
...
How is that relevant to us?
There are several aspects in our architecture where this concept applies.
Framework chooses and runs a controller
Old style:
- The member.php (or any other page) gets called and first needs to require_once the init.php, and other things, to load the basic settings.
IoC:
- The framework loads all the basic settings
- The framework (front router) looks at the request and the available class names, and then starts the controller.
- Ideally, the framework would give the basic settings to the controller, instead of making them globally available..
Controller chooses a page
The controller (such as SearchmembersController?) is not exactly a part of the framework. However, compared to the pages or layout templates, the controller is in a role where it is shared in more places.
Old style:
- member.php (or any other page) has to include the functions which are needed for loading a member profile from the DB
IoC style:
- The controller prepares the model, and gives the page what it needs.
Subclass methods called by base class methods
This happens a lot in our page and widget classes..
Old style:
- member.php calls the profileheader.php and footer.php, and then prints the specific content for the profile page
- profileheader.php prints the elements which are common for all member pages, and calls menu.php
- menu.php prints elements which appear on all pages.
IoC style:
- The base class PageWithRoxLayout? prints the menus and footer, and calls the subclass methods for the profile teaser and main content
- The subclass MemberPage? prints the member page teaser, and eventually calls some subclass methods.
- The subclass ProfilePage prints the main content.
Again, we have a shared layout which calls the individual layout.
Places where we don't have IoC
Obviously, all the stuff in htdocs/bw..
Aside of that:
- Most of the things in the modules folder are not IoC, but explicitly called from the applications.
- Many things inside the lib folder (Platform PT) have to be explicitly called, such as PRequest.
- Different applications reusing each other's functionality (can be layout widgets, or models)
- Inheritance: By declaring something a subclass of something else, we explicitly talk to a framework symbol.
Is this any bad?
That's a debatable topic. Often it is really non-trivial to avoid any explicit calling-each-other. Sometimes we can't avoid, or sometimes we don't want to - so is life. What we can keep in mind: Every time we explicitly call a singleton, floating function, global symbol, class constructor, or even if we derive from a framework class, we reduce the flexibility to restructure the framework without touching the applications. Sometimes we can avoid this, but often it is just the price we accept to pay.
Can there be full IoC ?
With full Inversion of Control (in theory), the user code would never call any framework function. The advantage would be that we can restructure or even replace the framework, without changing the applications. Sounds great.
However, there are enough cases where we would like to call functionality defined in a library methods, instead of waiting to be called. Often these things would fall into the "shared services" category. Or, we want to reuse parts of one application in another.
There are ways around this.
- Having traditional libraries in addition to the framework, where we don't care about IoC.
- We inject abstractions of the shared services into the applications.
- Isolate those parts of the framework which are explicitly used (such as shared base classes) and reduce their responsibilities and powers.
Injection of shared stuff
The concept is similar to having a phone number instead of a real physician.
The real physician would be always around, but it will always be the same one physician, and the physician is forced to stick around. Having a phone number, the emergency service can choose which and how many experts it will send if we make a call. This is nice for the emergency service company, because it can now hire and fire at will, or replace the full infrastructure, without letting us know. It is nice for us, because we get a state-of-the-art emergency care without changing anything ourselves.
Another example would be having a universal ticket for world-wide public transport, instead of being the owner of a train waiting somewhere in Madagaskar.
See also


