Layered Architecture, Dependency Injection, and Dependency Inversion

Building loosely coupled application architectures requires more than just separating your application into different layers.

by Jean-Paul S. Boodhoo

Jun 18, 2007

Page 1 of 4

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:

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.

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:

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.