Test-Driven Development (TDD) in practice

Manabie Tech-Product Blog
Manabie
Published in
4 min readFeb 4, 2020
Photo credit: Lee Campbell

In the past, usually when a company decided to start a project, they would go by waterfall approach: define the specifications first, then implement features later, then test and maintain. This methodology has many strong points such as tight control, extensive written documents, and approval between each phase, etc.; and is still used at some companies nowadays. Despite those strong points; however, the major disadvantage is that the methodology is highly resistant to changes. Once a software piece moves to the testing phase, it is very difficult to go back.

In an ever-changing world today, this particular drawback may result in great loss of money and trust. We want some methodologies that can allow us to develop software in a timely manner, yet assure its quality. One such methodology is Test-Driven Development (TDD).

TDD is a process that relies on a very short development cycle: first, the developer writes an automation test case for a particular requirement, then writes the minimum amount of code to pass that test (DO NOT do any optimization at this stage). After the code passes that test, the developer will refactor the code to acceptable standards, then start working on the next requirement.

There are many guides and examples on the internet to demonstrate how to implement TDD in projects, so you can search them easily.

Opposite to the simple definition and how-to, practicing TDD in reality could be quite intimidating. Among different issues, the most frequent complaint is that TDD slowed down the project. For newcomers, it may look like so. At the first look, your pacing is slowed down, you implement less features than before in the same time period. But do not be scared, in the long run, you actually save time for the project. By writing the test and implementing the code in small chunks, it is very easy to spot the uncertainty in the requirements early, then make changes on the spot.

At Manabie, we implement TDD by following these activities:

- Review features

- Break down features into requirements as small as possible

(Quick note: A requirement is a work order for an engineer who constructs some parts of the system).

- Get a requirement

- Write a test case

- Write minimum code to pass the test case

- Write another test case

- Write more codes to pass test case

- Repeat writing test cases and codes until the requirement is fulfilled

- Continue to implement other requirements until every requirement is fulfilled

- Refactor the whole feature

We want to promote communication between members, that’s why we prioritize working code before refactoring. We do not want to spend time on refactoring while requirements are still unstable. We want to know if the implementation is feasible and make changes as soon as possible if necessary. The refactoring will then occur when everything is stable at an acceptable level. This way, we lower the risk of misunderstanding.

When we break down the feature into requirements, ideally, a requirement should contain only 1 test case and a very small chunk of code just to pass that test case. For example, we have a simple feature:

- If A then C, if B then D

We will break this feature into smaller requirements:

- Requirement 1: If A, then C

- Requirement 2: If B, then D

When implementing requirement 1, we do not implement requirement 2 ahead, or doing any other logic, just follow KISS and YAGNI principles, write test and code to meet the exact requirement 1.

If mistakes are found, like no other case handling on the example above, our developers will ask the Product Manager to fix the feature and add more requirements for it later. Of course, in real projects, we often need more than 1 test case to cover a requirement. In this case, developers will write just a minimum amount of code to pass the tests one by one and do not skip any step.

At first, TDD can be irritating. However, when we look back, more than just code, we deliver a set of test cases, which are basically requirements in the form of test codes. Those test cases are way more detailed than any design document, since they tell exactly how software responds in every specific case. If we reread everything, we can write a whole detailed document about a specific feature we implemented. If there is a need for such a document, we should write the test cases in Behavioral-Driven Development style, which will save a lot of effort documenting.

So far, we only discuss TDD with unit tests, and people involved in this methodology are developers only. When there are more people involved in development (customers, QAs, etc.), simple TDD like what we discussed will not work. In that case, Acceptance Test Driven Development (ATDD) or Behavioral-Driven Development (BDD) should be considered. The principle is the same: test-first, but they focus on system-scale, rather than feature implementation.

That’s for today. Thank you for reading!

If you would like to be a part of Manabie and to work together to create more positive impact in education, let’s visit us at: https://manabie.com/careers

--

--