Co-authored by the badass Diana Villanueva
Test Driven Development (TDD) is a software development technique practiced by a portion of the developer community. In this article we are going to focus on the benefits TDD provides for product managers, product owners, and stakeholders. If you’re managing a project that is written without TDD, you’ll be missing out on a lot of the benefits we discuss below. And if you’re unfamiliar with TDD and managing a project that is developed without TDD, you’ll be able to notice some of the common problems we’ll highlight below, but you wouldn’t be able to suggest TDD as a solution. So it’s important that you learn how TDD can benefit your project and why your development team should be using it.
What does TDD look like?
Imagine you want to deliver a new feature that allows existing users to login. In a typical development approach, developers generate the login functionality without any automated tests and report the feature as done. With a TDD approach, developers write a test first. The test would say something like: “When the user exists and they log in with the correct username and password, they’re taken to their dashboard.” This test would immediately fail because the login functionality has not been built yet. Then, the developer would build the functionality that satisfies the test and the test would pass.
What are the benefits?
Before we jump into TDD, we’ll talk about the benefits of automated tests. What’s the difference? If the developer used the traditional method for the login feature, then wrote a test to check that it worked, that would be an automated test without TDD. It’s only when you write your automated test before the feature that you’re practicing TDD.
Automatic Tests help with:
Regression and Bugs
Imagine you spend the whole day doing chores around the house and at the end of the day you realize you don’t remember where you left your keys, but know you had them at the beginning of the day. Now, you have to think back through the whole day and look everywhere you’ve been. Now imagine a different scenario where you check for your keys every five minutes. In this scenario, when you lose your keys you only have to think back the last five minutes. You’re going to find them much faster.
Automated tests work the same way. If you discover a bug in your production environment, it’s much easier to find and fix it if you had a way of knowing that it worked five minutes ago: “Whatever we did in the last minutes caused the problem.” Automated test are fast and repeatable. You can build an automated test suite that tests your entire app every five minutes. Automated tests on new features can catch issues before they’re released to production. If a problem does reach production, automated tests reduce the surface area of the problem space. The more automated tests you have, the less untested code there is to comb through.
To summarize, automated tests can quickly and frequently check that features work. The more frequently you check, the sooner you find and fix problems. The faster you fix problems, the more your developers can focus on building new features that deliver new user value.
Confidence to change code and deploy
You want to focus on writing stories that deliver user value, regardless of what part of the application it touches. With the traditional method of development, a lot of developer behavior is motivated by fear. If a new feature requires too much change, there’s concern it will break existing features. There may be nasty parts of the code base that nobody is willing to touch because if it breaks, it would take a while to notice or have devastating effects. When fear interferes with quality, features will take longer to finish. Developers will think of creative ways to avoid interacting with the scary part of the code. These creative ways can’t take a direct path through the bad code so they’re harder to understand by others. This is why bad code tends to cause a downward spiral of quality unless addressed. The best way to address the problem is to surround it with enough automated tests that developers feel confident it can be changed without breaking any functionality.
If you’ve ever been in this situation, you may have felt pushback and pressure to prioritize different features by developers. But if there was a trusted test suite in place, this would not be a major concern. The automated tests would tell you and the developer that the existing features still work.
This also gives you an alternative to the dreaded “rewrite”. Rewrites are expensive and difficult to pull off. There’s no guarantee the rewrite will turn out to be better quality. You don’t need to rewrite the app if you can confidently change it to whatever you want.
In addition, when you trust your automated test suite, you have a lot of confidence that your features work because they’ve all been tested. This confidence allows you to deploy to production frequently without stress. No more all nighters.
Documentation
Here is a problem we often encounter: You have documentation that says when you put in a coupon, you get a discount. If the application code changes this behavior, the documentation will have incorrect information unless someone actively combs through it to keep it up to date. Keeping the documentation in sync with reality is expensive and not a huge value add relative to new features. In this context, it can be pragmatic to keep the documentation out of date. But, when someone reads it later they’ll be misled by its information. This makes people question its accuracy and when people are skeptical of the documentation, they tend to not read it. In the end, a lot of the effort to write it in the first place is wasted.
Let’s compare this to automated tests: If the coupon code stops working, the tests fail. Automated tests tell developers when they’re incorrect, traditional documentation does not. Automated tests act as a form of developer documentation that are always up to date. This helps velocity stay consistent even when new team members join the team.
TDD is automated tests on steroids
With TDD, you’ll get all the benefits mentioned above, plus these additional ones:
Better test coverage
When developers write automated tests after the feature works, it’s easy for them to forget to test some functionality because they have to think back and go through every possible path. When forgotten paths are discovered later, developers lose confidence in their entire test suite. They think, “What else did I miss?” This puts the team in a “worst of both worlds” situation where they put effort into automated tests but don’t trust them so they spend effort on manual testing, too. It’s a skill to write testable code and the most straightforward way to write a feature isn’t usually testable. Therefore when developers write the feature first, the code must often be modified so automated tests can be written against it. This creates a “measure once, cut twice” situation where the developer builds the feature, tries to test it, but then realizes they have to rewrite the feature in order to do so. Then time constraints cause developers to skip a lot of tests they should be backfilling.
When developers practice TDD, they write the test first, then write the minimal amount of code to make it pass. It bypasses all these issues. They’re sure that all their code is tested: It wouldn’t be there unless there was a test saying it needed to be. When you don’t practice TDD, you have to manually check the application to get the same confidence in it.
Deliver user value with simple solutions.
By writing a test first, developers constrain themselves to write the minimal amount of code to make the test pass. This focus prevents the common problem of over-engineering: Writing overly complex solutions when a simple one would suffice. Simple, minimalistic solutions maintain high quality. They’re easier to understand and there’s less to read through. This means they’re easier to maintain and change than complex, ornate solutions.
Easier for other apps to integrate with yours.
When other systems work with yours, the developers of the other teams will appreciate convenient APIs. This will make your product more appealing and people will be more willing to leverage it. Test Driven code is usually more pleasant to use. That’s because when the test is written, the developer has to think, “I wish I had some code that I could call like this, even though I don’t.” That’s exactly how anyone integrating with your APIs are going to think. In other words, TDD code is written the way people want to use it. Using the traditional or the test-after approach doesn’t usually work this way. Instead, the focus is on how to make the feature the easiest to implement, and that’s not always the most convenient way to use it. As a result, the design of the code becomes an afterthought.
PM and Dev agreement on Done.
TDD encourages and documents conversations about the definition of “done”. If the feature says, “when the user enters the correct coupon code, the discount is %15”, the developer can write a test that says exactly that. TDD makes this test the first step for the developer so the conversation has to happen early. With traditional processes, there’s a tendency for these conversations to happen after the feature is already written. It’s very expensive to realize the devs and PM are out of sync at this point because the feature may have to be rewritten and retested.
Hopefully these examples informed you of the value of TDD for your product. TDD is not only a developer tool, it is a methodology that helps provide better test coverage which in return increases confidence in your product and deployments. It focuses developers on the minimum amount of code required to deliver user value. It ensures a consistent velocity over time by eliminating unnecessary feature rewrites and reducing time on bugs.