Focus and test-driven development
The benefits of test-driven development are numerous. However, this time, I want to focus on some specifics related to software design.
When we write software, we solve many problems simultaneously. Some of these problems are:
- Decomposing the problem into smaller sub-problems
- Designing how the new behavior will be invoked
- Figuring out how to make the system exhibit the desired behavior
- Doing all of the above in a clean and maintainable way
Surely there are other things to consider, but for me, these are the most important regardless of what I’m developing.
How does test-driven development help here? By forcing me to focus on one of these problems at a time.
Test-driven development starts with the test list. (By the way, 99.9% of all the TDD material out there completely forgets about this part.) By creating a test list, I am practicing behavioral composition.
Each test on the list is an example of a new, small behavior I want to introduce to the system. The final solution is a composition of many small behaviors.
Once I have a list of small behaviors I want to implement, I can focus on which of these behaviors would make the most sense to implement next. I’ve written a bit more about this part in the test lists article, so I won’t go too deep into it right here. It’s enough said that this is a problem on its own and test-driven development makes that problem explicit.
After I’ve picked a test to write, I’m faced with many decisions. I have to decide how my new behavior will be invoked. Should I create a new class or add a method to an existing class? What kind of arguments should it take? What should the types look like? These are all important questions I need to answer. Again, test-driven development forces me to address this problem right then and there. If I can’t answer these questions, then what am I even doing?
The test serves as an example of a behavior. It tells me how the behavior will be invoked, what kind of data I need to invoke it, and what should happen as a result.
After the test has been written and I’ve seen it fail, it’s time to implement the desired behavior. Here, test-driven development helps keep me focused on a single problem: making the test pass.
So, let’s implement the simplest, quickest possible solution to do exactly that. It doesn’t matter if it’s the ugliest piece of code I’ve ever written. I just want the test to be green.
Finally, I have a working solution. The test is passing. The solution is the ugliest thing in the world. But it works.
This is where I can think about how to refine it. Let’s apply all the years of software engineering knowledge and experience to make the solution simple and maintainable.
Each step in this process is one little step. For simple-minded people like me, this makes software development manageable. It lets me focus on implementing one little behavior at a time, and doing so in tiny little steps. That is, in my opinion, the real benefit of test-driven development.