Published: 16 Oct 2009
By: Andrew Siemer

In this article we will take the next step in improving this code by further elevating our logical tiers to physical tiers. This simply means that we will create separate assemblies for each of the separate tiers. By the end of this article we will have our web project, a business layer project, domain project, and a data access project.

Contents [hide]

The Stack Overflow Inspired Knowledge Exchange Series

  • TOC Checkout the project homepage of this series to follow our journey from the creation of the famous StackOverFlow website.
  • Introduction

    In the last article we got some things ready for the article series. Part of this was to create a Posts table to hold our questions and answers down the road. We then added a Posts create script to our build process. Next we looked at how we could use a spreadsheet to generate some test data which we also added to our build process. Once all of the database tasks were complete we were then able to configure a LINQ to SQL datacontext in our Knowledge Exchange project. It was downhill from there. We were able to quickly add a query into our home page controller and force feed our view with a list of Post objects. With the home page displaying data we then took a look at the pros and cons of this approach. The majority of popular concepts were of course not met with this design approach!

    In this article we will start to address some of the flaws in our original design. The first step will be to refactor towards logical separation of our code. Then we can analyze the code to see what the remaining issues are. Then we will analyze the pros and cons of this design.

    Logical separation of the code

    In our current code base the only separation that we have is the data context which is in the Model folder that comes with the ASP.NET MVC framework. This isn't really a matter of separation though - it is more of a convenience factor! Also, our UI calls directly to the data context which is essentially our entire data access layer. To correct this we will start to create more of a layered approach with our app by placing code into more appropriate locations. We will also start to separate our code a little bit - specifically we will no longer allow the UI to talk with the database.

    Data Access

    Given that this is a fairly simple application for the purposes of demonstrating not so simple concepts we understand that our data access currently consists of one LINQ to SQL query in a controller. Lets create a better home for our data access by creating a folder off of the root called DataAccess. Then we will need to create two class files in there. One will abstract the creation of a DataContext and how it connects to the database. Our application currently knows too much about that process. The other class will be a PostRepository that will house our query logic. This is another area that we are exposing to much information. Once we are done moving this code around our UI should be able to make a direct call to a repository object and get its list of posts back.

    Let's start by building out our connection class. This class will create a new instance of our data context for us and return it to use when we need it. This means that it also needs to know how to get our connection string out of the configuration file. Imagine if we didn't have this connection class and instead created a whole bunch of connections when ever and where ever we needed to in the web project (like it is currently configured). What a mess! At the very least it doesn't follow the "don't repeat yourself" approach!

    Normally I wouldn't paste the entire class code in the article but there is something very important to see here that will need to be addressed down the road. It screams that we have a problem!

    Listing 1: DataAccess/Connection.cs

    Did you see the problem? There are actually a few problems here. First of all in the second using statement you can see that we are including a reference to our domain in the models folder which is under the "Web" namespace. We can't fix that issue till we move to a physical separation of our code (the next article). Then as you read the namespace for this class you will notice that our DataAccess is also in the Web namespace. UGLY! Now you might be asking "why don't use just change the namespace?" That is not really the proper way to address the issue. We can't really address this particular issue until the next article.

    The next thing we will create is a PostRepository which will handle all of our queries for Posts. If you have spent any time following the Domain Driven Design concepts you should immediately recognize the repository pattern. This class also has all the same problems that the Connection class has so I am not going to list the namespace and other surrounding code here.

    Listing 2: DataAccess/PostRepository.cs

    As you can see this PostRepository has one method for getting all posts. With this working we can now update our UI by removing all of the code that it had previously. We can then make call to our repository class and feed the results straight into the view model.

    Listing 3: Controllers/HomeController.cs

    While this code makes a lot more sense and is way easier for the front end user to use I have to wonder if it is totally complete at this point? Granted we don't really need anything more for this to work. But to me the fact that the UI still goes direct to the database just doesn't seem right. There must be something else we can do to correct this slight issue.

    Business Layer

    Again, I will admit that we don't NEED any other layers for this to be complete and functional. It is clean as it is. But let me suggest some issues with this current implementation.

    In the given scenario where do we insert new rules as they come from the business entities in the company? Granted we could just put them in the view as needed. But this means that we would need to repeat our code across many views. That wouldn't be very DRY. Ok...then put it in the data access layer? Yes, this would be better as it would at least be centralized but that wouldn't follow the single responsibility principle very well.

    Ok. So we will create a business layer. But why do I need to create it now? Why can't I create it later when I need to add some rules or insert some new application wide functionality? If we don't do it now then you will slowly build up more and more code that will directly attach itself to the repository that we created. By the time we actually need a business layer we will have many lines of code to update in order to insert it.

    Our business layer will also need to go into its own folder. I generally call this the "core" directory as in core functionality. This is where all of our applications service implementations will live. We will create a PostService class in a new Core directory. The PostService will have a method called GetAllPosts. This method will then connect to the PostRepository and return the data from the GetAllPosts on that class.

    Listing 4: Core/PostService.cs

    Now we can update our UI to speak with the service layer.

    Presentation

    Updating the UI is quite simple. All you need to do is swap the Repository keyword with Service.

    Listing 5: Controllers/HomeController.cs

    Analysis

    Since all we did was re-arrange our code into a more logical manner that is easier to manage our dependency graph hasn't actually changed all that much. We still have a web site that is dependent upon our data access layer.

    Figure 1: LogicalTiersDependencyGraph.jpg

    LogicalTiersDependencyGraph.jpg

    Pros

    This design is still very fast to develop once you begin to think in terms of buckets. My mom always had a saying that you have probably heard before. "A place for everything and everything in its place." Once you start to live this way even your quick and dirty projects will follow this form as it is significantly more flexible and less prone to abusing the DRY principle. Also, this design tends to be well abstracted and encapsulated. Also, maintaining a separation of concerns can be achieved with this approach.

    Separation of Concerns

    The concept of Separation of Concerns is a hard one to nail down if you don't stay on top of it. You will often see people follow the Domain Driven Design approach where they put all their business functionality in some form of a service class and all the data access code into a repository. This isn't bad but it also doesn't follow SoC very well either. When a repository class has 15 methods in it with the only thing in common being the type of object that it is performing various work on then the class has more than one reason to change.

    Take an OrderService for example. You might have SubmitOrder, PrintOrder, and CreateOrder. SubmitOrder pulls an Order out of the local database and pushes is via web service into SAP for processing. PrintOrder gets an order and feeds it to a print queue. And CreateOrder takes a submission from a client and saves it to the database. It is a fair guess with very little detail that there is more than one reason for this class to change!

    To clean this up a bit you might instead have an SapOrderService, a PrintOrderService, and an OrderService. Often times when following this pattern you will end up with lots of very little classes with very few methods in them. This will ultimately make your code more flexible, more readable, easier to refactor, easier to work with, etc. The only down side is the physical number of files created...which really isn't that big of a deal is it?

    Cons

    The cons of this approach are not small. We still have topical concerns such as the fact that our business and data access layers live under the web namespace. This doesn't make our code very intuitive. Also, there are still a load of dependencies in our code that shouldn't be there. Our code is considerably more flexible but is still not testable. It is not pluggable (meaning that I couldn't swap data source A for data source B without a lot of work. And most importantly, in its current form the code is not that scalable and certainly is not distributable.

    Table 1: Comparison Chart

    Coding Concepts

    Yes

    Sorta

    No

    Fast/Easy to develop: Can we generate the end product quickly?

    X

    Testable: Can we write tests around the majority of the projects code?

    X

    Flexible for refactoring: Can we easily refactor the code base to add new concepts?

    X

    Well abstracted: Do the users of your code only know what they need too?

    X

    Well encapsulated: Can you change the internals of code without impacting the users of that code?

    X

    Separation of concerns? Is your code well compartmentalized and only doing what it needs to?

    X

    DRY? Does your code follow the "Don't repeat yourself motto?"

    X

    SOLID? Does this code comply with the SOLID principles?

    X

    S: Single Responsibility Principle - there should never be more than one reason for a class to change

    X

    O: Open Closed Principle - should be open for extension but closed for modification

    X

    L: Liskov Substitution Principle - functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it

    X

    I: Interface Segregation Principle - clients should not be forced to depend upon interfaces that they do not use

    X

    D: Dependency Inversion Principle - high level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions.

    X

    Swappable? Can you swap out an entire layer down the road?

    X

    Distributable? Can you push complex processing of logical areas to a separate server easily to offload computing cycles and scale?

    X

    Summary

    In this article we refactored our current code from a UI direct to data access style web site into a logical tiered application. This took form by creating a separate data access layer area in our code as well as a separate business layer area in our code. We then moved our connection logic into its own class for reuse across the site. Next we created a repository to take care of all the querying for a given type of object. Once the data access was isolated we then created a fairly straight through business layer which can be easily modified in the future. This gives us a point to insert various new functionality if the need were to arise. With the reworking of our plumbing code we then cleaned up our front end by plugging into our new business layer. We ended the article with a look at the pros and cons of this approach and found that there were significant improvements gained with just this one refactoring. We acknowledge though that there was still plenty of room for improvement in this code.

    In the next article we will refactor this code further into what most people would call physical tiers. This will consist of breaking out our data access and business layer into their own physical assemblies. Once that is complete we will once again take a look at how this improved our code and what remains to be done to achieve the ultimate flexibility.

    <<  Previous Article Continue reading and see our next or previous articles Next Article >>

    About Andrew Siemer

    I am a 33 year old, ex-Army Ranger, father of 6, geeky software engineer that loves to code, teach, and write. In my spare time (ha!) I like playing with my 6 kids, horses, and various other animals.

    This author has published 29 articles on DotNetSlackers. View other articles or the complete profile here.

    Other articles in this category


    Code First Approach using Entity Framework 4.1, Inversion of Control, Unity Framework, Repository and Unit of Work Patterns, and MVC3 Razor View
    A detailed introduction about the code first approach using Entity Framework 4.1, Inversion of Contr...
    Exception Handling and .Net (A practical approach)
    Error Handling has always been crucial for an application in a number of ways. It may affect the exe...
    jQuery Mobile ListView
    In this article, we're going to look at what JQuery Mobile uses to represent lists, and how capable ...
    Book Review: SignalR: Real-time Application Development
    A book review of SignalR by Simone.
    JQuery Mobile Widgets Overview
    An overview of widgets in jQuery Mobile.
    Top
     
     
     

    Discussion


    Subject Author Date
    placeholder Did I miss an article? Robert Williams 10/16/2009 8:40 AM
    RE: Did I miss an article? Andrew Siemer 10/16/2009 9:51 AM
    placeholder RE: Did I miss an article? Andrew Siemer 10/16/2009 10:43 AM
    RE: RE: Did I miss an article? Robert Williams 10/16/2009 1:48 PM
    placeholder RE: RE: RE: Did I miss an article? Andrew Siemer 10/16/2009 2:01 PM
    RE: RE: RE: Did I miss an article? Sonu Kapoor 10/16/2009 2:03 PM
    placeholder RE: Did I miss an article? Sonu Kapoor 10/16/2009 8:42 AM
    RE: RE: Did I miss an article? Robert Williams 10/16/2009 8:56 AM
    placeholder RE: RE: RE: Did I miss an article? Sonu Kapoor 10/16/2009 8:58 AM
    RE: RE: RE: Did I miss an article? Sonu Kapoor 10/16/2009 10:03 AM
    placeholder RE: RE: RE: Did I miss an article? Sonu Kapoor 10/16/2009 9:53 AM

    Please login to rate or to leave a comment.