Layered Architecture, Dependency Injection, and Dependency Inversion

Layered Architecture, Dependency Injection, and Dependency Inversion

ost developers understand the value of the layered approach to architecture. The main principle behind layered architectures is that of “separation of responsibility”. Each layer is responsible for a finite amount of work. Any work that cannot (read should not) be done by a particular layer gets delegated to a layer more appropriate for handling the task.

Unfortunately, people using layered architectures can often run into a scenario where they introduce an unnecessary amount of coupling between layers of their application. A high degree of coupling is one factor that can lead to fragile application architectures that are difficult to change or extend.

In this article, I’ll take a project that was built using techniques that result in fragile, hard-to-test code and introduce some principles, techniques, and refactoring strategies that will help you realize flexibility and testability in your applications.

The first part of this article deals with introducing a design principle that will enable you to take advantage of layered architectures in a much cleaner fashion, and then demonstrates how introducing dependency injection into the mix can help you realize your goals for pluggable application architectures.

Figure 1. A Simple Screen: This simple screen looks like it should be easy to build, right?

The Case at Hand
Assume for a moment that Figure 1 is a screen that I am developing for viewing information on Employees that work with my company. Being that it’s such a “simple” screen, I dive in and quickly hammer out the code shown in Listing 1. (In case anyone asks, I would never do this!)

I’ll pause for a second to allow the utter travesty of the code in Listing 1 to truly sink in! The code breaks several application architecture rules:

  • Hard-coded connection strings.
  • User interface has intimate knowledge of database tables.
  • User interface is responsible for mapping database data into domain objects.
  • Coding to implementations not abstractions.
  • Forget about that last bullet point for a little while. I can start to remedy the first three items by introducing a layered application architecture.

Separating Responsibilities with a Layered Architecture

Software developers use the term cohesion to describe the relation and focus of a particular component.

One of the main issues with the code in Listing 1 is that it takes the single responsibility principle and throws it completely out of the window. The single responsibility principle simply states that “every object should have a single responsibility and therefore only a single reason to change.” If you are already familiar with the term cohesion, you can quickly identify that a component that follows this principle can often be described as a “highly cohesive” component.

If I took a moment to ask the question, “What should the main responsibility of the View Employees web page be?” The simple answer is that it should only be dealing with the rendering of a set of employees to the user. However, if I take a look at the code-behind, the reality of the situation is quite different. Instead of methods focused around the rendering of employees to the user, the component is currently responsible for:

  • Creating a connection to the database
  • Creating a SQL statement to pull the appropriate information from the database
  • Disposing of expensive resources (connection, reader, etc.)
  • Mapping the database information to a domain representation of the data
  • Rendering the information to the user

As you can see from this short list, this component has far too many responsibilities. To make matters worse, only one of the responsibilities has anything to do with “rendering” a list of employees to the user. If this does not smell of low cohesion, I don’t know what does.

Figure 2. Layer Diagram: Here’s a proposed high-level diagram for the separate layers.

For quite some time, most developers have been aware of the value of introducing the concept of n-tier/layered architectures into their applications to address this very issue. In short, the introduction of a layered architecture can ensure that each layer (as pragmatically as possible) can adhere to the single responsibility principle. Figure 2 shows a proposed high-level diagram for the separate layers that will make up the application.

I am going to tackle refactoring this application from the top down. I can first make use of the “passive view” variant of the “model view presenter” design pattern to deal with the abuse of responsibility in the code-behind for the web page. I will not dive into the details of this pattern in this article; you can take a look at an article I wrote last year that discusses the pattern in more detail)

The first refactoring task is to pull out code not directly related to the responsibility of “rendering employees” (read: pull pretty much all code from the code-behind!). The following is now the code-behind for the web page:

   public partial class       ViewEmployeesWithAdditionOfPresenter : Page,       IEmployeeView   {      private ViewEmployeesPresenterLowCohesion presenter;      protected override void OnInit(EventArgs e)      {         base.OnInit(e);         presenter = new          ViewEmployeesPresenterLowCohesion(this);      }         public IList Employees      {         set         {            this.employeesRepeater.DataSource = value;            this.employeesRepeater.DataBind();         }      }   }

Compared to Listing 1, the difference here is night and day. If you are not familiar with the passive view pattern, here’s a quick description:

  • View implementation (web page) implements an interface that is consumed by the presenter.
  • The View interface exposes events that are implemented by the View (web page) and subscribed to by the presenter.
  • The View raises events in response to events that occur on itself (for example, “Button is clicked,” “Load is happening”); these events are in turn handled by the presenter.
  • The presenter processes the event accordingly and may push information back to the view using the View interface.
  • Using the View interface allows the presenter to remain loosely coupled to any particular UI technology (for example, ASP.NET).

Listing 2 shows the first iteration of the presenter class.

From the looks of Listing 2 all that I have managed to accomplish is to push the messiness that was originally located in the code-behind for the web page and move it into another class. However, with the introduction of the interface for the view, I have introduced a concept that is critical in creating flexible layered architectures: the dependency inversion principle.

Editor’s Note: This article was first published in the May/June 2007 issue of CoDe Magazine, and is reprinted here by permission.

The Dependency Inversion Principle
As I mentioned, I stealthily slipped in the addition of this principle by introducing the passive view pattern?in particular, an interface (abstraction) for the view. The code for the View interface is as follows:

   public interface IEmployeeView   {      event EventHandler Load;      bool IsPostBack { get; }      IList Employees { set; }   }

Pretty simple. Notice that the Load event is defined on the View interface, but you probably did not see an explicit implementation in the code-behind for the web page. This is because all web pages already define a Load event (with the same delegate signature), which satisfies the requirements of the interface. The same goes for the IsPostback property (already satisfied by the Page class). So why introduce an interface at all? The reason is that by coding to an interface (or an abstraction), the presenter can now talk to any object that implements the interface, whether it is a Windows Form, a mobile web control, or a web page. The presenter does not care about the actual implementation because it will always be talking to that implementation through an abstraction?the interface. This point demonstrates and introduces the importance of the dependency inversion principle, which can be described simply as:

“High-level components should not depend on low-level components; they should both depend on interfaces.”

I will take that principle and utilize it to further clean up the code in the presenter.

I can now safely forget about the web page and its accompanying code-behind as it will remain static for the remainder of the refactoring process. Again, this speaks to the beauty of layered architecture and its ability to allow me to radically enhance the code without causing unnecessary ripple effects. In switching focus to the presenter, I am going to treat it as the “high level” component. What low-level components does it currently depend upon? The following code snippet should give you a couple of clues:

   using (connection = new       SqlConnection(ConnectionString))   {      SqlCommand command = connection.CreateCommand();      command.CommandText = "SELECT * FROM Employees";      command.CommandType = CommandType.Text;      connection.Open();      using (SqlDataReader          reader = command.ExecuteReader(            CommandBehavior.CloseConnection))      {         DataTable results = new DataTable();         results.Load(reader);         return results;      }   }

The preceding code couples the presenter to SqlConnection, SqlCommand, and SqlDataReader objects. In reality, worse than the coupling is the fact that this functionality does not really belong in the presentation layer of a project, because it still unnecessarily couples my presentation layer to the underlying physical database that is serving data to this application.

How can I address this problem? As the old computer-science axiom quotes, “Another layer of indirection will solve any problem.” I am going to clean up the code in the presenter by adding a service layer to the project. For a detailed description of what a service layer is you can read this article. In the context of this article, all you need to focus on is that I am using the service layer as a fa?ade to shield the presentation layer from the details of executing application functionality (in this scenario, retrieving a set of employees). I am going to utilize dependency inversion to come up with a contract (abstraction) for a service-layer component that will provide me the ability to “Get All Employees.”

Examining the presenter closely, I can identify that its main role is to provide the View with a list of employees. It should not matter how that list is retrieved?that falls into the realm of the service layer (ultimately a mapper layer, but I’ll omit talking about that in this article). With the main role identified, I come up with an interface for the service-layer component that the presenter will talk to:

   public interface IEmployeeTask   {      IList       GetAllEmployees();   }

Yes, it’s that simple. Again, following the dependency inversion principle leads me to believe that the presenter now has more than just a dependency on the View. Prior to the introduction of the service layer, the presenter was responsible for work that will (eventually) be pushed down into a service layer. The beauty of coding to abstractions is that the presenter has to talk only to a contract. At compile time the presenter does not know (or care) whether that contract is implemented. This allows me to complete the code for my presenter without the need for an actual concrete implementation of the service-layer component to even exist. Listing 3 shows the presenter refactored by introducing a dependency on a lower-layer component.

This cleans things up considerably. By utilizing the dependency inversion principle I have refactored the presenter into a much more highly cohesive unit. It is responsible for pushing data to the view (by means of an interface); and it retrieves the data from a service-layer component, that it also talks to using a contract (interface). In completing the refactoring for the presenter, I also quietly snuck in a new technique that makes utilizing dependency inversion all the more appealing: dependency injection.

Dependency Injection
If you take a closer look at Listing 3 you will see something very important happening in the constructor of the presenter:

   public      ViewEmployeesPresenter(IEmployeeView     view, IEmployeeTask task)

Even though the presenter has its own cohesive set of responsibilities, it cannot accomplish its responsibilities without leaning on its dependencies. It just so happens that those dependencies are provided to it at the time of creation. This is a type of dependency injection called constructor-based dependency injection.

The main idea behind dependency injection is that if an object relies on other “components” to help it accomplish its work, it should not be responsible for creating those components; rather, the components it depends on should be injected into it in the form of abstractions.

The two most popular types of dependency injection are: constructor injection and setter injection.

In constructor injection, the object with dependencies is provided with all of its dependencies at the time of instantiation. It does not matter who creates it?it has to be given all that it needs to do its job. If it is not provided with all that it needs (read: null is passed in as a dependency), the object should not be expected to be able to complete its work. The one disadvantage to constructor-based injection is that it can get a little unwieldy if the object has a lot of dependencies that you have to provide to the constructor (of course, you could shield programmers from this by using a factory).

Setter injection uses a slightly different technique and almost always relies on a factory to create the object and wire it up with its dependencies. In setter injection there is no special constructor on the object with dependencies; instead, all its dependencies are injected by the factory through setter properties that the object exposes for the dependencies it needs. A disadvantage of setter-based dependency injection is that omitting the factory can unnecessarily couple components that use the object to the specific implementations of the dependencies the object requires.

The whole concept of dependency injection hinges around the concept of programming to abstractions. In this scenario the presenter has a dependency on:

  • A “view” that can render the information that is pushed to it.
  • A “service” that can execute application functionality on behalf of the presenter.

From a testability perspective, utilizing both dependency inversion and dependency injection allows for an increased level of testability as well as lower coupling between components of an application. The following code demonstrates how to utilize a combination of unit testing and mock objects to verify that when the presenter is constructed it subscribes to the Load event on the View interface:

   [Test]   public void ShouldSubscribeToViewEventsOnConstruction()   {       MockRepository mockery = new MockRepository();       IEmployeeView mockView = mockery.CreateMock();       IEmployeeTask mockTask = mockery.CreateMock();       mockView.Load += delegate { };       LastCall.IgnoreArguments();       mockery.ReplayAll();       ViewEmployeesPresenter presenter = new          ViewEmployeesPresenter(mockView, mockTask);       mockery.VerifyAll();   }

The preceding code uses a mock object framework called Rhino Mocks and the NUnit unit testing framework. (As a practitioner of TDD, I would usually write this test first to drive out the functionality of the presenter; however, for this article I chose to not cloud the topic with another conversation about TDD!) You can find the accompanying code that makes this test pass in the presenter class itself:

   public ViewEmployeesPresenter(IEmployeeView view,       IEmployeeTask task)   {      this.view = view;      this.task = task;      HookupEventHandlersTo(view);   }      private void HookupEventHandlersTo(IEmployeeView view)   {       view.Load += delegate {          LoadEmployees(); };   }

Notice that the constructor calls the HookupEventHandlersTo method, which in turn subscribes to the Load event defined by the View interface.

From a maintainability perspective I now have a guaranteed way of ensuring that whenever the presenter is constructed it subscribes to the Load event on the view. Of course, the actual functionality comes when the Load event on the view is triggered. This is where the presenter can communicate to the service layer and request a list of all employees, which it then pushes back to the view. Yet again, leveraging dependency injection allows me to easily write a test for this scenario. And again, I can substitute mock objects in place of “real” objects and the presenter is none the wiser because it is dependent on abstractions, not implementations.

The presenter has been relegated to nothing more than a component that acts on and reacts to its dependencies. The component that the presenter consumes seems to be the place where all the action should be happening. I’ll drill down into the service layer and show how you can apply the techniques of dependency inversion and dependency injection to create a clean implementation of the IEmployeeTask interface.

Dependency Injection and Inversion in the Service Layer
Listing 4 shows that all the code stripped from the presenter seems to have gone the way of the Dodo bird. I can address that by creating an implementation of the IEmployeeTask interface in the service layer. Listing 5 shows my first take at an implementation of the service. This can’t be right. Did I do all that work to clean up my UI and presenter only to come down to the service layer and duplicate the mistakes that started me down this path in the first place? Armed with the new knowledge I have about dependency inversion and dependency injection I can now clean up the dependency on implementations rather than abstractions. I’ll start by introducing a new interface into the mix:

   public interface IConnectionFactory   {      IDbConnection Create();   }

With the IConnectionFactory interface created I can use dependency injection to ensure that the service layer class is constructed with an IConnectionFactory:

   public EmployeeTaskLowCohesion      NoDependencyInversion(      ConnectionFactory connectionFactory)   {      this.connectionFactory =          connectionFactory;   }

That small change allows me to change the code in the GetEmployees method to that shown below:

   public DataTable GetEmployees()   {      using (IDbConnection connection  =          connectionFactory.Create())      {         using (IDbCommand command =             connection.CreateCommand())         {            command.CommandText =                "SELECT * FROM Employees";            command.CommandType = CommandType.Text;            connection.Open();            using (IDataReader reader =                command.ExecuteReader(               CommandBehavior.CloseConnection))            {               DataTable results = new DataTable();               results.Load(reader);               return results;            }         }      }   }

Notice that the GetEmployees method is no longer coded to an explicit SqlClient implementation; it now uses abstractions defined in the System.Data namespace, which (with a little work) could allow this component to seamlessly work with any database. The only differentiator would be the implementation of IConnectionFactory that would have to be plugged in to create a connection bound to a particular database (Oracle, SQL, MySQL, etc.). Again, another positive side effect of this style of coding is that it allows me to easily test the behavior of this class without actually pointing it at a real database.

So, am I done with the current implementation of IEmployeeTask? Absolutely not. In my opinion, the current implementation still has too many responsibilities that should be placed in other objects (even completely different layers). Rather than drill down into more abstractions, I would rather spend the remainder of this article discussing the wiring up of all of these dependencies to one another. You can look at the code that accompanies this article to get an idea of how I cleaned up the service layer class, as well as separated responsibilities into more discrete layers.

Gluing It All Together
With all of these abstractions and dependencies being injected left, right, and center, some of you might be asking the question, “Who injects the dependencies?” I’ll revisit the presenter and the accompanying web page. Remember the constructor for the presenter:

   public ViewEmployeesPresenter(      IEmployeeView view, IEmployeeTask task)

I can’t construct the presenter without giving it both the view it is working with and the service layer it makes requests of. This poses a problem for me because the code-behind for the web page needs to instantiate the presenter that will work with it (there are other solutions to this that are outside the scope of this article):

   presenter = new ViewEmployeesPresenter(this);

This would be fine if the presenter had a dependency only on the view. Unfortunately, it does not. The presenter must have both of its dependencies satisfied at the time of creation. A quick way to solve this problem would be to add a reference from the web project to the service layer project, and then do this in my code-behind for the web page:

   presenter = new ViewEmployeesPresenter(      this, new EmployeeTask());

Unfortunately, this causes the view to not just be responsible for creating its presenter, it also now has to create and be coupled to the dependencies the presenter is reliant on. That seems to defeat the purpose of going down this road in the first place.

You can solve this problem in a multitude of ways starting from simplistic and “coupled” to more involved and loosely coupled. I’ll start off by examining the simplistic approach.

I want to ensure that the only thing the web page needs to do to construct the presenter is:

   presenter = new ViewEmployeesPresenter(this);

To do this I will take advantage of constructor chaining to offer a simple constructor that the view can consume. This “convenience” constructor will call into the “greedy” constructor (the one that requires all of the dependencies) providing it with whatever it needs:

   public ViewEmployeesPresenter(      IEmployeeView view):this(view,      new EmployeeTask())   {       }   public ViewEmployeesPresenter(      IEmployeeView view,       IEmployeeTask task)

This frees the view from needing to know anything about any dependencies (other than itself) that the presenter requires. This is a simple solution, and it introduces coupling between the presenter and a particular implementation of one of its dependencies. However, the coupling is not terrible as it only occurs in the convenience constructor. Everywhere else in the presenter it interacts with its dependency by means of the interface. The coupling exists because now the presenter is responsible for creating its dependency (an IEmployeeTask implementation). Of course, being pragmatic, if you were trying to introduce the concepts of dependency injection and dependency inversion into your own applications, this would allow you a good starting point?with an acceptable level of coupling.

However, if you want to ensure that classes with dependencies are in no way coupled to implementations of those dependencies, you can utilize the features of a service locator.

Dependency Injection with Service Locators
To completely eliminate the need for the presenter to be aware of which implementation of IEmployeeTask it should use, you must add a new element into the mix. In the realm of dependency injection, a service locator is simply an object that knows how to retrieve dependencies for other objects. In this scenario, it would be the role of the service locator to find an implementation of IEmployeeTask that the presenter can work with. All of you who have been reading along probably know the answer to the question, “Does this mean that my presenter will now have a dependency on this service locator?” Absolutely. Then you might ask, “Does this mean I should start changing the constructor of my presenter to also allow it to accept a service locator?” You could do that. Unfortunately, if other classes down the road want to utilize the services of the locator to resolve their dependencies, they too would require a constructor that allowed them to accept an interface to the service locator. This seems like a little too intrusive to the architecture and more work than is necessary.

The solution I am going to propose is one that you can use immediately if you want to start utilizing service locators in your own projects. It is also a solution that can scale when you start using full-blown dependency injection frameworks like Windsor Castle, a popular, open-source dependency injection framework. I am first going to create an interface for the service locator:

   public interface IDependencyResolver :      IDisposable   {   void RegisterImplmentationOf(      T component);      T GetImplementationOf();   }

The preceding code uses generic methods to avoid the need to cast when invoking the locator from client methods. I stated that I want existing classes to be able to consume the functionality provided by the service locator without a need to have an explicit parameter dependency on it. To accomplish this I will use a static class that will delegate all of its calls to any particular implementation of the service locator interface:

   public static  class DependencyResolver   {      private static IDependencyResolver          resolver;      public static void RegisterResolver(         IDependencyResolver resolver)      {         DependencyResolver.resolver = resolver;          }      public static T GetImplementationOf()      {         return resolver.GetImplementationOf();      }   }

Notice that the DependencyResolver class has a method called RegisterResolver which is passed an implementation of IDependencyResolver that it can forward its calls onto. What does this translate to from the perspective of the presenter? Instead of it needing to have knowledge of the EmployeeTask implementation of IEmployeeTask, it can now use the DependencyResolver class to locate an implementation of IEmployeeTask. This changes the constructors in EmployeePresenter from this:

   Public ViewEmployeesPresenter(      IEmployeeView view):this(      view,new EmployeeTask())   {               }      public ViewEmployeesPresenter(      IEmployeeView view,       IEmployeeTask task)

To this:

   public ViewEmployeesPresenter(      IEmployeeView view):this(view,      DependencyResolver.GetImplementationOf      ())   {               }   public ViewEmployeesPresenter(      IEmployeeView view,       IEmployeeTask task)

Notice that I am still making use of the greedy constructor that requires everything that the presenter requires. I can use this constructor from a testing perspective to verify the behavior of the presenter. In the constructor that the web page uses, the presenter uses the DependencyResolver and asks it to retrieve an implementation of an IEmployeeTask. Now, nothing in the presenter couples it to the EmployeeTask component!

I chose to couple the presenter to the service locator by using the static DependencyResolver class. Someone out there right now is screaming, “static classes are evil!” In addition, lots of people scream, “singletons are evil.” In either case, they are not evil, as long as they allow for testability, which is typically not easy to do with traditional singleton or static class implementations. This scenario makes testability easy because the DependencyResolver static class does nothing more than delegate its work to an IDependencyResolver implementation (which you can easily fake at test time).

The advantage of using the interface (IDependencyResolver) is that when I am first starting down the service locator route, I may be content with creating my own service locator that gets configured at application startup. Listing 5 shows the code for such a locator. Here’s an example that configures such a locator in a class invoked at application startup:

   public class ApplicationStartupTask   {              public static void Initialize()      {         IDependencyResolver resolver = new            CustomDependencyResolver();         resolver.RegisterImplmentationOf            (new EmployeeTask());         DependencyResolver.RegisterResolver(resolver);      }   }

Notice that I explicitly tell the service locator when asked for implementations of IEmployeeTask to return the EmployeeTask object. This particular implementation also enforces the EmployeeTask to be a singleton in this application, even though it is not explicitly marked as a singleton. The final step registers the service locator with the DependencyResolver so that all clients can access its functionality.

If you want more functionality out of your service locator you may not want to code it yourself. By using the IDependencyResolver interface, you can easily switch to an implementation that leverages already existing dependency injection frameworks. Listing 6 shows an example of an IDependencyResolver implementation coded to work with Windsor Castle.

The value of coding to interfaces means that when (and if) I switch to Windsor (or another dependency injection framework), very little of my client code should change. In fact, the only change required to use Windsor is to change the ApplicationStartupTask class as follows:

   public class ApplicationStartupTask   {      private static readonly string          ContainerConfigurationPath =          Path.Combine(AppDomain.         CurrentDomain.BaseDirectory,          "");      public static void Initialize()      {         IWindsorContainer container = new             WindsorContainer();         BooReader.Read(container, ContainerConfigurationPath);         DependencyResolver.RegisterResolver(            new WindsorDependencyContainer(container));      }   }

The advantage of using a full-featured framework such as Windsor is that there is no longer any code (not even in ApplicationStartUp) tied to particular implementations of dependencies. Objects that need dependencies can still ask the DependencyResolver class to retrieve them and the DependencyResolver will use whatever implementation of IDependencyResolver was provided to it to satisfy the request.

In the downloadable source code accompanying this article, you can see how I configure the Windsor container using Binsor, a great tool for configuring Windsor without XML files. Ayende Rahien developed Binsor and it allows me to configure dependencies using configurations stored outside of the application.

Wrapping Up
I have covered a lot of ground in this article. I started with a single-tiered application that breaks many of the best practices that many of you are already well aware of. I introduced a layered architecture and some refactoring techniques that drove me to use the dependency inversion principle. You can see the benefit of coding to abstractions vs. implementations. To top it off, I introduced the concepts of dependency injection and service locators as tools to help you realize the benefit of coding to abstractions.

You now have another arsenal of tips and techniques that you can start applying to realize more loosely coupled solutions in your application architectures.

See also  Comparing different methods of testing your Infrastructure-as-Code

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist