In traditional software and web applications application layering is one of the tenets of good application design and architecture. It stems from the separation of concerns principle in computer science which is the process of separating applications and programs into distinct features that overlap in functionality as little as possible. Hence, the single responsibility principle and DRY concepts in software engineering and object-oriented programming.
Typically, in layered applications, a given application layer should only communicate with and depend on the layer directly below it.
Take the following diagram for example, taken from the Microsoft Application Architecture Guide v2 (I added the red arrow indicators that typically represent where dependencies are):
In this example, the Presentation Layer would talk to and depend on the Business Layer. The Business Layer would talk to and depend on the Data Layer. The Data Layer would talk to and depend on the database.
This is generally considered good application design despite there being dependencies between layers. However, traditionally, layer n-1 dependency (one layer dependency) has been the normal and accepted practice. But experience tells us that all-too-often we find dependencies on more than just one layer. In fact, we may find dependencies between multiple layers…or worse….between all layers, ending up with something like this:
The application may work fine. In fact, it may work perfectly. But the net effect, in the case of either diagram, is that, with each dependency, change becomes more difficult. Our apps become more difficult to maintain, more difficult to test, and more difficult to change which can result in longer development cycles, higher costs and increased risk of failure on our projects.
Usually, these dependencies come in the form of concrete class names. For example:
MyService service = new MyService();
As Scott Hanselman would say, “anytime you find yourself writing code like this, quit your job and go do something else.” No seriously, you should at least stop and acknowledge what this really is – a dependency on an implementation. Sure, factory classes and singletons come in handy to remove the need to new things up, but we still end up with a dependency – only now we’re dependent on the Singleton or the Factory.
Ideally, we want to declare a dependency on “some thing” without saying what that “some thing” is.
A simplified analogy
If you are hungry, you could ask your friend, “do you have a hamburger?” in which case you are expressing a need for an explicit implementation of something that satisfies hunger (a hamburger). If your friend has a hamburger, great! He would give it to you, you would eat it, and you wouldn’t be hungry anymore. Problem solved! But if your friend does not have a hamburger, you’d still be hungry – mainly because you were too specific in your request. Now, instead of asking for the hambuger, you could ask your friend, “do you have anything to eat?” In this case, you are expressing the “need” (food or something that satisfies hunger) vs. a concrete implementation. This way, if your friend has anything to eat he can give it to you (regardless of whether it is a hamburger or not) and you won’t go hungry. Any food would suffice.
What’s the point?
The point is that by being less specific in our request for food, we are more adaptable. The same is true with software. If we simply declare dependencies on contracts (interfaces), rather than implementations, our software becomes more adaptable and easier to change. Dependency Injection exists to help you do just that.
The goal of Dependency Injection (DI for short) is to separate behavior (or implementation) from dependency resolution, which is really just encapsulation – one of the main principles of computer science and object-oriented programming. I like to think of Dependency Injection as “intra-app SOA”; the end result being a highly decoupled application composed of “services” with explicit service boundaries and contracts (or service interfaces) where any given application layer has no knowledge of any other layers. It cares not the number of layers nor the implementation within each layer. Each layer simply depends on a contract and can be reasonably sure that at runtime there will be at least one implementation available to satisfy that contract. With Dependency Injection on our side, the above diagram might change to look something like this:
At first glance, this doesn’t look much different from the first diagram. We still have “dependencies.” However, now we are dependent on a contract, not an actual implementation. This provides enormous benefits to us as application developers because our application layers are now plug-n-play. They are hot-swappable like hard drives in a RAID configuration. We can change the implementation of a layer and as long as we implement the agreed upon interface, we can rest assured we won’t break something in another layer.
Of course, we still have to unit test our new layer to make sure we don’t have any internal bugs, but as long as other layers only depend on the interface (not the implementation) we know we can reliably swap out an implementation without affecting other parts of an application or system. Ideally, each implementation of an application layer becomes a “black box” to the other layers with which it interacts.
In the case of our MyService above. Instead of writing our code like: MyService service = new MyService();
Using Dependency Injection, we would instead write; IService service { get; set; }; as a property on our class or we would use constructor injection and have something like.
public class HomeController(IService service)
{
}
As you can see, we are now expressing a dependency on a contract (an interface) rather than an implementation and we are now “wired” for a Dependency Injection/IoC framework to resolve these dependencies for us without explicitly identifying them in our code.
You might say, “that’s all fine and good, but how do I make sure that my application is only dependent on contracts/interfaces?” More importantly, for existing applications that might not have been written this way, how do I find all the application dependencies and extract them into interfaces in order to move to a DI-friendly application architecture.
This is where being a .NET developer in this day and age makes your life much easier. Thanks to some new features in Visual Studio 2010, you can now answer those questions fairly easily. If you have one of the higher level VS2010 SKUs (Premium and Ultimate), you have the ability to create Application Architecture Layer diagrams. While you may have known that, you may not be aware that you can also validate an application against a layer diagram and have Visual Studio generate the dependencies between your layers so that you can see the dependencies between layers.
Using this feature, not only can you say, “my application should look like this” by creating an application layer diagram, but with the validation feature, you can ask the question, “does my application look like this?”
To get started with this feature, let’s take the following ASP.NET MVC project that I’ve setup as an example for this post. (I’ve circled the areas of immediate interest)
As you can see, I have actually organized my solution folders to mimic my application layering. We have a Repository/Data Access layer, we have a Services layer and we have a Presentation/UI layer. You’ll also notice that we have a Contracts project (or layer) which contains our interfaces.
So our dependencies go something like this:
- Site (our ASP.NET MVC app) depends on an IUserService.
- Our Services, depend on an IUserRepository and IUser.
- Our Repositories depend on the IUser contract since that is the contract they return from their operations.
There are no dependencies between layers. They only depend on interfaces in the Contracts project.
You may have also noticed that there are four different “repository” projects and three different “services” projects. This is where the plug-n-play concept I discussed above comes in to play. ASP.NET MVC 2 comes with great support for Dependency Injection (which MVC 3 builds upon) which allows you to plug-in your DI/IoC framework of choice for all your DI needs. In my case, I’m using Autofac. ASP.NET MVC provides an extensibility point that allows you to say, “anytime my application needs something to satisfy a contract/interface, here’s where to find it.” That “where to find it” part is where an DI/IoC framework plugs-in to satisfy the dependencies of your application without having to declare explicit dependencies between your application layers and/or components.
Frameworks such as Autofac, Ninject, Castle Windsor, StructureMap and Unity, all have some concept of a “registry” which is basically an Interface-to-Implementation mapping or dictionary. With our MyService example above, we would be able to register our implementation MyService as the service that satisfies all dependencies on IService. Then, any time the application needs an implementation of IService, it will ask the DI container to provide one from its registry.
I won’t go into the details of how these dependencies get registered with or resolved by the DI/IoC frameworks. I’ll leave that for you to read about on your own or to explorer by digging through the attached sample code.
Instead, we’ll jump right into the benefits that using Dependency Injection provide.
So, in the diagram, we happen to have four different implementations of a DataAccessLayer.
- DatabaseRepository – persists data to a SQL database
- FakeRepository – fakes the peristence to an underlying data store (ideal for UnitTesting )
- MongoDbRepository – persists data to a MongoDb database
- XmlRepository – persists data to an Xml file
All four Repository projects implement the IUserRepository contract/interface that our Services layer depends on. This allows us to reliably swap out one for another without affecting any code in the services layer at all. So, it would be trivial to add another repository that persisted data to Oracle, SQL Azure, Amazon SimpleDB, Microsoft Access, Excel, a flat-file, what have you – just so long as the repository implements the IUserRepository interface, we’re good.
Likewise, we have three different implementations of our Services layer.
- CachingService – retrieves data from an IUserRepository and caches the results
- FakeUserService – a services that fakes retrieving data from an IUserRepository (again, ideal for unit testing)
- UserService – same as the caching service (just without caching)
These services all implement the IUserService contract/interface that our presentation layer (UI) depends on.
Now, on to creating an application architecture and validating these stated dependencies.
From the Architecture menu in Visual Studio, you select New Diagram.
In the dialog box that opens, select Layer Diagram and give it an appropriate name.
You should end up with a blank architecture diagram that looks like this:
Now, using either the Toolbox or by right-clicking, we can begin adding layers to your diagram. After adding our application layers, our diagram should look like the following:
Now, to validate our architecture (and dependencies), we first need to tell Visual Studio, what code/projects are in what layers. We start by dragging our projects (or solution folders) into the associated application layer. For example, in my sample solution, I would drag the entire DataAccessLayer solution folder into the Data Access layer on the diagram:
Here’s what we should end up with when we’re done:
It looks very similar to when we started, but now we have a small indicator in the upper-right-hand corner which tells us how many projects are associated with each layer.
Now for the magic!
Simply, right-click anywhere in the white space on the application layer diagram and click Generate Dependencies.
If what I told you above about how my application is architected is true, then you should get an updated diagram that looks like the following:
Ah, now isn’t that diagram a breath of fresh air? In this diagram, Visual Studio is telling us there there are absolutely NO dependencies between the layers of our application! Rather, all application layers depend only on the Contracts project which is simply a collection of interfaces. This is the epitome of encapsulation and tells us that our application layers are decoupled from one another and can be swapped out for other implementations without risk to the rest of our application.
This is ideal for TDD scenarios and allows for simultaneous development on different application layers if we have already ironed out our contracts/interfaces. This means more parallel development can occur which can potentially reduce project timelines. And of course, with TDD on our side, we can reliably test individual layers and sign-off on them knowing that they are not dependent or affected by other layers/components whatsoever. End-result: higher-quality software developed in a shorter amount of time.
Now, if your application doesn’t look like this and looks more like the second picture with dependencies between every layer, don’t worry! Visual Studio can also help you find those dependencies so that you can factor out the concrete references into interfaces/contracts.
First, start by removing the dependencies from your diagram that you don’t want to have in your app – do this by rick-clicking on the dependency arrow and selecting Delete. Next, after you have removed all the unwanted dependencies, simply right-click anywhere in the whitespace of the diagram and select Validate Architecture. Visual Studio will proceed to build your projects and determine if your application actually validates against your stated (desired) architecture. If it does not, the violations will show up in the Error list window and you can start going through these dependencies and replacing the concrete implementations with contracts/interfaces. Additionally, application architects can use this functionality in conjunction with TFS to prevent code check-ins that violate an application architecture diagram.
With Visual Studio 2010, ASP.NET MVC 2 & 3 and the rich support for Dependency Injection, you can begin extracting interfaces from your concrete classes to remove the hard-dependencies in your apps, increase the maintainability of your apps. These features aren’t limited to MVC either. Many DI/IoC frameworks also work with ASP.NET WebForms as well as Windows Forms, WPF, and Silverlight. With these tools in your toolbox you too can begin enjoying the bliss that is a truly decoupled application that is easy to maintain, easy to test, easy to change and easy to replace when the next technology comes along!
Download the sample code: MvcDI.zip
For more reading on ASP.NET MVC and Dependency Injection I suggest you check out the following blogs:
http://weblogs.asp.net/scottgu/
http://hanselman.com
http://haacked.com
http://bradwilson.typepad.com/
Happy Injecting!