DCSIMG
February 2009 - Posts - Offir Shvartz

Offir Shvartz

We code with love or we code not...

February 2009 - Posts

Layered Application wannabe

Hi it's been a while since my last post (just had nothing interesting to write about). In this post I wanted to share an issue I encountered recently while reviewing a medium scale web application.

Layered Application

This is a common architecture of an enterprise application that has a large number of components (read about it here).

The Problem

I was told that the web application I was reviewing conformed with the Three-Layered Services Application pattern. I started taking a closer look at the code and found that the web app had one solution that contains a web site and three class library projects: BL (Business Logic), DAL (Data access Layer) and Common.  It seemed like the layers of the app were really independent and separated, until I encountered something like:

public void DoSomeLogic() //Some Input
{
    DataSet entitiesDs = DAL.ReadEntities();
    foreach(DataRow dr im entitiesDs.Tables[0].Rows) 
    {
        runSomeAction(dr["entityId"])
 
    }
    //More code
}

The above is  a simplified example of code in the BL assembly (Business Logic layer) - It uses the DAL in order to read the entities from data base.

So what's wrong with this code ?

  • The BL is using the first table from the data set assuming it exists and contains the right data - can cause runtime error.
  • In the Data Row object we read column name "entityId" (even if it is const string) - causing two problems:
    • can cause runtime error if the column doesn't exists.
    • dr["columnName"] returns an object we need to cast or parse - this can cause invalid cast exception and performance issues in case we Parse the object result.
  • The use of DataSet - first I must confess that I HATE DataSets because:
    • it uses a large amount of memory that in most cases contains more then we need (especially when we build a layered application) like relations.
    • it is weak type (the opposite of strong type) you just don't know what you have - you just can't understand from your code what the data set contains causing maintenance to be very hard, essentially requiring you to debug to understand the code.

The main issue: We don't really have layer separation --> changes in the Data Base schema may cause changes both the Business Layer (BL) and in the data access layer (DAL).

Layered Application Benefits

When I think back to the years I develop without Layer separation, I just can't understand how I could do it. Layer separation seems so natural and so required now. There are a lot of benefits (I'll try to give most of them)

  • Maintenance - in case of schema change we need to modify only the Data Layer.
  • Reusable - Blocks of functionality are modular and can be used in other applications due to good separation and abstraction.
  • Readable - good separation cause clear code. The objects that pass between the layers are simple (containing no logic) making the function flow clear and understandable.
  • Testable - if you use TDD you have to keep this separation because you want to test only a specific unit (in the BL for example) - no separation makes this task impossible.
  • Flexibility - replacing Layers while using the same interface is a simple task when the separation is complete.
  • Scalability - when the data objects are simple and small size we can easily deal with them in chunks, clear code allows developing scalable application.

Solution

The solution is to use simple data container objects to pass between layers ("object model"). In most cases I think they shouldn't hold any logic - leave the logic to the BL layer.

You already know what I think of DataSets, but still there are some cases (not many...) we need to use them. For example - a loose coupled functionality (when we don't know and care what is returned and just want to bind it to a data grid in our UI). but if out BL needs to implement some functionality using the DataSet (like in the example above) - we must make only the data we use strong typed and init the objects strong type properties in the Data layer. Inherit from DataSet and add the needed properties for your logic.

For example the solution for the code above:

public class EntityDataSet: DataSet
{
 
 public int EntityTableIndex {get; set;}
 
 public DataTable EntityDataTable 
    {
        get 
        { 
            return this.Tables[EntityTableIndex];
        }
    }
 public string EntityIdColumnName {get; set;}
 
 
}

and the function looks like this:

public void DoSomeLogic() //some input
{
    EntityDataSet entityDs = DAL.ReadEntities();
    foreach(DataRow dr in entityDs.EntityDataTable.Rows) 
    {
        doSomeLogic(dr[entityDs.EntityIdColumnName]);
    }
    //more code
}

Summery

To conclude using layered application pattern can be very profitable. Ask yourself is you application architecture is really layered application, or just layered application wannabe. Using three separate projects is just not enough, make sure that changing the data base schema will cause only a change in the Data access layer and changing the business logic will need only modification in your business logic layer.

Cheers Offir :-)