Sunday 14 December 2008

Using TDD and Resharper to Learn Something New

This week, I have been working on building RSS feeds from objects in our domain model. I am using System.ServiceModel.Syndication to do the RSS/Atom formatting, so all I needed to worry about is the mapping between domain and the SyndicationItem.

Until recently I would have used XML (along with all its angle bracket evilness) to achieve this. However, I am becoming increasingly disillusioned with using XML for configuration because of the difficulty in testing and reading it. So, having been inspired by Fluent NHibernate and the fluent configuration of Unity, I decided that I would do the mapping using a fluent style. I was aiming for an API that would let me do something like:

var doc = Repository.FetchDocument(someDocId);

var map = new SyndicationItemMapping
{
Title = doc => doc.Filename,
Summary = doc => doc.Body.Substring(0,100),
Content = doc => doc.Body,
Copyright = doc => "(c) 2008. All rights reserved"
};

var syndicationItem = map.From(doc);

I haven't done enough functional programming yet for all the concepts to have fully gelled in my head. I'm quite happy writing lamba expressions but I still struggle with the syntax for the Action<T> and Func<T> delegates that consume them. I knew (or thought I knew) that I was in for a tough couple of hours.

TDD teaches us that when we get stuck like this we should write a test. I knew the kind of API I wanted, so it took me just a few moments to compose a test:

[Test]
public void MapsTitleFromAnEntity()
{
var entity = new MockEntity { Name = "entity name"};
var mapper = new SyndicationItemMapper<MockEntity>
{
Title = entity => entity.Name
};
var syndicationItem = mapper.From<MockEntity>(entity);
Assert.That(syndicationItem.Title, Is.EqualTo(entity.Name));
}
This is where the magic of ReSharper kicked in. A couple of [Alt]+[Enter]'s in the right places generated the code for my SyndicationItemMapper class in a matter of seconds:

public class SyndicationItemMapper<T>
{
public Func<T> string Title { get; set;}

public SyndicationItem From(T entity)
{
throw new NotImplementedException();
}
}
So within a matter of about ten minutes, I had the outline of my implementation and know immediately how I was going to progress. I then completed the implementation for that test and added a few more tests with their implementations. In just over an hour I had built the entire mapping.

Now the point of this post, is not to show how easy it was to build fluent interfaces (although when I compare the time this took compared to all the time it would have take me to build all the XML wotsits I'd have needed, its really quite impressive). No, the point is how TDD helped me to quickly learn some syntax I was unfamiliar with.

Before TDD I would probably have written a [button 1] test harness and then spent hours floundering around trying to find the correct solution (and may well not of). But with the test case I had some solid syntax to aim for and could get the implementation within a couple of hours. Add in the power of Resharper and I was able to get the basic implementation done in a matter of minutes.

No comments: