Test Driven Development — the Good, the Bad, and the Reasonably Beautiful

All that glitters is not gold, yet its value is still up to you.

Nadhif A. Prayoga
7 min readMar 20, 2021

Test Driven Development (TDD) is an approach to software development, “rediscovered” by Kent Beck in 2003, that encourage developers to write tests prior to writing the code. This approach had a purpose: To make sure that every scenario is tested and proved before being shipped.

But how does it do that? Is it really a necessity or is it simply another fancy approach that just leads to overengineering? Why do we, as developers, need to adhere to an almost 20 years old standard?

In this article, I would like to tell what I know and what I experienced.

An Overview

Automated testing has become a norm in the software development world, especially in tech giants where a single mistake may be costly. Nowadays many companies have their own testing team, where all they would do is write tests separate from the development team. Testing is the best way to make sure a program works as intended before being delivered.

The cycle of TDD — Image from marsner.com

TDD consists of three primary steps: Red, Green, and Refactor.

Red: Make a test for the function you’re going to create. For many, this is the most challenging part, as it forces you to think about the entire function before you even write it. This is the crux of TDD. You then would run the test and it would fail.

Simple availability tests

Green: Write a “minimal implementation” of the function that would pass the tests. Many seems to think that they have to write functions as minimally as they could, I disagree. You should treat green as how you would write a normal code without TDD. Botching your own code for the sake of fulfilling an approach is, quite frankly, a waste of time. You then would run the test and it would succeed.

Simple fulfillment of the test

Refactor: This is where you would improve the code from the previous green implementation. Sometimes, this step is unnecessary and you may skip it altogether. Refactoring is when you try to think how you can make what you have written more efficient, faster, or just tidier without changing the bigger picture.

The Good

So, knowing how it helps, what benefit do we gain from implementing it? Well, there a couple that I experienced, such as:

Eliminating bugs before they are born
TDD eliminates any potential for some bugs to arise, such as regression bugs. With TDD you’re confident that, as long as your function pass the tests, your program will work as intended. Or at least as the tests intended it to.

In our case, we created a test for a form even though we don’t plan on making the form until later, making sure that it works even later down the line.

A future proof test in case something changed

More robust and well-thought-out functions
TDD forces you to write self-sustaining and better functions. It forces you to think about the entirety first as opposed to figuring it out on the go. It helps you write codes that are loosely coupled with one another and focus more on what you’re currently working on.

In our case, since we are still early in development, we wrote a view that offers a dummy list instead of having a hard-coded dummy list on the html itself. This not only finishes the HTML first, but also serves as a reminder that we have to add the proper function later.

Dummy list, serves as a reminder and finishes the html without a need to change

No Stone Left Unturned
This is arguably the benefit everyone wants the most. TDD checks for every situation that the tests calls for. When something does fail the test, you would know exactly what fails and where. It also serves as a list of potential scenarios that may happen on a program, very useful for a project with multiple members.

In our case, we make sure to not only check if a page exist, we also check if it has a specific object. This is to make sure that the page is both accessible, goes to the right place, and has the right object.

Making sure everything is fulfilled

The Bad

For even Superman has his kryptonite, there is always a catch to every methodology. Below are a couple:

Slower development
Yes, as expected, TDD reduces the overall speed of development. Because you’re forced to think about everything at the start, you start taking more time thinking than doing. This leads to momentum loss for many developers who are used to do their programming parallel with their thinking.

What our team experience is that we also have to do both together, because pushing a RED without an implementation will mean that no further RED may be pushed, as it would make further pipelines fail the test.

Two Reds in a row

Double the effort, quadruple the code
TDD introduce at the very least one test per function. This means that the amount of code you have to write at least doubled. But a lot of programs have more than one flow to them, thus creating more and more tests down the line. This means a lot of efforts are spent writing the tests, sometimes even more than the efforts needed to write the code.

The test (left) vs the code to be tested (right)

Over-testing and overengineering
TDD forces you to think of every situations. Sometimes, even situations that are not relevant to your business context. Useless tests may arise that are not relevant at all to any use-case just to cover a line that isn’t all that important. The drive to refactor may also lead to early optimization, which can lead to more time loss and a code that does way more than it needed to.

In our case, since we have a motivation to get 100% coverage, we have to make dummy functions for the urls, this means to make a dummy test as well that needs to be changed later on.

Dummy test, the views still uses the same templates

The Reasonably Beautiful

Crude yet so great

Here’s what some people, especially younger developers like me, are missing. TDD does not solve anything. TDD does not make your code great, TDD does not make you great. TDD is not some magical instructions you can follow and expect great results from it.

However, TDD helps you reach those goals. TDD is a proved concept, a tool. It works, but it has to be wielded by someone who can use it properly. Emphasis on properly. TDD gives your code the push it needs to achieve greatness, to be clean and ready for every situation, to be well-thought-out and capable, to be the best version of itself. TDD is but a make-up that makes even the freakiest Frankenstein’s code reasonably beautiful.

You see, TDD only works if the mind behind it believes in it. If you believe in its benefits, you would reap the rewards. There is no reason to use TDD if you do not believe in it. So then ask yourself, do you really believe in TDD? Does your code need TDD? Are you capable of achieving what you set out to achieve without it?

In short, our current project benefits greatly from TDD. Despite our original doubt, it serves as a great tool to achieve our goal of satisfying our client. Not only does it help us not have bugs and deliver our code with confidence to our client, it also strengthen our skills for the future. And I think that’s enough for us to justify having TDD in our project.

Conclusion — The Right Tool For The Right Job

Sometimes, it just does not work

So, when and where should you use TDD?

  • TDD helps with cleanliness and error-free implementation, meaning the more people on a project, the better it is.
  • TDD is particularly useful on bigger projects that cannot afford to fail.
  • TDD shines the most on a well-thought-out projects. Projects that already have a good amount of resources poured into it. Projects that have all of their requirements ready.

Picking whether to use TDD or not is a skill in and of itself. A wrong pick may result in an overengineered code. But more importantly, you have to believe that TDD brings benefit to your project.

TDD is a tool which needed to be handled by a skillful person to unlock its full potential. But a skillful person does not arise in a single day. There is nothing wrong with using TDD for practice. Like it or not, TDD is an important methodology that is useful to have in every arsenal. And it’s here to stay.

Wake up, developer. We got a code to test.

--

--

Nadhif A. Prayoga

I am a computer science student at University of Indonesia. Writing certain stuff only