Articles     Forum     Examples     Download     Open Source

 

Why and what of Inversion of Control

Ke Jin

Oct. 17, 2007

Last major update: Apr. 12, 2008

 

Copyright(c) 2007 by Pocomatic Software. All Rights Reserved.

 

Component-Based Development (CBD)

An everlasting pursuance of this industry is seeking software development techniques and paradigms that are more productive and cost effective than their predecessors. One of the examples is the evolution from structured programming to object oriented (OO) paradigm. OO techniques are more effective on lowering the problem complexities by abstracting and partitioning a given software application into loosely coupled and less complicated objects.

 

However, the productivity, customizability/extendibility, and maintainability of a development/support cycle are not solely determined by how well the application was abstracted, partitioned, and implemented in objects. They also heavily rely on how effective and flexible these separated objects are integrated and manipulated together as a seamlessly collaborated system as well as deployed/configured in a service or middleware adapting environment. Although mainstream OO programming languages, such as C++ and Java, are fairly effective on general object-oriented decomposition, control logic and procedure implementations, low-level constructions/configurations, they are rather primitive, stiff, and poorly expressive on integrating and manipulating domain/service level objects, referred to as components hereafter.

 

For instance, to facilitate lifecycle control, to simplify dependency management, and to prevent tight coupling to particular service object implementations, common programming practices tend to avoid certain intrinsic features, such as object constructors and setters, of these classic OO languages. Instead, they often resort to various contrived low level plumbing structures and even kludges such as object factories, builders, directories, adaptors, singletons, configuration/property managers, managers of factories, managers of managers, and so on. For years, OO professionals have taken these design patterns for granted and even enthusiastically exercise them. The detrimental side of this practice, especially when applied to high level component based application development, has rarely been questioned [1].

 

Besides, the imperative natural of these classic OO programming languages tend to miss the forest (high-level architectures/structures) for the trees (low-level logic control procedural code). Development and maintenance engineers taking over an existing application have to rely on its out of date design/architecture documents and low level code comments/patterns.

 

The component-based development (CBD) paradigm tackles the two issues above by shifting plumbing logic into frameworks that manipulate components and set up applications based on users/developers provided declarative descriptions. Contrary to the common confusion, such declarative descriptions are not meant to be application setup scripts. Rather, their fundamental intention is to explicitly express application architectures/structures without mandating their imperative plumbing procedures (namely describe the what instead of the how). The goal of CBD paradigm is to support effective and flexible application compositions by these frameworks and having application developers focus on business logic and domain issues without concerning low-level plumbing complexities. Additionally, the declarative nature of application descriptions should make the high level architectures of their applications manifest and self-documenting (see further discussions in IoC containers vs the DI pattern and XML in IoC containers). 

The Prior Art

During the past decade, numerous CBD frameworks have been standardized by committees and offered by vendors[2]. These traditional CBD frameworks are mostly based on invasive component models combined with the dependency/configuration lookup scenario.

 

By being invasive, each of these frameworks dictates its own non-portable component programming model that mandates complaint components to support framework pre-defined interfaces (in forms of parent classes/interfaces and/or collections of operation signatures) and framework specific component home interfaces. It implies that components have to be specially tailored or wrapped for each specific CBD framework.

 

In the dependency/configuration lookup scenario, frameworks do not set up the actual applications but merely translate their declared structure descriptions into dependency/configuration settings in framework served component contexts or global registries for lookup. Component implementations, which suppose only consist of business logic, have to deal with plumbing logic by resolving their dependencies and instantiation/property configurations from these directories using framework specific APIs. This scenario implies components could only be tested and used within their originally intended frameworks.

 

The invasiveness of component models and dependency/configuration lookup scenario significantly raised the entry barriers of these CBD frameworks and increased complexities of their component implementations. Certain notorious CBD frameworks, such as the CORBA Component Model (CCM)[3], are so complicated that are barely usable without additional highly proprietary tools.

 

These two characteristics also isolate heterogeneous frameworks by compliance barriers. They prohibit the reusability of third party components and legacy implementations, rule out the transferability of developer/user skill and experiences, and preclude the interchangeability of development tools across frameworks. Consequently, many traditional CBD frameworks were repeatedly re-invented and duplicated at expensive costs but only ended up with primitive maturities and small margins of acceptances.

The Art of Inversion of Control

The Inversion of Control (IoC), sometimes referred to as dependency injection (DI) (however, see article IoC vs DI), is a straightforward application plumbing technique based on a common programming practice. CBD frameworks that combine the declarative application descriptions and the IoC technique are referred to as IoC frameworks. Contrary to their predecessors, IoC frameworks are non-invasive and use the dependency/configuration injection/setting scenario.

 

By being non-invasive, decent IoC frameworks are neutral to component models. They impose neither any mandatory interfaces nor operation signatures on components nor framework specific home interfaces. Rather, IoC frameworks accept almost all types of programming artifacts as components and plain old instantiation/lifecycle control methods (such as constructors/destructors, factories, reference counting methods, etc.). For instance, in Java IoC frameworks, objects of any types extended from the type java.lang.Object are valid components, and are referred to as plain old Java objects (POJO). In PocoCapsule/C++ IoC framework, instances of arbitrary user or third party defined classes and template classes, classes generated from CASE or UML tools, plain old K&R C structs (a.k.a POD), unions, functions (i.e. function pointers), arrays and so on are all qualified as components, and are referred to as plain old C++ objects (POCO)[4].

 

By the dependency/configuration injection/setting scenario, IoC frameworks wiring/deploying applications by explicitly injecting/setting their dependencies and properties through calling plain old operations on plain old objects (components). Since this injection/setting scenario is an inverse version of the traditional lookup/resolving scenario, it is referred to as Inversion of Control (IoC). By this scenario, application plumbing are no longer burdens of business logic component implementations but responsibilities of the underlying frameworks.

 

The concepts, models, and scenarios of IoC frameworks are straightforward and align with common practice of plain old OO programming. Hence, they imply almost no learning curve and introduce no additional complexities to component implementations. Besides, they completely eliminate the coupling to framework and compliance barriers of component models. This means IoC frameworks are able to support heterogeneous and framework agnostic components that are developed without even being aware of their targeting frameworks.

IoC is far more than a "lousy constructor"

IoC technology was thought to be no more than a simple old design pattern/principle, a lousy way of wiring components through dependency injection, or something merely about unit test and "test driven development". In the articles Domain Specific Modeling in IoC frameworks and Inversion of Control Containers vs. the Dependency Injection pattern, it will be argued that this technique enables a paradigm shift. 

 

Back to the PocoCapsule articles page 

 

This page has been visited:

click here for a fancy web counter
free hit counter html code

[1] See more discussion by Matthias Felleisen, On the Expressive Power of Programming Languges, 1991

[2] Examples of these component frameworks include the old pre-3.0 EJB, OMG CORBA Component Model (CCM), the Service Component Architecture (SCA) from OpenSOA for WebServices/SOA, the OMG Robotic Technology Component (RTC), and the US Navy JTRS Software Communications Architecture (SCA) for software defined radio (SDR).

[3] Measured by the length of a training course offered by an ORB vendor, it takes more than 15 weeks for a C++/Java programmer to be fully trained on CORBA, CCM, and needed OMG services (Event/Notification, DDS etc.).

[4] Many POCOs, such as STL containers, standard iostreams, are low level components. Although they can be manipulated and wired using IoC containers, it should be clarified that, not as a restriction but as a guideline, IoC frameworks are intended for business and/or service level objects integration and manipulation.