DIP: Dependency Inversion Principle

August 27th, 2006 Comments

The Dependency Inversion Principle deals with how to correctly design classes such that their dependency on one another causes the least amount of work in case of a change. Uncle Bob’s definition of DIP states:

  • High-level modules should not depend on low-level modules. Both should depend on abstractions.
  • Abstractions should not depend on details. Details should depend on abstractions.

Essentially what this principle means is that in a tiered design, higher level modules and lower level modules should not directly depend on each other; instead they should only depend on abstractions. Moreover, abstractions should not have any knowledge of details (other classes in the system).

This principle closely relates to some of the other design principles I discussed previously in that it yields a design that is highly decoupled ensuring that minor changes in one part of the application do not cause a domino effect in other parts of the application. Moreover such a design is extensible — as new business entities are added, usually such as design scales well by requiring only new code to be added rather than existing code to be modified. ASP.NET 2.0′s Provider Model is a great example of such a design that provides a default implementation for various sub-systems such as Membership, Personalization, Navigation, etc. but also allows developers to modify the default behavior by extending certain classes.

LSP: Liskov Substitution Principle

August 23rd, 2006 Comments

The Liskov Substitution Principle dictates when and where it is correct to derive a subtype from an existing supertype. As defined by Barbara Liskov and Jeannette Wing, it essentially states that:

Let q(x) be a property provable about objects x of type T. Then q(y) should be true for objects y of type S where S is a subtype of T.

What it means is that if S is a subtype of T, then a function q(x) must behave in the same manner irrespective of the type of x whether it be S or T. In other words, if a piece of code behaves differently for a subtype than a supertype, then that code violates the LSP (and consequently the OCP).

Let’s say that we work for a bank and that we have a simple teller application. Currently the teller application works with checking and savings account types.

public abstract class Account
{
    public abstract double CurrentBalance { get; }
    public abstract void Deposit(double amount);
}

public class CheckingAccount : Account
{
    private double _currentBalance;

    public override double CurrentBalance
    {
        get { return _currentBalance; }
    }

    public override void Deposit(double amount)
    {
        _currentBalance += amount;
    }
}

public class SavingsAccount : Account
{
    /* Savings account implementation */
}

Our bank just entered the mortgage business so we need to modify our teller application to support this new account type. During the short analysis phase we decide that since mortgage account is type of an account (IS-A relationship), we can simply create a new mortgage class deriving from the Account abstract class, override a method and a property, and we should be in business. We add a new class as follows:

public class MortgageAccount : Account
{
    private double _currentBalance;

    public override double CurrentBalance
    {
        get { return _currentBalance; }
    }

    public override void Deposit(double amount)
    {
        _currentBalance -= amount;
    }
}

Everything sounds logical, that is until we come across this code in the teller application:

public class Bank
{
    public void ReceiveMoney(Account account, double amount)
    {
        double oldBalance = account.CurrentBalance;
        account.Deposit(amount);
        Debug.Assert(account.CurrentBalance = oldBalance + amount);
    }
}

Based on our pre-existing code, the ReceiveMoney() method is making a reasonable assumption that the new balance should be equal to the old balance plus the newly deposited amount. This assumption is, however, violated if we pass an instance of the Mortgage class to this method. This is a clear violation of the LSP.

Inherit With Care

July 18th, 2006 Comments

I was asked to look at an ASP.NET 1.1 application that was designed with a distributed architecture using .NET Remoting. Over a period of a few hours of heavy usage, this production application would intermittently bring the Windows 2003 Server that it was being hosted on to a screeching halt. Cause unknown. No event log entries, nothing suspicious in IIS logs, nothing too special about the application that would indicate this behavior. Performance monitoring, however, indicated that the handles on the OS would gradually increase to dangerous levels of 50,000+ before the application would crash. Hmmm, what could be using so many handles and not releasing them? My first instinct was to make sure that all the remoting objects were disposed properly after use. Upon closer investigation, however, I found out that all ASP.NET pages in the application were inheriting from a custom base class. The base class was overriding the page’s Init method, and guess what I found in that method? A call to RemotingConfiguration.Configure() method. At first I was surprised why would someone configure remoting every single time a page is instantiated? Soon it hit me why system handles were astronomically increasing. Once that line of code was moved to Application_Start event, the application hasn’t crashed in weeks. Moral of the story? Inheritance is a good OO concept, but only we as developers can decide how badly we want to abuse it!