Imagine a blacksmith. They build the sword on fire, shape it with the hammer, and then finish it with the water.

Programming is a craft as much as blacksmithing.

However, instead of using the forge to build a sword through the power of heat, in programming you use your mind to craft the code through the power of failure. Instead of waiting to see the result after you bring the iron back from the cold, you see the result after the failure becomes a success and the test passes.

Last time I wrote the Missing Practical Step-By-Step Test-Driven Development. Since then, I've written how to create a Money model and how nobody crafts the perfect code in the first time.

The first post introduced the story of Jack, a moneylender searching for better ways to calculate the interest of his loans.

It goes like this:

Hi, I'm Jack. My business is to give loans. I can make a small loan to you, but if you do, then I will charge interest for each dollar above a certain threshold. Can you build something that can do that calculation for me? $0 to $2000 = No Interest $2001 to $5000 = 9 cents per dollar $5001 to $10000 = 14 cents per dollar $10001+ = 21 cents per dollar

After the first post, Jack ended up with a product that can calculate $0.09 of interest for each dollar above $2000 up to infinity. That was the first boundary of the problem. Now it's time to develop the code for the next boundary. This time, the code needs to calculate $0.14 of interest for each dollar above $5000.

Like before, there’s a repository where you can see one commit per test run. That repository shows the Red/Green/Refactoring steps in each commit.

The commit has a 🔴 when it represents the red step.

step. The commit has a green ✅ when it represents the green step.

step. The commit has a 🔨 when it represents the refactoring step.

Let’s begin.

Jack is happy with $0.09 for each dollar above $2000, but he'll be happier if the code can calculate $0.14 for each dollar above $5000.

Let's start with a test for $5000, which is one dollar less than $5001. You should expect this test to pass and the next one to fail.

As expected, the test passes. $5000 loan amount should still use the old rule. According to Jack's specification, the new rule of $0.14 should only apply for loan amounts of $5001 or higher.

Now the test for $5001 loan amount fails because it calculates $0.09 instead of $0.14. That is intentional. You haven't implemented the rule for the next range. Therefore, you can see the old algorithm still in effect. That test failure drives you to implement the code for the next range.

The screenshot for the test failure of $5001 loan amount. It expects $270.14. Instead, it gets $270.09.

At this point, there are many paths to take to make this test pass. I can think of two:

Evolve the old conditional and find ways to write the minimum amount of code that can make this test go green as soon as possible. Isolate the old conditional and create a new one to account only for the new rule. The test only passes once the algorithm is complete.

You can argue the first alternative respect the laws of TDD more than the second one. The first alternative doesn’t require you to build the whole algorithm for the test to pass, the second one probably does. Therefore, the first alternative seems more likely to assist you in achieving a good outcome. However, for the sake of experiment, let's try the second approach.

For the second approach, you can isolate the old conditional to only run for loan amounts that are greater than $2000 and less than $5001. This way you can focus solely on the code for loan amounts of $5001 or more.

The test failure changes from calculating $0.09 for each dollar to ignoring all calculations. Therefore, it returns $0.00. That is because you've isolated the previous logic.

The screenshot for the test failure once you isolate the algorithm for the range between $2000 and $5000. It expects $270.14. Instead, it gets $0.00.

Now how would you develop the first condition for loan amounts greater than or equal to $5001? You can probably write something like "if the loan amount is greater than $5001, then start to build the algorithm for the next range."

Don't do that. You're jumping the gun!

Remember we're doing TDD. Therefore, according to the law number 3, "You are not allowed to write any more production code than is sufficient to pass the one failing unit test." The minimum condition you can write is "if the loan amount is exactly $5001, then start to build the algorithm for the next range." Anything more than that is an unnecessary level of transformation to the code that hurts the purpose of what you're trying to achieve.

"Minimum" is subjective. You can argue that returning a static amount of $270.14 is the minimum you can write to make the test pass.

However, if you change the code like that, it won't assist you to discover the patterns that matter. You know you need an algorithm that is similar to the one for the $0.09. Therefore, you can try to build the new requirement using the code of the previous algorithm as a template, only now you don't need to rediscover the calculation again from scratch.

If you start from the return value, the compilation errors may drive you to rebuild the old algorithm in the context of the new requirement.

Let's try.

If you already know the solution for some parts of the problem, you can use the tests to drive you to figure out the remaining parts you don't.

The first thing is to start with the conditional for loan amounts of $5001. Create an undeclared "interest amount" variable and return that.

The test is still red because the code didn't declare the variable “interest amount.” However, now it fails with a different error message. The message tells you that something is missing.