Friday, November 27, 2009

What's the Problem with List<T> Properties in BLL?

Today I'll speak about a practice for business logic layers (BLL).

The .NET List<T> is a nice and really handy class for in many destinations. However, this class is not the best solution for libraries like business logic layers (BLL) to provide related domain objects.

Above a very simple part of a fictive business logic layer (BLL).
class Order {
   public int Id { get; set; }
   // ...
}

class Customer {
   public int Id { get; set; }
   public List<Order> Orders { get; private set; }
   // ...
   internal void SetOrders(List<Order> orders) {
      this.Orders = orders;
   }
   // ...
}
Using the List<Order> in this solution can cause some problems.

Lacy Loading

You should always try to load all information needed for a specific business case. Though, there are reasons why this makes no sense. For instance if the don't know which related data are needed when you start your business transaction. Another reason might be a too huge count of related objects. Here is lazy loading a nice pattern.

In our fictive layer, there are cases when we need the orders of our customer, but there might be several other cases when we don't need the related orders. You can use a Builder to compose different customers for different business cases. However, sometimes the required relations to handle a business case are not clear when the business transaction starts.

Always to load too much information might become a performance problem. Lazy loading is a nice practice (when it is used correct) to ensure related information if they are needed. One way to handle lazy loading is AOP but sometimes you can end up in a ripple loading. For instance, if you have to handle thousand customers and their orders it makes more sense to load all (or a page of 100) orders in one database query. In this case you might prefer a special implementation which handles this loading.

Validation

You can derive from List<T> but it does not provide any way to validate the Order which become accessed/removed/added. Probably you want to validate newly added orders to ensure they are valid and/or not yet attached to any customer. What about deletion? It should not be possible to delete an order which is already billed. For these business cases, you need an observable list or a read-only list.

Presentation

This very depends on how flexible your BLL wants to be but think about your presentation layer. If you want to be able to bind your orders list to a data bindable control like the .NET DataGridView. The List<T> does not provide all required methods to enable add/remove handling for the grid.

Notice, I do not speak about any coupling between business and presentation layer but it might be neat if your BLL provides some binable objects which can be reused in win-, wpf- and/or web-applications.

Custom Behavior

As a last reason for now (there might be more) why List<T> should not be used here is customization of behavior. Probably your list needs to be sorted by any order information. Maybe you need an observer list which organizes this sorting, even if you change one or more of the contained orders.

Better Solution

A better approach to provide related 0...* objects is usually the IList<T> interface. This interface provides (almost) all methods which are available by using List<T> but it provides a very low coupled representation of the Order property. Feel free to use List<T> for common initialization within your BLL. If you ever need a special handling you are able to provide another list though.
class Customer {
   public int Id { get; set; }
   public IList<Order> Orders { get; private set; }
   // ...
   internal void SetOrders(IList<Order> orders) {
      this.Orders = orders;
   }
}
Another solution is to provide a completely custom list interface or base class (I always prefer interfaces). This also works fine and keeps you able to provide different lists with different behavior. Though, this has a larger startup cost for your project. IMO IList<T> fits fine for most consumers of a BLL.

No comments:

Post a Comment