Software Design Blog

Journey of Rinat Abdullin

Component-Driven Development and IoC Containers

Nicholas Blumhardt has recently made an appearance on .NET Rocks (that’s the podcast I’m listening on a regular basis). The talk was extremely interesting - starting from Autofac and going all the way to the component driven development philosophy.

Let’s try to reiterate and summarize some ideas about the Component Driven Development, IoC containers and evolving enterprise applications in general.

What is a component-driven development?

We could try to describe component-driven development as an approach in which code is fragmented into reusable and testable components that are combined together to form application foundation for delivering business functionality. The combination and management of components is generally delegated to Inversion of Control Container.

A component itself is a class that implements some service contract and explicitly defines the dependencies that it needs in order to fulfill this contract. Actual implementation is hidden from everybody else outside the component.

An example of component would be:

[Immutable]
public sealed class CustomerRepository : ICustomerRepository
{
  private readonly IDalSettings _dal;

  public CustomerRepository(IDalSettings dal)
  {
    _dal = dal;
  }

  public Guid CreateCustomer(Customer customer)
  {
    return _dal
      .CreateCommand(Queries.CreateCustomer)
      .With(() => customer.Name)
      .With(() => customer.CompanyUrl)
      .ExecuteAndReturn<Guid>();
  }

  Customer ICustomerRepository.GetCustomer(Guid customerID)
  {
    return _dal
      .CreateCommand(Queries.GetCustomer)
      .With(() => customerID)
      .ExecuteAndReturn(Queries.CustomerSelector);
  }
}

As you can see, component explicitly declares its dependency on the IDalSettings and implements following service contract:

public interface ICustomerRepository
{
  Guid CreateCustomer(Customer customer);
  Customer GetCustomer(Guid customerID);
}

Components tend to be rather concrete and stick to the single responsibility principle, where each class is dealing with a single and a rather specific task.

I personally perceive components as low-level building blocks that are just one level higher than the language elements and elements from the Base Class Library of .NET. Or you could also look at the components as elements from the Domain Specific Class Library, that is unique to your specific domain.

Side note. In reality, the boundary between these BCL and DSCLs is blurred a bit. This allows, for example, to move certain components from domain libraries (provided, these building blocks are abstracted and reusable enough) into libraries shared between multiple projects. Most of the time these components are about cross-cutting concerns of an application. An example of such a library would be Lokad.Shared library.

These components are used to create a foundation for delivering an actual enterprise application. This foundation is established by wiring and configuring components together through an Inversion of Control (IoC) technology. Inversion of Control Containers generally take care of various things, relieving us from the need to do them by hand. Examples of these things are:

  • injecting cross-cutting concerns into the application;
  • managing life cycles of components and ensuring their deterministic disposal;
  • handling dependency resolutions, wiring and configuration.

This forms the application infrastructure (almost an Infrastructure of Components) that could be used to deliver a variety of actual applications in the same domain.

No matter, how we organize our components, there are a few common rules:

  • Every component is registered in this infrastructure by a service contract, while the implementation specifics stay hidden from the higher logical levels and even neighboring components.
  • Components declare their dependencies explicitly in the constructor (it is advised to avoid property injection, as it tends to complicate the interactions).
  • Generally in .NET (although not always) components are sealed classes that do not inherit from any other base class, while implementing an interface or two. We are favoring composition here.
  • Most of the time, components are immutable and are merely an object-oriented representation of a function, which receives (and memorizes) its parameters via the constructor.
  • Additionally, it usually is a good practice to implement interfaces explicitly for IoC in .NET. This will reduce the temptation to use components directly, instead of referring to their service contracts (aside from the fact that explicitly implemented classes do not trigger “Missing XML documentation” warnings).

Logical encapsulation and reliance on the service contracts significantly simplifies code reuse and unit testing, thus promoting good development practices. It also increases flexibility, since you could rather easily substitute one component for another, as long as they both abide to the same contract.

Component Layers

Sometimes building blocks are logically organized into the layers in order to make application feel more simple and decoupled. This makes it more manageable and flexible in the long run.

Components in one layer tend to share some common features for the services they are providing. Also they tend to:

  • be located in the same project and even namespace;
  • have similar dependency requirements;
  • use similar resources and libraries;
  • be grouped within the same container if nested container hierarchy is used.

Let’s have a look at a sample picture below:

Sample Component Infrastructure

For example, DAL Layer is about basic components that provide raw access to the database, abstracting away configuration settings. They are consumed by other components implementing certain service contracts about persisting, querying and manipulating objects (that’s the Repository Layer). Repositories could be consumed by the decorators that adhere to the same contracts but inject cross-cutting concerns along the way (most common are: performance monitoring and retrying on dead-lock and timeout exceptions).

Repository interfaces could be exposed to the higher-level component layer within the infrastructure - Service Layer. This layer, in its turn, would use these contracts to expose functionality for:

  • API adapters, exposing services provided by an application via WCF, SOAP, REST or whatever communication technology is being used (validation, paging, authentication and authorization concerns are injected along the way).

  • Web applications, providing human-manageable UI to work with the same services Automation Engines, leveraging repository and service interfaces to provide some business functionality (notifications, workflows, external integration etc).

If we look at the component infrastructure from the perspective of the top-level consumer, then we will not see something solid. There is just a set of service contracts that are readily available to be consumed and used.

We don’t have to worry about relations and dependencies between the components, because IoC Container handles it all for us, while take care of complex object hierarhies and activation chains. More than that, logically we are not even able to care about such things, because the implementation and interface details are hidden from as as well.

That’s our highest level development language, if you wish. In it, every service contract represents some syntax element that could be combined with the others in order to deliver business functionality.

That’s the first article from the short series of two on Component-Driven Development. In the next one I’ll talk about some common strategies for developing greenfield applications CDD-style and migrating existing legacy applications towards the brigher Component-driven and IoC-powered future (which happens to have less development friction and consume less resources).

Meanwhile you can: