When sitting with a blank Visual Studio project in front of you, ready to start up that new killer application of yours, where do you actually start?
Almost every programmer has heard about and used the highly acclaimed 3-layered architecture:
My guess is that most developers have a tendency to start developing either from the top with the presentation layer or from the bottom with the data layer. However, even if it is understandable to have some initial thoughts about the presentation layer and the data layer, the recommended starting point is the business layer – or the domain layer as some would call it.
The business layer is the natural starting point, because the business layer should have no dependencies to either the presentation layer or the data layer – or any 3rd party libraries for that matter. It should be possible to build and test the business layer in total isolation from the two other layers.
This might sound a bit awkward to some, because most developers probably have made tons of projects where the business layer is depending on the data layer. I know for sure that I have… But this is not the right way to do it. The business layer should consist of nothing else than POCO’s (Plain Old CLR Objects) – or POJO’s (Plain Old Java Objects) if you are in the Java world – and abstractions. This means that the business layer should not reference anything else than the basic .NET framework libraries (i.e. System, System.Core etc. – those files that are automatically added to your project file references when you create a new project in Visual Studio). No other dependencies whatsoever. Period!
Why is this so important? Because, besides simplifying establishing unit tests, it dramatically increases the maintainability and reusability of the whole code base.
Doing it wrong…
Let’s say you have a classical application with some sort of product service in the business layer that can perform CRUD operations on products in a repository in the data layer. This very often leads to a dependency graph like the one shown below:
This is because somewhere in the product service you will “new” up a dependency to the product repository:
this.repository = new Data.ProductRepository();
So, you have a situation where the higher level component (the business layer) depends directly on a lower level component (the data layer). This has at least the following disadvantages:
- The product service cannot be reused in isolation in another context
- The product service cannot be unit tested in isolation
- One product repository implementation (using for example a RDBMS for persistence) cannot easily be replaced by another implementation (using for example an XML file for persistence)
Doing it Right…
Let’s say that instead of “newing” up an instance of the product repository in the product service, then you inject the repository into the service through a constructor argument:
private readonly IProductRepository repository;
public ProductService(IProductRepository repository)
if (repository == null)
throw new ArgumentNullException("repository");
this.repository = repository;
Now the dependency graph looks like this:
An abstraction of the product repository in form of an interface is introduced. It is the high level component (the business layer) that owns this abstraction. The product repository is an implementation of this interface.
But now the data layer is depending on the business layer? Yes, indeed. Everything is turned upside-down, because now this object graph adheres to the Dependency Inversion Principle (DIP):
High-level modules should not depend on low-level modules. Both should depend on abstractions.
Abstractions should not depend upon details. Details should depend upon abstractions.
DIP was first introduced by Robert C. Martin (Uncle Bob) back in the mid 90’s and is one of the main principles of object-oriented design.
Instead of directly creating an instance of the repository using the new keyword, the product service has relinquished control of the repository dependency and delegated that responsibility to a third party control. This technique is called Constructor Injection – a sub-pattern of Dependency Injection. How this instance of the repository is created and by whom is of no concern to the product service. You can push this burden all the way to the top of the application into a single component – what is referred to by Mark Seemann in his book Dependency Injection in .NET as the Composition Root of the application. Depending on the type of application, the actual composition root can vary, but more about this in the last post in this series.
Anyway, now the product service can be easily reused in another context and unit tested in isolation, because it is no longer depending on any particular implementation of the product repository. In the unit test, the fixture of the test class itself can act at the composition root creating an instance of some mock repository that can be injected into the product service. Furthermore, an alternative implementation of the repository can be easily created and used in the application.
So, it all begins with the business layer. During the lifetime of the project, make it a habit to regularly check those project references in the business layer project file to make sure no reference to some obscure 3rd party library – or even worse, the presentation layer or the data layer – has accidently sneaked in. You should consider using some tool, or even making automatic tests, to check that the POCO’s-policy for the business layer is enforced.