NIF
Start with the sad paths and postpone the solutions
This kata consists, originally, in creating a Value Object to represent the NIF, or Spanish Tax Identification Number. Its usual form is a string of eight numeric characters and a control letter, which helps us ensure its validity.
As it’s a Value Object, we want to be able to instantiate it from a string and guarantee that it’s valid in order to use it without problems anywhere else in the code of an application.
One of the difficulties of developing these kinds of objects in TDD is that sometimes they don’t need to implement significant behaviors, and it’s more important to make sure that they are created consistent.
The algorithm to validate them is relatively simple, as we’ll see, but we’re mostly interested in how to rid ourselves of all of the strings of characters that can’t form a valid NIF.
History
This kata is original, and it came about by chance while I was preparing a small introduction to TDD and live coding workshop about the benefits of using the methodology in day-to-day work.
While I was delving into this example, two very interesting questions made themselves apparent:
- Starting with tests that discard the invalid cases allows to avoid having to deal with the development of the algorithm as soon as we start, getting them out of the way and reducing the problem space. The consequence is that we end up designing more resilient objects, with cleaner algorithms, contributing to preventing the apparition of bugs in the production code.
- The mechanism of postponing the solution of each problem until the next text becomes apparent. That is: to make each new test pass, we introduce an inflexible implementation that allows us to pass that test, but in order for the previous ones to keep passing, we are forced to refactor the code that we already had.
Problem statement
Create a Nif class, which will be a Value Object, to represent the Spanish Tax Identification Number. This number is a string of eight numeric characters and a final letter that acts as a control character.
This control letter is obtained by calculating the remainder of diving the numeric part of the NIF by 23 (mod 23). The result indicates us in which row of the following table to look up the control letter.
| Remainder | Letter |
|---|---|
| 0 | T |
| 1 | R |
| 2 | W |
| 3 | A |
| 4 | G |
| 5 | M |
| 6 | Y |
| 7 | F |
| 8 | P |
| 9 | D |
| 10 | X |
| 11 | B |
| 12 | N |
| 13 | J |
| 14 | Z |
| 15 | S |
| 16 | Q |
| 17 | V |
| 18 | H |
| 19 | L |
| 20 | C |
| 21 | K |
| 22 | E |
There’s a special case of NIF, which is the NIE, or Foreigners’ Identification Number. In this case, the first character will be one of the letters X, Y and Z. For the calculation of mod 23, they are replaced by the values 0, 1 and 2, respectively.
Hints to solve it
This kata can help us learn several things, both about TDD and about data types and validation.
In kata, it’s common to ignore issues such as data validation in order to simplify the exercise and focus in the development of the algorithm. In a real development we cannot do this: we should actually put a lot of emphasis on validating the data at different levels, both for security reasons and to avoid errors in the calculations.
So we’ve included this kata precisely to practice how to use TDD to develop algorithms that first handle all of the values that they cannot manage, both from the structural point of view as well as from the domain one.
Specifically, this example is based on the fact that the effective behavior of the constructor that we’re going to create is assigning the value that we pass to it. All else it does is check that the value is suitable for that, so it acts as a barrier for unwanted values.
Being a Value Object, we’ll try to create a class to which we pass the candidate string in the constructor. If the string turns out to be invalid for a NIF, the constructor will throw an exception, preventing the instantiation of objects with inadequate values. Fundamentally, our first tests will expect exceptions or errors.
From the infinite amount of strings that this constructor could receive, only a few of them will be valid NIF, so our first goal could be to delete the most obvious ones: those that could never fit because they have the wrong number of characters.
In a second stage, we’ll try to control those that could never be NIF due to their structure, basically due to them not following the “eight numeric character plus one final letter” pattern (taking into account the exception of the NIE, which could indeed have a letter at the beginning).
With this, we’d have everything we need to implement the validation algorithm, as we’d only have to handle strings that could be NIF from a structural point of view.
One thing that the previous steps guarantees us is that the tests won’t start failing when we introduce the algorithm, as its examples could never be valid. If we started using strings that had that valid NIF structure, even if we’d written them randomly, we could run out into one string that was valid by chance, and when implementing the corresponding part of the algorithm that test would fail for the wrong reason.