Everything is Red, Green, Refactor

Work Less with TDD!

Why Anything Else is not Enough

Zakiy Saputra


Source: https://marsner.com/blog/why-test-driven-development-tdd/

This article was written for the purpose of individual assignment for PPL CSUI 2021 and to educate readers on TDD and their alternatives


Before we move on, let’s preface this article with an opinion that in a perfect world, TDD is flawless, is the best software development process to be practiced in developing software, and should be implemented by every developer, their children, and also their neighbors, who might not be a programmer. Let’s continue with a fact, shall we?

TDD is (subjectively), quite annoying. For TDD to works, a developer needs to understand their software first, such as the environment, programming language, and extension devices to create a test (take selenium, as an example). The surge of popularity and proven effectiveness of TDD pushes institutions and learning programs to teach their students how to use and incorporate TDD. Sadly, most of the time, these students don’t have the full grasp of their program environment, which makes them think (and supports the notion), that TDD is useless. You, reading my article right now, is probably thinking “See, he agrees with me! TDD is useless!” but sadly, that’s not the case.

My reaction when I just tricked you | credit: Catbug

Because TDD is indeed useful in the long run!

Quick Report: What’s a TDD Again?

A TDD is a development cycle that is started by creating automated test cases that aren’t completed which results in a red pipeline. A TDD is defined as a cycle of:

  1. [Red] In this commit, you create a series of tests of a function that you would like to make. Since you haven’t actually code the functions yet, this will result in a failing pipeline that is colored in red, hence why named Red. When pushing this commit, programmers usually marked the commit with Red at the start for easier documentation.
  2. [Green] After writing tests on the previous commit, you can write the functions you intended to write to finish your task and also to pass your test. Since the tests you previously made would pass in this commit, the pipeline on your commit will be marked green, hence Green. Just like Red, programmers usually marked the commit with Green at the start.
  3. [Refactor] After passing the tests, in this commit you can add additional adjustments to improve your program while keeping the pipeline green. There are many reasons for a programmer to do refactor such as improving the function’s UI/UX, cleaning code smells or unintended bugs, and others.
An example of a full TDD cycle in development

By implementing TDD, developers would achieve many benefits in their program such as better design process, eliminates possible bugs and defects, and promotes the implementation of clean code. These benefits are what make most programmers and developers use and advocate TDD (guess not so overrated anymore, huh?).

Without TDD, chances are you’re going to commit your code under one of the following scenarios: Making tests after you’re done coding, or not writing tests and depends on manual testing. In this article, I’m going to explain why TDD is usually preferable (and also needed instead of only using) to both of these alternatives.

A Life Without Automated Test: Manual Testing

Manual testing is defined as the testing of the software where tests are executed manually by a QA Analyst or a Programmer (if there’s no QA Analyst). It is performed to discover bugs in software under development.

In manual testing, a tester checks all features of a given application or software. The testers execute the test cases and generate the test reports without the help of any automation software testing tools. Test cases tested by testers in manual testing are usually made to tailor the criteria/fulfillment of the functions themselves. Below is an example of a User Acceptance Test (UAT), which is one of the manual testings we can do and I did on my RPL class:

The first column marks the numbering of task(PBI) of the application or software, the second column marks the task name, the third column marks the developer of the task, the fourth marks the scenario that needs to be done by the tester, and the last column marks the expected results that came out of the testing that needs to be given as the result for the test to be passed as true.

Sometimes, manual testing alone can be better than TDD for few reasons. As an example, a small and simple project would most likely fare better using manual testing than TDD due to the initial costs TDD needs over manual testing. This would overturn if your small project would scale later on and became big though, since, under that case, TDD would fare better on Return of Investment(ROI) than manual testing. Not only that, automated testing on TDD usually doesn’t cover some aspects that are only capable to be evaluated by humans, such as visual aspects of your application. This doesn’t justify you not use TDD though, since manual tests are prone to human mistakes, can’t be recorded, and can’t cover all kinds of tests. Imagine manually testing a scenario where you need to do an extreme case test where 100 people are using your software backend, daunting isn’t it?

The Rebellious Sibling of TDD: TAD

For everyone who’s still learning how to program and isn’t decent at implementing TDD yet (including me!), Test After Development (TAD) is most likely your current go-to method in developing your program. Test after development can be defined as a development cycle that goes along like this:

  1. Write your function
  2. Write tests that would pass the function

This looks easier (well, it is, honestly), faster, and works as good as TDD at a glance, or is it? Unsurprisingly, TAD has worse code coverage and results than TDD for a few reasons, here’s why:

  1. A TAD cycle doesn’t drive your design process as opposed to TDD. Since TAD doesn’t drive your design process, a TAD isn’t guaranteed to remove possible defects of your tasks that can be eliminated at the start by using TDD and realizing what to do in implementing your feature.
  2. A TAD cycle yields lower coverage as opposed to TDD. Even though automated tests are objective, they are made by humans at the end of the day. You’re more prone to skip out few lines in testing your functions by using TAD compared to TDD.
  3. A TAD cycle reduces fewer defects than TDD. Elaborating from point number 1, a TAD cycle is usually done under the mentality of “Let’s write as many easy lines as possible that would cover most coverage of the feature”; Since the tests are made after the functions have been made, developers tend to write tests for the sake of passing the coverage, not passing the actual functions itself, leading to lower coverage and higher defects compared to TDD (because who wants to bother changing their code for the test in TAD?).

Since TAD gives fewer benefits than TDD with similar costs given (setting up the infrastructure for automated testing, maintenance, etc), it is better for you to pick up on TDD development than TAD when you can.


TDD gives a lot of benefits in developing your programs. Without doing TDD, you can do alternatives such as Manual Testing and TAD. Manual Testing is faster than TDD and can check some information that can’t be tested by TDD, but are worse in general, so Manual Testing should be used as a complement of TDD instead of replacing TDD. TAD yields worse results than TDD in almost every aspect and shouldn’t be used over TDD when you could. Always use TDD when you can!

After reading this article, I hope you learned about the importance of TDD and the trade-off between alternatives of TDD! See you in my next article!

Adprog Course, University of Indonesia
RPL Course, University of Indonesia
PPL Course, University of Indonesia