Tuesday, August 18, 2009

XML in IoC containers: A hell or a realm?

While the essence of Inversion-of-Control (IoC) container appears to be easily comprehensible and well understood, it is subtly confusable and badly misread. One of the biggest confusion is the use of XML. Namely, application composite wiring/configurations are programmed as XML documents (or textual strings). This practice in IoC containers, notoriously known as the "XML Hell", draws various FUD criticisms, such as:
  • These XML codes are merely verbose and lousy procedural scripts.
  • These XML codes are poorly debuggable.
  • These XML codes lack static type safety.
  • These XML codes are refactoring-adverse.
As to be evidenced through the following discussions, these FUD claims not only completely missed the point but also turned out to bring up examples that affirmed the strength and significance of this XML programming realm instead.

Are these XML codes verbose and lousy procedural scripts?
First of all, as pointed out in the article IoC containers other than the DI pattern, these XML codes are not scripts that verbalize the procedures to produce the required configurations. Instead, they are models that visualize the required composite layout themselves (or requirements and constraints). This is just like the distinction between the assembly instruction book of a vehicle and its design blueprint. Hence, these XML codes are meant to be schematically intuitive and self-documenting rather than linguistically fluent and concise.

Secondly, also pointed out by the article IoC containers other than the DI pattern, these XML codes are intended to serve as mediating data worksheets as well. These data worksheets are going to be exchanged between IoC containers and independent applications/plugins that provide value-added features, such as model generation, editing, displaying, transformation, verification, storing, and querying. Therefore, these XML codes are desired to be programmatically manipulable as first class objects to heterogeneous programs rather than grammatically readable as natural language sentences to English programmers.

It is widely thought that such a data modeling issue was no more than another nail for the universally effective golden hammer - procedural languages (such as Java). A chief scientist of a Java consulting firm once even made an assertion: "Everything that can be done with xml should be doable from a java program". Consequently, various kludges have been invented and enthusiastically practiced to eliminate XML for data modeling, for instance, by expressing data composite model layouts in procedural method chaining layouts (i.e. the so-called fluent API coding style) or Java annotated data type layouts (i.e. metadata). Although claimed as substitutes or killers of their XML counterpart, it is not hard to see that these clever kludges are merely poorman's mimics of declarative data description languages. Not only they lack language level support of formal and intuitive schema definitions and structure/content integrity constraints, but also their codes are hard to be manipulated as first class objects. These "using procedural language for data modeling" kludges appear to have certain claimed advantages (such as debuggable, static type safety, refactoring-friendly) over XML, they missed the fundamental points of both the procedural programming and the data modeling paradigms in general.

Are these XML codes poorly debuggable?
Here, the "debug" specifically means stepping and tracing through the runtime executions of procedure codes at source level. When comparing to IoC containers, XML-eliminated DI frameworks frequently emphasize their advantage (as a killer feature) of being able to debug user authored application assembling/configuring codes written in procedural languages. Nevertheless, relying on such stepping/tracing debug simply indicates the following two facts of these DI wiring programs and their languages:
  • these programs consist user designed procedural code and user defined mutable states/variables
  • these programs are written in languages that lack of statically verifiable data schema support.
On the contrary, user authored XML codes in IoC containers are not procedural scripts but data descriptions that model the required composite arrangements with well defined schemata and statically verifiable integrity constraints. In general, code orders in these XML programs do not imply the actual step-by-step imperative execution orders of the underlying plumbing operations performed transparently by IoC containers. Hence, just like freeing from runtime debugging syntax errors, static type errors, and memory pointer arithmetic faults is an advantage of the Java environment, relieving the burden of runtime debugging structure/content constraint violations and IoC plumbing procedures is the very point and the strength of IoC containers and the data description language like XML!

Are these XML codes unable to feature static type safety?
This FUD criticism is specific to the static type safety. This is because that the dynamic type safety is already supported in IoC containers through comparing reflection retrieved metadata informations against operation signatures referred in these XML codes. For static type safety, component type informations are supposed to be retrieved from POJO (and/or POCO) component source code. Apparently, this was considered by this FUD to be not possible or significantly difficult.

However, firstly, it is obvious that what should be blamed here is not these XML codes but those POJO/POCO source codes written in classic procedural languages. Namely, the difficulty (if any) is not on inspecting operation signatures referred in these XML code but on retrieving type informations from those POJO/POCO source code. In another word, this issue actually reveals an advantage of these XML codes over classic procedural language code on being explicitly manipulable as first class objects.

Secondly, various "static reflection" engines for these procedural languages, such as Eclipse CDT C++ DOM/AST, JDT Java DOM/AST (since June 2004, Eclipse 3.0), GCC-XML (since 2002), Eclipse JDT JDOM (as early as 2002, for Eclipse 1.x/2.x) have long and widely been available. With these engines, type information "static reflection" from POCO/POJO component source code is as simple as dynamic reflection from compiled metadata. Therefore, static type safety check for these XML codes is as easy as the widely supported dynamic type safety for IoC containers.

Thirdly, this FUD criticism itself is merely a red herring to mislead readers to believe that, without static type safety, these XML codes would imply significant overhead (claimed to be 10 times slower) and be error prone at runtime. Nevertheless, in IoC containers, dynamic type check on each signature in these XML codes needs only be performed once (or very few times). Hence, the real performance overhead from dynamic type check is negligible for almost all real world applications that use decent IoC containers. More importantly, in IoC/DI scenario, operation signatures referred in these XML codes are resolved (and checked) by IoC container at applications (especially test applications) initialization or reinitialization phase. Hence, these XML codes are no longer involved in the executions of the applications once they passed this initialization/reinitialization phase, let along to cause runtime type errors in production applications. Certainly, a start-up time type checking that requires a start-up test is still different from source code editing or compiling time check. However, arguing such a start-up type check was practically unacceptable would be self-contradictory to the previous argument that emphasized the advantage of runtime debuggability which implies more than starting the applications.

Fourthly, with regarding to static code check, this FUD criticism inadvertently brought up a fundamental weakness of procedural languages and a significant strength of the XML paradigm. Namely, grammar (or syntax structure) and static type safety check of procedural languages tend to be too primitive and too generic to ensure user authored procedures are free from runtime errors or wrong runtime results without errors. This is why procedural languages and their XML-eliminated DI frameworks emphasize runtime debug and sufficient runtime test coverage. On the contrary, in IoC containers, these XML codes do not specify the runtime procedures but explicitly describe the required results and, therefore, are not only inherently free from runtime errors caused by procedural bugs in user codes but also enable much sophisticated and problem/domain specific schema verifications to statically diagnose errors in user described requirements or even results themselves.

Are these XML codes refactoring-adverse?
This FUD claim can be put as: "POCO/POJO function signatures are expressed as literal strings in these XML codes. Because literal string in C++/Java code do not participate in code refactoring, hence, these XML code are not able to participate in component interface refactorings either." The erroneousness of this FUD claim is fail to understand that having a pair of quote characters surround a string text is merely an appearance rather than the cause of "refactoring-adverseness". In fact, the quote character pairs surrounding string texts are removed at lexical analysis stage even before these strings being added to the abstract syntax trees (AST) internally used by compilers or refactoring engines. The "refactoring-adverseness" of these strings is not due to the quote character pairs surrounding them but simply because the literals strings themselves in C++ or Java languages have no language level connections to names/signatures of variables, interfaces/classes, and/or functions/methods known by refactoring engines.

On the contrary, the mapping from the attribute values in form of quoted strings in these XML codes to POCO/POJO interface/class type names and function/method signatures are well defined. Otherwise, the underlying IoC engines would not even be able to resolve invocation methods through reflection in the first place. Hence, having refactoring on these XML codes is straightforward, and having them participate in POCO/POJO component code refactoring is not more difficult than (if not significantly easier than) the original work of supporting refactoring on C++/Java code themselves (would C++/Java be criticized as being refactoring-adverse as well?), not to mention this integration approach has largely been simplified by the open architectures of existing refactoring IDEs (such as the Eclipse Language Toolkit (LTK) refactoring architecture) and the Eclipse CDT C++ DOM/AST and JDT Java DOM/AST "static reflection" engines.

Furthermore, the "refactoring" in this FUD criticism obviously meant the interactive refactorings made in an IDE environment. As pointed out above, it is possible to have these XML codes participate in such an interactive refactoring of POCO/POJO. However, it would only make sense if the XML codes and the POCO/POJO component/service implementation codes were developed together within the same IDE project. Unlike programmatic API frameworks (as well as those XML-eliminated DI frameworks) which consider wiring configurations an statically built-in integral part developed together with and spread throughout their applications, IoC containers have assembly/deployment arrangement code completely separated from POCO/POJO component/service implementations. Namely, these arrangement code tend to be authored independently outside of (or decoupled from) the development phase(s)/cycle(s), IDE project(s), and/or brain(s)/team(s)/vendor(s) of those components/services. Hence, having these XML code participate in an interactive refactoring of those POCO/POJO code is largely a phantom requirement from misreading or misusing of IoC containers.

Tuesday, August 11, 2009

Inversion of Control Containers vs the Dependency Injection patter

IoC containers are not about a design pattern

While the essence of
Inversion-of-Control container appears to be easily comprehensible and well understood, it is subtly confusable and badly misread. This paradox is reflected from various seemingly evident and widely taken for granted but misleading interpretations, such as the following two well known assertions on what these containers are about:
  • Inversion-of-Control (IoC) is simply the Dependency-Injection (DI) design pattern for loose coupling between business logic implementations.
  • IoC containers (hence, tend to be referred to as DI frameworks) are programming frameworks primarily to facilitate the DI design pattern.
Misled by these interpretations, many readers disappointingly concluded that IoC containers were merely about a trivial design pattern that not only was doable by hand in a few lines of code without a container but also had already been a plain old practice on the street for years before it became a buzzword hype. These stereotypes missed the substances for the superficies (such as IoC/DI type 1,2,3, reflection, and design patterns). Consequently, the significances and implications of IoC containers have largely been neglected, as one can tell from the sigh of some DI folks: “I was expecting a paradigm shift, and all I got was a lousy constructor”.

IoC containers emerged as a mainstream solution by successfully challenged the dominance of their predecessor(s), the old EJB (2.x), that was based on the service locator design pattern. If IoC containers were merely to facilitate a plain old hand doable design pattern for loose couplings between components, then what made them superior to their predecessor(s)? Was the EJB's service locator design the cause of tight couplings between components? Was the service locator design pattern not doable by hand (if this was counted as an advantage)? Was the core engine of old EJB containers primarily to facilitate the service locator design pattern? Or, was the change from service locator to IoC/DI any paradigm shift (if we were expecting any)?

Firstly, neither the EJB's service locator design incurs tight couplings between components, nor the IoC/DI design relatively loosens such couplings if any! The objective and strength of IoC containers are orthogonal to the attempt of reducing the component-component (or component-service) couplings. Rather, they are superior to their EJB predecessor(s) by completely eliminating component-container couplings. As an example: if A and B are two components (either concrete instances or abstract interfaces) and C is an IoC container that injects B's reference into A, then, contrary to the popular misinterpretation, the injection here has nothing to do with loose coupling between A and B but serves to completely decouple A (and B as well) from the C. Here, in this example, the C itself is neither being injected with the reference of A or B nor has its reference been injected into A or B.

Secondly, neither the service locator design was hard to do by hand, nor the core engine of old EJB was to facilitate this design pattern. Similarly, although appearing as a core design pattern in IoC containers,
as Stefano Mazzocchi once pointed out, IoC (or DI) is not what IoC containers focus to do but what they merely use. In fact, it is not IoC containers facilitate the IoC/DI design but this design serves the containers. In another word, the essence of IoC containers is not "IoC" but the "container". It is just like the essence of "electric cars" is not "electricity" but the "car". It would miss the point to say electricity could be generated without cars, and worse, to conclude electric cars were merely to facilitate (i.e. to generate) electricity.

Thirdly, changing from the old EJB's service locator design to the new IoC/DI design makes component containers seamless and neutral/non-invasive. However, this design change neither unveils a new paradigm nor alters the primary objective of the containers. Instead, it is this inherited objective itself, to be discussed further in this article,
implies mindset and paradigm changes.
IoC containers != DI frameworks

As being pointed out above,
IoC containers are neither about loose couplings between components nor meant to facilitate the DI design pattern (or the Dependency Inversion Principle). However, many programming libraries known as DI frameworks (and the JSR 299) are precisely to facilitate this pattern. Although these DI frameworks are orthogonal and even opposite to IoC containers on focus, objective, and philosophy, they are constantly claimed to be substitutes or even killers of IoC containers. To avoid further confusions and meaningless apple to orange comparisons, it is now necessary to differentiate IoC containers from these DI frameworks.

DI frameworks are programming libraries with the following objectives, focus, and characters:

  • They are primarily to facilitate the DI design pattern in wiring loosely coupled business logic implementation modules (objects) into applications.
  • They focus on providing programmatic APIs (e.g. templates, annotations, and binder classes/functions) for DI configuration authoring in the same implementation languages of their business logic modules.
  • They favor DI annotations tightly coupled with business/service logic modules and consider DI configurations a statically built-in integral part of their applications.

Hence, DI frameworks emphasize the advantages of the programmatic APIs for DI configuration programming. This reflects the belief of
"the most powerful way to 'configure' something is to write the code that produces what you want. Code is precise. Code is good." In DI frameworks, these configuration "codes" are distinct from the "data". They are either step-through debuggable and testable procedural programs tightly integrated with their applications or binary metadata structures/templates and annotations to be read by DI frameworks through runtime reflection.

Quite differently, IoC containers are a category of assembly and deployment engines for component-based applications (namely, applications built from prefabricated coarse-grained high-level application or service function modules) with the following characters and objectives:
  • They use the IoC design to non-invasively control container-agnostic components (e.g. plain old C++ or Java objects/service interfaces) in assembling and deploying applications.
  • They are primarily to support the "code is model, code is data" paradigm for composite authoring, where:
    • program code explicitly model the required composite arrangements rather than the procedures that produce such arrangements (or their plumbing contexts, builders, or binders),
    • program code are not written in the same implementation languages of their applications but in data representations neutral to these languages.
  • They clearly separate these composite arrangement model/data representations from their components and applications, and have them (composite arrangement representations) manipulable as first class data objects independently.
Hence, in the vision of IoC containers, an application is a composite of binary components and external services. Such a composite is declarative programmed by modeling it in a first class data representation. This is "code is model, code is data" programming paradigm is what IoC containers (and their predecessors) are primarily about, why they are useful, and where they are fundamentally different from plumbing by hand (or facilitated by DI frameworks) in classic OO languages. Therefore, it is this programming paradigm, rather than an OO design pattern, the very essence of IoC containers.

By "code is mode", IoC containers consider "a cost effective, intuitive, and maintainable way to configure (assemble and deploy) applications is to model what you want rather than to write the code of how to produce them". Therefore, in IoC containers, user codes are self-documenting models that visualize user requirements (i.e. what users want) rather than verbalize user solutions (i.e. how to produce the configurations). In general, code orders in these IoC programs do not imply the actual step-by-step imperative execution orders of the underlying plumbing operations performed transparently by IoC containers. This enables more strong static code verifications and frees users from the concerns of IoC procedural bugs and the burdens of runtime debugging.

By "code is data", these composite modeling codes are not merely or necessary user manual programs but, most importantly, able to serve as language neutral mediating data worksheets to be handed from or exchanged between independent modeling applications or plugins in forms of internal data objects, online messages, as well as external off-line documents or records. Comparing to the binary immutable metadata/annotation/API driven tight integration of DI frameworks, this data driven approach enables a much flexible while safe integration between IoC containers and third party modeling applications or plugins that generate, edit, display, transform, merge, refactor, compare, analyze, verify, and query these modeling codes at primitive POJO/POCO component API levels as well as at various domain specific modeling levels.

Certainly, this classification does not exclude the existence and usefulness of hybrid solutions sitting between these two, for instance, configuration modules are separated from their applications but coded as metadata of the same implementation languages and even manipulate these metadata at the source code syntax level.