3 Is Many

This is an installment in my Zero-Friction TDD series.

When I was a kid, my parents taught me that many is any number above three two*; they used the simple counting sequence one, two, many. This little story may make me seem like I was an incredibly dim-witted kid, but the point was obviously not that I couldn't count to more than three, but rather that, in many cases, unary and binary systems may be special, but as soon as you cross the threshold to three, you are dealing with a number that doesn't exhibit any particular characteristics.

Note: I'm not talking about number theory here. I'm sure someone will be able to tell me about all sorts of special characteristics of the number 3. Incidentally, three also seems to be a magic number in many cults and religions. That's not what I'm talking about either.

If you will allow me to further digress, studies have shown that some animals can count to both three and also higher numbers. This goes for humans as well: If I place a number of marbles/dice/glass beads/whatever in front of you, and you have to give me the number as fast as possible, you can probably do that without counting up to perhaps five or six. For higher numbers, you will have to count the items. Three is an instantly recognizable number by the human mind, but I'm not talking about cognition either.

As a colleague once told me: The hardest scale-out you can perform is going from one to two. Nonetheless, if you look at concepts such as active/passive failover clustering, it would seem as though going from two to three is also non-trivial.

However, once you have managed to deal with three of whatever it is you deal with, you are probably ready to deal with four, five, or even twenty-seven. To bring the topic back to code, at that point you are probably working with a list of some sort.

When testing against lists, 3 is a good Equivalence Class for many. If you have a list of three elements, you have distinct elements for the head, interior and tail of the list. You can perform meaningful sorts and filtering on such a list.

In fact, I usually find that I can reproduce most scenarios (as well as most bugs) with lists of three elements.

When writing unit tests, for maintainability the number 3 shouldn't just appear as a magic number in the test, so it makes more sense to define it as a constant somewhere, as in this, otherwise inane, example:

 private const int Many = 3;
 public void SumOfManyNumbersWillBeCorrect()
     // Fixture setup
     IEnumerable<int> anonymousNumbers = 
         Enumerable.Range(0, MyClassTest.Many);
     int expectedSum = anonymousNumbers.Sum();
     MyClass sut = new MyClass();
     // Exercise system
     int result = sut.Sum(anonymousNumbers);
     // Verify outcome
     Assert.AreEqual<int>(expectedSum, result, "Sum");
     // Teardown

The only noticeable part of this piece of code is the Many constant, which is used in the test code itself. This is a good hint to the Test Reader that this test deals with many integers, without particularly caring about how many there are.

* Edit 2009.01.20