TDD by Example: Chapter 12 Addition, Finally

Summary

Beck starts the chapter by clearing his todo list and starting over. He adds a todo for addition between dollars and Francs but finds that it's too tough a test so he adds a todo to implement addition between two dollars. This test proves trivial to get to pass so he does it in one big(relative to the small steps he has been taking so far) step. He comments on how TDD gives you control over the size of the steps.

Stops to consider how to even write the test for multi-currency arithmetic.

Decides on the kind of solution he wants

Creates what I think is the same things as a fake. It's an object that does the thing you want but has the same API as the one you are using.

Mentions that there is no trick to coming up with the idea of creating a fake.

Comes up with "Expression" metaphor. Arithmetic operations between involving "Expression"s result in other Expressions, "Sum" is a subtype of "Expression". Another subtype of "Expression" is "Money"

Having solved the addition of two Moneys with the same currency he stops to consider how he can even write the test for multi-currency addition. He decides he wants a solution that looks as close to basic arithmetic as possible. He doesn't want to have to consistently have to deal with different currencies and their exchange rates when doing the arithmetic operation. This leads to the "trick" of creating an object that behaves that he wants.

The object has to be able to do everything Money does without worrying about exchange rates. He comes up with the idea of the Expression. An Expression is something that add two instances ofMoney together. An Expression can do arithmetic operations with other Expressions and return a new Expression. This means that:

A Money is the atomic form of an expression

This leads to the idea that the test should be assert:

assertEquals(Money.dollar(10), reduced)

Where reduced is what you get when the result of an operation on two Expressions is given to the Bank to reduce the value to a certain currency. The Bank is responsible for dealing with exchange rates.

He gives two reasons that the Bank should be the one dealing with exchange rates:

Beck ends up with this test:

public void testSimpleAddition() {
	Money five= Money.dollar(5);
	Expression sum= five.plus(five);
	Bank bank= new Bank();
	Money reduced= bank.reduce(sum, "USD");
	assertEquals(Money.dollar(10), reduced);
}

He gets it to pass by adding the Expression interface and moving the definition of plus to it, having Money implement Expression, and creating a Bank class that implements reduce with a hardcoded return value.

interface Expression {
	Expression plus(Money addend) {
		return new Money(amount + addend.amount, currency);
	}
}

class Money implements Expression {}

class Bank {
	Money reduce(Expression source, String to) {
   		return Money.dollar(10);
	}
}

This paves the way to refactor to a real implementation.

Commentary

I think this quote captures the essence of this chapter:

TDD can't guarantee that we will have flashes of insight at the right moment. However, confidence-giving tests and carefully factored code give us preparation for insight, and preparation for applying that insight when it comes.

Beck has a flash of insight in this chapter that he says is at "the heart of what we are doing". Using Expression as the basis for all the arithmetic between various kinds of Money with each individual instance of Money also being an Expression seems elegant. It's like he found the base case from which unfolds everything else within this domain.

The other side of the quote above is that TDD cannot guarantee insight. I would take it even further that TDD can't even guarantee what Beck might call a good design because the person practicing TDD has to know what good design is and has to be aiming to go there. Several times in the this chapter and in previous chapters Beck assumes his shares his design sense.

For example when he writes:

Instead we would like a solution that lets us conveniently represent multiple exchange rates, and still allows most arithmetic-like expressions to look like, well, arithmetic.

He say "we would like", but do we? I don't know what I would like here. What does "conveniently represent multiple exchange rates" mean? How will I know if the design is "convenient"? What makes a design "convenient"? Why do want it to look like arithmetic? Why is that better than not looking like arithmetic? What's the other option?

I'm not trying to be difficult and nitpick. I think Beck assumes a certain "taste" among his readers. I think this book was written for someone with at several years of professional experience, who heard that TDD might be helpful. It assumes that the person is familiar with what Beck would consider good design and wants to know how to consistently produce good design. It's not for someone trying to figure out what good design is.

I'm starting to think that TDD by itself won't produce well designed, maintainable code. I think the person using TDD has to know where they want to go and TDD can help get them there. TDD is the driver but the programmer is the navigator.