- What is a control?
- How is it inverted?
- Which side of this control was up, before being inverted?
Historically speaking:
Stefano Mazzocchi, of Avalon framework fame, is credited with popularizing IoC (Inversion of Control), and he, in turn, credits Brian Foote with coining the term in the Avalon document.
Quoting Brian Foote:
"The framework often plays the role of the main program in coordinating and sequencing application activity. This inversion of control gives frameworks the power to serve as extensible skeletons. The methods supplied by the user tailor the generic algorithms defined in the framework for a particular application."and quoting Stefano Mazzocchi et al. from the Avalon document:
"Inversion of Control (IoC) is the concept that a Component is always externally managed. Everything a Component needs in the way of Contexts, Configurations, and Loggers is given to the Component. In fact, every stage in the life of a Component is controlled by the code that created that Component."
Stefano further elaborates in his blog that he first came across the term in Michael Mattson's thesis in page 96. Quoting from the thesis:
Apart from Stefano's definition in the Avalon documentation, which discusses IoC simply in terms of code creating a component, all the other definitions have the container or framework in a central position, and this focus on container became more acute in later evolution of the definitions. IoC is defined as movement of the control from "main" to the "container". The container creates the component, configures and initializes the component, and manages the component life-cycle. Spring framework documentation defines IoC simply as compositing of the application from its constituent components.
"The major difference between an object-oriented framework and a classlibrary is that the framework calls the application code. Normally the applicationcode calls the class library. This inversion of control is sometimes named the Hollywood principle, “Do not call us, we call You”."This entry from Stefano's another post traces the origin of the term to Xerox PARC.
Apart from Stefano's definition in the Avalon documentation, which discusses IoC simply in terms of code creating a component, all the other definitions have the container or framework in a central position, and this focus on container became more acute in later evolution of the definitions. IoC is defined as movement of the control from "main" to the "container". The container creates the component, configures and initializes the component, and manages the component life-cycle. Spring framework documentation defines IoC simply as compositing of the application from its constituent components.
Creators of Pico Container and Martin Fowler establish a an etymology of the term IoC here:
Martin Fowler comments on the confusion surrounding this term in the second link above, quoting him:"When these containers talk about how they are so useful because they implement Inversion of Control I end up very puzzled. Inversion of control is a common characteristic of frameworks, so saying that these lightweight containers are special because they use inversion of control is like saying my car is special because it has wheels."
Fowler introduced the term "Dependency Injection" to clear up the ambiguity surrounding the semantics of IoC.
Stefano however does not quite concur with the renaming of IoC as above:
Stefano however does not quite concur with the renaming of IoC as above:
"Martin Fowler renames it Dependency Injection, and, in my opinion, misses the point: IoC is about enforcing isolation, not about injecting dependencies. The need to inject dependencies is an effect of the need to increase isolation in order to improve reuse, it is not a primary cause of the pattern."
further on:
"Moreover, I think Michael Mattson is right: IoC is not even a design pattern, but a general principle that separates an API from a framework, based on who is in control. Dependency Injection misses that entirely and misleads the reader to believe that this is just another way of composing objects."We can add to this confusion by also taking into consideration the definition of control itself, as in control flow. In control flow, control is the definition of "choice" of the next computer instruction to be executed in a series of instructions using the various control structures. However, it seems that control, as defined in control flow, does not figure that much in definition of IoC other than the reference by Brian Foote in context of coordinating and sequencing of application activity.
So where are we after all this?:
The term IOC is as confusing as it is popular. It is assured that we, coders and programmers, will be questioned about our understanding of it in most of our technical appraisals. And while we start to give our answer, we often have this fear that we might not be able to explain ourselves because we are not sure that we and the appraiser comprehended this elephant from the same end.
Are we loosing control yet? |
From the historical context, we primarily have two perspectives on what IoC stands for:
- Martin Fowler, Pico Container, and Spring framework's perspective of IoC, which views it in context of dependency injection, and compositing of the software application - in effect, a fancy implementation of the Factory Pattern with some leverage of reflection thrown in.
- Stefano's view that IoC is about enforcing isolation, modularity and reuse.
Let us re-examine what an IoC container means to us, following is a dependency graph of objects that constitute a software application. Further, let us not denote them as components yet, but plain dependency of constituents:
A is where we have our main method, the entry point or invocation point of the program. Also, above diagram does not denote an inheritance structure but only a composition dependency.
- With traditional O-O our code layout is something like this:
//TODO: Simplify image
- Considering the statement "everything a component needs is provided by the code that created that component" the code layout is something like this:
- The "Create" and "Configure" sections of the code in Class A can be further abstracted away in a factory or container class. The code layout then becomes something like this:
//TODO: Simplify Image (This sucks)
- From above, if we extract the dependency tree into a separate file (the usual XML) and modify the get operation of container to look up a component on the basis of its class name then we have our first generic container. The layout then becomes something like this:
//TODO: Simplify Image (Sucks likewise)
We now revisit following statement from Stefano:
"IoC is about enforcing isolation, not about injecting dependencies. The need to inject dependencies is an effect of the need to increase isolation in order to improve reuse, it is not a primary cause of the pattern."From above it is evident that dependency injection is only a piece in realizing IoC but does not define IoC in totality.
So what are we missing?
The Bindings:
A uses B and A is tied to B with the following lines of code in A:
TODO: Image here
TODO: Image here
B b = new B();
b.doSomething();
The aim is isolation, that is, to decouple A and B. Dependency injection allows us to get rid of binding due to the constructor (new() B() part). We still need to get independent of the declaration and invocation part (B b).
The declaration and invocation dependencies are factored out by using interfaces. Interface abstract the contract of usage and provide an indirect handle to the user class. The user class henceforth is only interested in the contract and not on who provides the implementation.
If we modify our example and consider B to be an interface and BImpl to be its implementation then we have the following lines of code in A:
TODO: //Image here
B b = new BImpl();
b.doSomething();
The above lines of code in A change as below when we have a DI container in play:
TODO://Image here. What has changed finally?
B b = container.get("B");
b.doSomething();
In the first line of code, A is essentially asking the container to provide it with an implementation of B interface. The mapping of B and BImpl as interface and implementing classes is specified in the container's context file.
//Draft:
Therefore, isolation achieved at these levels:
- Abstract out the object dependency tree into the xml file (discuss the pros and cons of using annotations maybe?)
- Abstract out the creation dependency. (Fowler's concept of IOC limited to this. DI subject matter)
- Abstract out the usage/call dependency; through interface. (Also called plug-in architecture, with a XML-RPC fronting it becomes service oriented architecture).
Still, how did control get inverted?
//TODO: Explain with images.
Possible examples:
- Wheels of cars, steel vs alloy vs wood. (Will explain interface)
- Drive from point A to B. Create the car (who does?) Drive the car. (Possible explains DI, may confuse).