Wednesday, March 24, 2010

Too-Busy Constructors

In dealing with a more complicated OO design, it can be a mistake to put too much initialization logic into constructors. This is especially important for an OO design that uses inheritance significantly. In this post I offer three reasons against doing too much in a constructor. lazy loading, exception handling, and control over execution order.


First, lets look at control over execution order. It can become complex to reason about the order in which code gets executed. It is necessary to distinguish between the execution of data field initializers and the code in the constructor. I blog here about the exact sequences that occur in VB.NET and C#. The languages have a significantly different ordering! Moving initialization logic into a separate initialization routine can allow you to control this order more precisely, without having to fit logic into object initialization as implemented by your .NET language.


Second, the lazy loading pattern is an extremely useful technique to be aware of. Martin Fowler articulates the lazy load pattern well within his Patterns of Enterprise Application architecture. The basic idea behind lazy loading is that it can be significantly more efficient to delay gathering data until it is actually needed. It is possible that the data may never actually be needed. At the same time, a calling class need never know about the lazy implementation. It can call the object that employs lazy loading and simply assume that the data will be available when it is needed. For some things that are naively done in the constructor, using the lazy load technique is the best way to go.


Third, handling exceptions generated from within a constructor can prove difficult. If the exception should prove critical and can’t be easily handled then the code execution flow can be messy. You have to allow for disposal of all relevant objects and resources obtained so far. You also need to consider what the results of the exception unwinding the call stack will be.


In my own experiences with profiling .NET applications, object creational concerns have proven to a significant cause of inefficiency. In one case, I found that there were an excessive number of Oracle connection objects being created. These connections weren’t actually being opened (thankfully!) but they were instantiated nonetheless. Having constructors do less and instantiating fewer aggregated objects can result in code that is more manageable and more efficient.

4 comments: