Tag Archive for 'c'

Liskov Substitution Principle

Last night I was reading Agile Software Development, Principles, Patterns, and Practices (freaking amazing book) and came across the Liskov Substitution Principle. I had never heard of this principle, so it got me intrigued.

What it is…

The idea is very simple. For any client using a base class, any child class should be able to be substituted in that client. It seems very straightforward, but the example Martin gives blew my mind.

Is a Square subclass of a Rectangle a valid model? Maybe. It depends on how clients use it. If a client expects to be able to change the height and width independently, then this model actually breaks down. Martin sums it up better than I,

This leads us to a very important conclusion. A model, viewed in isolation, can not be
meaningfully validated. The validity of a model can only be expressed in terms of its clients.

He follows this up by saying that the Is-A relationship actually applies to the behavior of an object and not how we may envision an object relationship. A square Is-A rectangle because it has 4 sides and each side has a 90 degree angle between them. A square Is-Not-A rectangle because its height and width can change independently.

How many times have I created an object hierarchy based on how I perceive the objects vs how the behave? Too many. This principle is really easy to violate, and causes an application to become fragile when violated.

How to prevent it…

The book goes on to talk about Design by Contract, which can help prevent this behavior by specifying pre-conditions and post-conditions on any given method. These conditions are published with the base class. The oddity of Spec# makes a lot more sense when thought of in regards to the previous example.

Another way to accomplish this without built-in language support is to create a test fixture hierarchy similarly to the object hierarchy. That way, any expectations on the base class can be verified on all sub classes.

[TestFixture]
public abstract void RectangleBaseTests
{
    protected abstract Rectangle { get; }
 
    [Test]
    public void ChangeWidth()
    {
        int oldHeight = Rectangle.GetHeight();
 
        Rectangle.SetWidth(5);
 
        Assert.That(Rectangle.GetHeight() == oldHeight);
        Assert.That(Rectangle.GetWidth() == 5);
    }
 
    /* More Rectangle tests .... */
}
 
[TestFixture]
public void SquareTestFixture : RectangleBaseTests
{
    private Square _square;
 
    protected override Rectangle
    {
        get { return _square; }
    }
 
    [SetUp]
    public void Setup()
    {
        _square = new Square(5,5);
    }
 
    /* more Square only tests... */
}

This still isn’t optimal because it requires developers to actually create the tests that verify functionality, but it is better than nothing.

In the end, the solution doesn’t matter as much as understand the problem. I highly recommend any developer read up on the Liskov Substitution Principle.

How you should start your next project…

public interface IRepository<T>
{
    T Get(object id);
    void Update(T entity);
    void Add(T entity);
}
 
public interface IEntity
{
    object Id { get; }
}
 
public abstract class EphemeralRepository<T> : IRepository<T>
    where T : IEntity
{
    private IDictionary<object, T> storage;
 
    public EphemeralRepository()
    {
        this.storage = new Dictionary<object, T>();
    }
 
    public T Get(object id)
    {
        return (this.storage.Keys.Contains(id) ? this.storage[id] : default(T));
    }
 
    public void Update(T entity)
    {
        this.storage[entity.Id] = entity;
    }
 
    public void Add(T entity)
    {
        this.storage.Add(entity.Id, entity);
    }
}

The data layer can quickly become a time sink, especially since the amount of change in a new project is so high. There isn’t much value to spending time coding it initially. It is going to change, and you will have to update your repository, schemas, mapping files, etc.

I know I am not the first to offer this advice, but I think reinforcing it is important.

LINQ bites back

Today I found some odd behavior when working with LINQ. It is hard to describe, so here is the code.

public void Foo(IEnumerable<string> strings)
{
	IEnumberable<string> stringsInDb = strings.Where(s => this.QueryTheDbAndTakeALongTime(s));
 
	foreach(string str in stringsInDb)
	{
		//Where clause in LINQ is actually executed 
	}
 
	foreach(string str in stringsInDb)
	{
		//Where clause in LINQ is actually executed  AGAIN
	}
}

Luckily, some unit tests detected this behavior. It actually isn’t surprising when you think about it though. The proper thing to do for this case is actually call ToList() after the Where().

IEnumberable<string> stringsInDb = strings.Where(s => this.QueryTheDbAndTakeALongTime(s)).ToList();

Don’t let this behavior bite you.

C# Destructors and IDisposable

This week I found myself somewhat confused on when to use destructor. Originally I assumed that anytime you implement IDisposable you should have a destructor that calls Dispose().

This is not the case though. The only time you really need a destructor is when a class directly contains unmanaged resources, like file handles.

A good example of when not to use a destructor is a wrapper class. For instance, if you have a database connection class wrapped with some sort of adapter class, the adapter class doesn’t need a destructor. It still needs to implement IDisposable to enable early disposal of resources, but the destructor of the underlying database connection class will handle any potential leak cases if Dispose() isn’t called.

Here is a quote from a very good article on C# traps:

The destructor should only release unmanaged resources that your object holds on to, and it should not reference other objects. If you have only managed references you do not need to (and should not) implement a destructor. You want this only for handling unmanaged resources. Because there is some cost to having a destructor, you ought to implement this only on methods that consume valuable, unmanaged resources.

The really powerful statement is “it should not reference other objects” which basically backs up my previous statement on wrapper classes.

Here is another good article on destructors and IDisposable.