Coding Dojo

The first Leeds Coding Dojo on 09 July 2014 was an almost packed affair. The problem to tackle, in a language of our choice, was price calculation for books with different discounts given for buying different books – out of a choice of 5 different books. No discount is given for the same book being bought more than once. And before I forget – TDD and pair programming to be followed throughout the exercise. More details in the slides here.
It was refreshing doing proper TDD as per the three cardinal rules while focusing on the technique and proper pair programming. Some of the first set of work done is posted at github if anyone’s interested.

Programming just to pass the next test is not as easy as it sounds. In daily work the mind is already racing ahead trying to work out how to cater for possible future situations, which is not recommended as per TDD. So for the first part of the dojo, the book price was set same for all books and thus a constant. The changes needed when different prices were introduced did not cause any sweat since we had a set of tests by then to guide the change.The dojo was useful in giving guided practise, the guidance given ably by Grant Crofton, the organiser and a good friend. An experienced hand at such events, his tips and encouragement were well utilised by pretty much all the attendees.

The tests in this case led me to the following implementation of the price calculator, catering for maximum possible discount for the end users buying multiple sets of different books.
public double Scan(params Book[] books)
{
    var distinctBooks = new List<List>();
    var booksList = new List(books);

    while (booksList.Any())
    {
        var distinct = booksList.Distinct().ToList();

        distinct.ForEach(x => booksList.Remove(x));

        distinctBooks.Add(new List(distinct));
    }

    var price = 0.0;
    distinctBooks.ForEach(set =>
    {
        price += set.Sum(y => y.Price) *
                         (1 - DiscountDictionary[set.Count]);
    });

    return Math.Round(price, 2);
}
Now this made the tests pass, but is not very maintainable code. The one class doing everything in one method is a precursor to a lot of huge methods in a few classes, each trying to do a whole lot, with the big ball of mud just around the corner.

Which is where the refactor bit in the Red-Green-Refactor cycle of TDD comes in. The tests allow worry free refactoring – working code is just a few undos away, so long as the tests are run after every refactoring. To speed up the cycle, the tests are recommended to be unit tests – more than a few seconds running time is too much for some practitioners.

With that in mind, I’ve ended up with the classes shown below. For this exercise I did not write individual unit tests for these classes, but with responsibilities split, it should not need too much effort.

public class Books : List
{
    public Books(IEnumerable distinct) : base(distinct) { }

    public double FinalPrice(IDictionary discountDictionary)
    {
        return this.Sum(y => y.Price) *
                      (1 - discountDictionary[this.Count()]);
    }
}

public class DistinctBooks
{
    private readonly List _distinctBooks;

    public DistinctBooks(IEnumerable books)
    {
        var booksList = new List(books);
        _distinctBooks = new List();

        while (booksList.Any())
        {
            var distinct = booksList.Distinct().ToList();

            distinct.ForEach(x => booksList.Remove(x));

            _distinctBooks.Add(new Books(distinct));
        }
    }

    public double FinalPrice(IDictionary discountDictionary)
    {
        return _distinctBooks.Sum(x => x.FinalPrice(discountDictionary));
    }
}
With these classes taking over their responsibilities the call in the price calculator is reduced to:
public double Scan(params Book[] books)
{
    var finalPrice = new DistinctBooks(books)
                          .FinalPrice(DiscountDictionary);

    return Math.Round(finalPrice, 2);
}
This set of changes are uploaded to this github location.

All in all, a very satisfying experience, looking forward to the next one, with an entirely different challenge.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s