Deadly Poison of Lazy Loading and not following Design Guidelines

Sometimes I perform a code review and at first glance everything looks fine, but - while I’m digging my way in - I slowly start to encounter some ‘hidden features’. This post is all about the dangers of lazy loading and not following some of the design guidelines.

The case

In this specific case I have been asked to review a library because it’s not performing very well. They have this data intensive application library and some single requests can take up to 22 seconds to return a result. So I started to look at some of those requests and at first all looks pretty well. It’s just that some actions take a long time while they don’t seem to perform any real work at all.

For example:

public Tree<Product> LoadProductsTree(CustomerId customerId){
    Tree<Product> produktTree = new Tree<Product>();
    foreach(Product product in GetProducts(customerId)){
       TreeNode productNode = CreateTreeNode(product);
       productTree.Add(productNode);
    }
    return productTree;
}
 
public static TreeNode CreateTreeNode(Product item) {
    TreeNode node = new TreeNode();
    node.Title = item.Title;
    node.Description = item.Description;
 
    return node;
}

Lazy loading

The underlying problem turns out to be a combination of two very common design mistakes. The first one is lazy loading of properties which are almost always needed when someone uses the object. The second one is using properties instead of methods.

In the above code, both Title and Description properties are language specific and require a join in the underlying database between two tables. The designer of the code thought it might be expensive to retrieve this data and so decided to use lazy loading for these properties. But he forgot one very important rule to know about lazy loading: Lazy loading of properties, is only of use if – most of the time – you don’t use these properties. Since Title is such a prominent part of a product, it simply does not apply for lazy loading.

Design Guidelines conventions

The reason it took me some time to find out what the problem was with this library, is due to the fact there is no way for me to know that accessing the Title property results in a database call. The biggest problem is, that most of their developers don’t know either which properties in this library result in database calls. That’s all because they’ve used properties where they should have used methods.
A method indicates work to be done, and a property should not perform a lot more work than retrieving a field value. If they wanted the Title and Description values to be lazy loaded, these ‘properties’ should have been methods named GetTitle() and GetDescription().

Deadly Poison

If they followed the design guidelines on properties and methods, they would have known what the problem is with this library. They probable would have noticed all the Get methods being called a lot. If they would have loaded these properties eagerly they wouldn’t have this problem either. It’s just a combination of the two that was poison to the performance. While profiling I discovered that one simple WCF request could result in no less than 23.000 connections and queries to their database and knowing that, it’s no wonder that this does take some time…

Conclusion

1. Do get as much of the data you need, but no more, in as few as possible requests to the database.
2. As soon as you have to retrieve a value from the database it's not a property no more.
3. Be aware that LinqToSql also uses a lazy loading pattern for joins by default and there's also no hint at all that we are going back to the database with those lazy properties either!
4. Entity Framework 4.0 allows for lazy loading but it's not the default.

5 Comments

  • Lazy loading is not bad thing if it is clear how it works. In your case I think the problem is messing up the properties and causing the situation where nobody is able to understand when database queries are run.

    Lazy loading is like electricity - it helps smart ones and kills fool ones. :)

  • @DigiMortal: Fully agree...

  • Nice Write up !!! Needed a Reminder now and then !!!

  • "Do get as much of the data you need, but no more, in as few as possible requests to the database." I totally understand this bit, however, how would you design your business layer when you architecture your application? For example, Order -> Lineitem -> product ->category.If I need to return an order list and all its fields, should I get data using sql joins? If so, I believe it would kill business layer. Otherwise, we have to consider lazy loading if we want to return List.

  • @jessmmy: I don't fully understand your question. But it all comes down to this. It depends on your demands when you decide to use lazy loading or not. If you need the data for reporting, you ARE going to need ALL data. So be smart en load all data in one query. If you use it to built a user interface and you start by selecting an order number and than a line item, and from that line item a product. Get every object one by one.

    Problems arise when you take very very common properties, like "ProductTitle", and make those lazy properties. Because that will make SURE that almost everytime you create a product object it needs to perform at least 2 queries.

    It all comes down THINK about why you are doing what you are doing. Lazy loading is nice for properties you almost never use. Lazy loading is horrible for properties you almost always use.

    Lazy loading is nice for user interfaces, but terrible for reporting.

    Cheers,
    Wes

Comments have been disabled for this content.