Jan '10 21

Recently, a fairly notable icon within the software development community posted some thoughts on Twitter which I found surprising. The individual stated:

“What’s the right number of dependencies to inject? A few. In a very large system, perhaps a few dozen.”

Given that I found this statement to be fairly controversial, I urged the individual to write an article explaining what had brought them to such a conclusion. Later that day, an article was published on the subject explaining their position. After reading the article, it became clear that what was being argued against was the degree of coupling to a dependency injection framework, not dependency injection in general. While minimizing an application’s degree of coupling to any given framework is a goal to be encouraged, the argument was partially based upon a lack of familiarity with the conventional use of dependency injection containers.

In an effort to demonstrate that use of a dependency injection framework is usually unnecessary,the article presents two versions of an example billing application with and without relying upon a framework. The following is a C# version approximating the examples presented within the article:

Dependency Injection Framework Version

    public class Application
    {
        public static void Main()
        {
            IContainer container = new Container().AddConfiguration(BillingConfiguration);
            BillingService billingService = container.Resolve<BillingService>();

            // TODO: do something with the billing service ...
        }
    }

    public class BillingConfiguration : ContainerConfiguration
    {
        protected void Configure()
        {
             Register<ICreditCardService>().As<CreditCardService>();
             Register<ITransactionLog>().As<DatabaseTransactionLog>();
        }
    }

Manual Dependency Injection Version

    public class Application
    {
        public static void Main()
        {
            BillingService billingService = new BillingService(new CreditCardProcessor(), new TransactionLog());

            // TODO: do something with the billing service ...
        }
    }

Comparing the two examples, the second is obviously the more straight forward and concise of the two approaches.

Foreseeing the concern that one might want to use the billing service in a lower layer of the application, the article proceeds to set forth an example which configures a globally accessible static instance of the service within the main method:

    public class Application
    {
        public static void Main()
        {
            BillingService billingService = new BillingService(new CreditCardProcessor(), new TransactionLog());
            BillingService.Instance = billingService;

            // Now the BillingService.Instance can be accessed anywhere within the application
        }
    }

To further address the need to create separate instances of the billing service, the article next presents an example which configures a globally accessible Factory instance which can be accessed from other parts of the application. Perhaps in an attempt to show some recognition of the benefits of using a framework, the Factory is designed to encapsulate the registration and use of a container for retrieving instances of the billing service:

    public class Application
    {
        public static void Main()
        {
            IContainer container = new Container().AddConfiguration(BillingConfiguration);
            BillingService.Factory = new BillingServiceFactory(container);

            // Now we can make new instances of the billing service anywhere within the application
            BillingService billingService = BillingService.Factory.Create();
        }
    }

    public class BillingServiceFactory : ContainerConfiguration
    {
        IContainer _container;

        public BillingServiceFactory(IContainer container)
        {
            _container = container;
        }

        protected void Configure()
        {
             Register<ICreditCardService>().As<CreditCardService>();
             Register<ITransactionLog>().As<DatabaseTransactionLog>();
        }

        public BillingService Create()
        {
            return _container.Resolve<BillingService>() ;
        }
    }

The article concludes by submitting that dependency injection frameworks should only be used for areas of an application that are known extension points, and that in most cases the best course of action is to manually instantiate any needed objects along with their dependencies.

While these examples may seem perfectly sensible to those unfamiliar with using a dependency injection framework, there are several problems with the techniques presented here.

First, the simplicity of these examples fail to highlight the issues involved in real-world applications. Applications designed with an adherence to low-coupling and preferring composition over inheritance often result in object grafts many levels deep. That is to say, the dependencies of one object may have dependencies of their own, which in turn have dependencies of their own, and so forth and so on. While it is possible to use the manual instantiation techniques described in the first example, the resulting code will soon become both unsightly and unwieldy. Couple that with the reuse of components across multiple types and duplication starts to arise. The examples above don’t highlight these issues since they are only working with a simple object graph.

Second, issues arise in the introduction of global variables to access instances of the billing service or the factory. For one, the design becomes more opaque. Classes which reference global resources don’t express their external dependencies through their interface thereby requiring you to look at the code to discover what dependencies are required. Two, this introduces a responsibility to the billing service which isn’t an inherent concern. The responsibility for the creation and lifetime management of the service is a separate concern from the service’s core responsibilities and one which can change for different reasons.

Third, the encapsulation of the container registration and resolution of the billing service within the factory actually serves to more tightly couple the application to the dependency injection framework. What’s been missed in the examples thus far is the fact that the billing service is itself a dependency of other types and they in turn may themselves be dependencies. By ensuring that all types within the system are using dependency injection, the entire dependency chain can be resolved by one call to the container. This eliminates the need to produce specialized factories for each type.

Consider the following example:

    public class Application
    {
        public static void Main()
        {
            new Bootstrapper().Run();
        }
    }

    public class Bootstrapper
    {
        public void Run()
        {
            ConfigureContainer();
            Container.Resolve<IShell>().Show();
        }

        void ConfigureContainer()
        {
            // Configure the container
        }
    }

    public interface IBillingService
    {
        // define billing methods
    }

    public class BillingService : IBillingService
    {
        public BillingService(ICreditCardProcessor creditCardProcessor, ITransactionLog transactionLog) { ... }

        // implement IBillingService methods here
    }

    public interface IShell
    {
         void Show();
    }

    public class Shell : IShell
    {
        public Shell(IBillingService billingService) { ... }

        public void Show() { ... }
    }

In this example the container is only referenced from within the Bootstrapper and the container is only used to resolve an instance of the type IShell. Given that all types have been registered, the container traverses the dependency chain, building up the object graph from the bottom up. This allows the entire application to remain decoupled from the dependency injection framework as well as avoiding the need to create and further maintain type specific factories. As the application grows in complexity, there may be the need to introduce other entry points or strategies for handling lazy-loading, but coupling to the container would remain minimal.

If you find yourself needing to invert your dependencies on an inversion of control framework then you are doing it wrong.

Tagged with:
Oct '09 05

The Arrow Ani-pattern is a name given to the resulting structure produced by using excessive nested conditional operators. The following pseudo-code demonstrates why the name is apt:

if( ... )
{
    if( ... )
    {
        if( ... )
        {
            if( ... )
            {
                if( ... )
                {
                    //--> do something
                }

            }
        }
    }
}

The structure above becomes increasingly problematic as each additional nested condition adds to the cognitive load required to parse the represented logic. According to studies performed by Noam Chomsky and Gerald Weinberg in 1986, few people can easily understand more than three levels of nested conditional statements. It is therefore recommended that techniques for restructuring the code be sought out when this pattern begins to emerge.

Guard Clauses

One approach to refactoring the arrow anti-pattern is to use guard clauses. Guard clauses are a form of assertion which makes a tangible contribution to the logic of the method. By restructuring nested conditional statements to successive conditional exit points, the code becomes easier to understand and eases further refactoring efforts such as method extraction or clause reordering.

void SomeProcess()
{
    if( ... )
        return;

    if( ... )
        return;

    if( ... )
        return;

    if( ... )
        return;

    if( ... )
        return;

    // do something
}

Method Extraction

Another approach especially suited to blocks comprised of nested looping structures is the extraction of segments into separate methods. For each block forming the body of a loop statement, extract the body into a separate method which can then be examined independently of the containing loop statement:

Before

    void SomeProcess()
    {
        while( ... )
        {
            while( ... )
            {
                while( ... )
                {
                    while( ... )
                    {
                    }
                }
            }
        }
    }

After

    void SomeProcess()
    {
        while( ... )
        {
            MethodA();
        }
    }

    void MethodA()
    {
        while( ... )
        {
            MethodB();
        }
    }

    void MethodB()
    {
        while( ... )
        {
            MethodC();
        }
    }

    void MethodC()
    {
        while( ... )
        {
            MethodD();
        }
    }

Logical And/Or

In cases where the nested structure is comprised solely of checks against the state of an object, the conditions can be extracted into a collection of Boolean methods and combined to form a more concise and readable guard clause:

void SomeProcess()
{
    if(ConditionA() &&
          ConditionB() &&
          ConditionC() &&
          (ConditionD1() || ConditionD2()) &&
          ConditionE())
    {
        // do something
    }
}

Composite Specification Chain

As a variant to the previous technique, the Specification pattern can be used in the form of a composite specification chain to render a concise and readable guard clause. Using this technique, specification classes are written to test each case, and the resulting set of specifications are composed into a single composite specification which can evaluate the state of the given object. Due to the encapsulation of the evaluation logic in the form of separate specification classes, this technique has the added benefit of enabling substitution of the specification implementation via the Strategy pattern for test isolation or other variable composition needs.

void SomeProcess()
{
    ISpecification<SomeType> specification = new IsConditionA()
        .And(new IsConditionB())
        .And(new IsConditionC())
        .And(new IsConditionD1().Or(IsConditionD2()))
        .And(new IsConditionE());

    specification.IsSatisfiedBy(this).Then(() => { /* do something */ });
}

Conclusion

The techniques presented here are a few approaches to helping achieve more readable and maintainable code by eliminating the arrow anti-pattern. Through the judicious application of these techniques, developers can in small ways leave their code base cleaner than they found it.

Tagged with:
Jun '09 21

Composite application architecture is an approach to software development which seeks to produce applications which can be constructed from pre-built components, thus allowing a single platform to be more easily customized for end users.

The pre-built components, or modules, comprising a composite application often share data access concerns such as the need to access a central database. The use of object-relational mapping frameworks are an increasingly common strategy for facilitating data access needs. This is due to their ability to minimize much of the repetitive, low-level data access coding often required by more traditional approaches, and their ability to abstract much of the idiosyncrasies of specific database vendors, providing greater potential for portability between vendors.

NHibernate, arguably the leading object-relational mapping framework for the .Net platform, facilitates object-relational mapping through a centrally configured component called the SessionFactory. A SessionFactory is configured with the connection parameters for a specific database along with the mapping meta-data required for associating objects to the relational data within the database.

It is generally advised that a single SessionFactory be created per database. This is both due to the overhead required in its creation, and in order to facilitate various caching strategies such as the caching of generated SQL statements, and of entities across sessions (referred to as the second-level cache).

For composite applications, configuration of the SessionFactory can pose a bit of an obstacle given that any centralization of the mapping configuration would tend to couple otherwise independent and optional modules together. Additionally, a centralized configuration of the mappings for each of the modules precludes encapsulation of the configuration needs within each module, and can introduce maintenance complexity for modules developed by separate development teams or organizations. On the other hand, allowing modules to maintain their own SessionFactory for a shared database instance introduces startup overhead and precludes taking advantage of the caching features of the framework.

As demonstrated in the remainder of this article, one approach to solving these challenges is to create a staged application bootstrapping process which both facilitates decentralized mapping registration and centralized SessionFactory initialization.

While potentially applicable in other usage scenarios, the following approach is based upon the use of Fluent NHibernate, the Prism composite application library, and the staged bootstrapping strategy presented within the article: Enhancing the Prism Module Initialization Lifecycle.

Our first step in demonstrating this strategy will be to create a module named DataModule which will serve as an infrastructure-only Prism module for configuring NHibernate. Using the ModuleBase implementation of IModule presented in the aforementioned article, the OnPreInitialization() and OnPostInitialization() methods will be overridden.

namespace CompositeSpike.Data.Module
{
    public class DataModule : ModuleBase
    {
        readonly IUnityContainer _container;

        public DataModule(IUnityContainer container)
        {
            _container = container;
        }

        protected override void OnPreInitialization()
        {
        }

        protected override void OnPostInitialization()
        {
        }
    }
}

The OnPreInitialization() method will be used to register services to be consumed by other modules while the OnPostInitialization phase will be used to perform the final database configuration.

Next, let’s create a CustomerModule which represents a module using NHibernate for its data access needs. This module need only override the OnInitialization() method to gain access to services registered during the Pre-Initialization bootstrapping phase.

namespace CompositeSpike.Data.Module
{
    public class CustomerModule : ModuleBase
    {
        readonly IUnityContainer _container;

        public DataModule(IUnityContainer container)
        {
            _container = container;
        }

        protected override void OnInitialization()
        {
        }
    }
}

Next, we’ll define a mapping service to be used by our CustomerModule for registering which map types and/or assemblies are to be included during the configuration of the SessionFactory.

namespace CompositeSpike.Data.Services
{
    public interface IMappingRegistryService
    {
        void AddMap() where T : IClassMap;
        void AddMap(Type classMap);
        void AddMapsFromAssemblyOf();
        void AddMapsFromAssembly(Assembly assembly);
    }
}

Next, we’ll provide an internal implementation of the mapping service to be contained within t
he DataModule. Two additional properties, Assemblies and Types, are provided to enable the DataModule to access any mapping types and assemblies registered by modules during the Initialization phase.

namespace CompositeSpike.Data.Module.Services
{
    class MappingRegistryService : IMappingRegistryService
    {
        readonly IList _assemblies;
        readonly List _types;

        public MappingRegistryService()
        {
            _assemblies = new List();
            _types = new List();
        }

        public IEnumerable Assemblies
        {
            get { return _assemblies; }
        }

        public IEnumerable Types
        {
            get { return _types; }
        }

        public void AddMap() where T : IClassMap
        {
            AddMap(typeof (T));
        }

        public void AddMap(Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }

            if (!_types.Contains(type))
            {
                _types.Add(type);
            }
        }

        public void AddMapsFromAssemblyOf()
        {
            AddMapsFromAssembly(typeof (T).Assembly);
        }

        public void AddMapsFromAssembly(Assembly assembly)
        {
            if (!_assemblies.Contains(assembly))
            {
                _assemblies.Add(assembly);
            }
        }
    }
}

With the service defined, let’s return to the DataModule and complete the body of the initialization methods.

To ensure the mapping service is available during the initialization phase of the other modules within the application, the IMappingRegistryService and its internal implementation need to be registered as a singleton with the Unity container during the PreInitialization bootstrapping phase:

        protected override void OnPreInitialization()
        {
            _container.RegisterType(new ContainerControlledLifetimeManager());
        }

After modules have been given an opportunity to register mappings with our service during the Initialization phase, the service can be retrieved and used to supply the class map types and/or assemblies required for the Fluent NHibernate configuration:

        protected override void OnPostInitialization()
        {
            var service = _container.Resolve() as MappingRegistryService;

            ISessionFactory sessionFactory = Fluently.Configure()
                .Database(OracleConfiguration.Oracle9
                              .ConnectionString(
                              c => c.Is(ConfigurationManager.ConnectionStrings["example"].ConnectionString))
                              .ShowSql())
                .Mappings(m =>
                    {
                        service.Types.ForEach(t => m.FluentMappings.Add(t));

                        service.Assemblies.ForEach(a => m.FluentMappings.AddFromAssembly(a));
                    })
                .BuildSessionFactory();

            _container
                .RegisterInstance(new NHibernateDatabaseContext(sessionFactory),
                                  new ContainerControlledLifetimeManager());
        }

Our final step is to complete the initialization method within our CustomerModule to register any desired mappings to be used by the DataModule:

        protected override void OnInitialization()
        {
            var dataMappingService = _container.Resolve();
            if (dataMappingService != null) dataMappingService.AddMapsFromAssemblyOf();
        }

That concludes our example.

By utilizing a mapping service in conjunction with a multi-phased initialization strategy, a proper level of separation of concerns can be maintained for the modules within a composite application while at the same time utilizing NHibernate’s SessionFactory in the prescribed manner.

Tagged with:
preload preload preload