Freigeben über


Fighting Against Coupling: a Moment for Reflection

 One  of the most recurrent problems we have to face, as aspiring architects, is the problem of  dealing with highly adaptable applications for different environments

For instance, we need to build an application able to access a DB/2 database in one environment, an Oracle database in another one, and an XML file in a third one. The data access logic in the two first cases is pretty similar, but the ADO.NET classes are not the same on each case. The XML file need also special logic (not based in SQL)

The problem with the command new is that we need to explicitly write the name of the class we want to instantiate. So we need to put different names on each case and recompile the application before deploy it

But, thus, the application could drive to an untenable maintenance. This is a limitation of Static (explicit) Instantiation. Fortunately, .NET provides a mechanism that enables another level of object creation: Dynamic Instantiation

Dynamic Instantiation is possible thanks to a feature called Reflection. Reflection permits us to see the execution environment as first class objects. That way, we can load assemblies (for instance, taken their name from strings), we can instance classes located inside them (again, taken their names from strings or any other indirect mechanism)

So, let's go ahead and start building highly adaptable applications

But… wait… One moment… Strings, ha? So… where can we put those strings? That's a very good question that everybody ask. And be sure that most of them considers that there's no answer for that question, so they build, first of all, some infrastructure classes to support configuration properties, in order to read them while loading the application

This is an unnecessary step, because .NET 2.0 comes with built-in support for configuration settings. This support, in .NET 1.1, was available through the Configuration Management Application Block (CMAB), later called Configuration Application Block in the Enterprise Library 1.0

But in .NET 2.0 all that functionality is embedded and extended in the Visual Studio 2005 IDE. In fact, every project can define its own execution settings. Application settings can be thought in two levels

  • Application-bound: typically connection strings, timeout intervals, server names, etc. In general terms, parameters available for every user (not dependent on him/her). Usually this parameters can vary from an installation to another one. But, in each one, they vary very little
  • User-bound: this kind of settings are kept in a per-user basis. Examples of this are: color and layout preferences, last five issued queries, etc. In few words, user settings are suitable to keep the last session state along different executions. Thus, high changeability is expected for these settings

What .NET 2.0 does with what the user loads as settings in Visual Studio 2005 is to create on the fly a class called Settings (in the project namespace), containing all the parameters defined by the user as read/write properties. Although usually properties are defined as strings, we can specify the type of everyone. Every serializable class can be the type of any property to be set

We can change these properties during execution, and save all the bundle thanks the method Settings.Default.Save(). Application-bound properties will be stored in the same directory where its project assembly is, under the name

<assembly name>.exe.config

On the other hand, user-bound properties will stay at

C:\Documents and Settings\<username>\Local Settings\Application Data\<assembly name>\user.config

So, what we have learned so far is that we can, via application settings, indicates classes to be dynamically instanced by Reflection

So far so good, but if you don't, I have a question: if the application won't know until runtime which class will be instanced, how can we, at development time, invoke methods on that still unknown class!?

Without answering this question, all the benefits of using Reflection to avoid coupling are useless. But, once again, fortunately there exist a technique to address this issue: Interface-based programming

Interface-based programming, aka "Programming against Interfaces" implies to define a clear set of properties and methods that must be present in the class to be known during execution. That's the idea of interfaces: not concrete logic but placeholder to be filled with concrete logic

If you were wondering for a longtime about why interfaces exist, I guess this is a transcendental moment in your career. Welcome to the Truth! Say goodbye to your old folks in the club of people who don't know why interfaces exist. Have a nice stay in the club of people who already discovered why interfaces exist

So, beyond jokes, we can code the application in order to talk with the defined interface and, during execution time, access to the application settings in order to get the concrete class to be instanced via Reflection

Bibliography usually call interface implementers as "pluggable components". Now…

How do you see if we check again all of these concepts, but in a deeper level, including demos? It's great, isn't it?

Join this webcast, the third in the series of Architecting n-tier applications with Joe Hummel

Creating Dynamic and Configurable Applications

Hasta la vista