Welcome to the series of blog posts written by the team of Web Developers at Droids on Roids. While our group meetings we found out that we have different perceptions on various aspects of Test-driven Development (TDD). We decided to publish the conclusions from our long debates in the form of discussing and clarifying 6 Misconceptions about TDD.
The series is dedicated not only to web developers but also to mobile devs, while this article was written especially for business and app owners.
The agenda of this series about misconceptions is the following:
- TDD brings little business value and isn’t worth it
- We all understand key laws of TDD in the same way
- It’s hard to introduce TDD cycle to your everyday work
- There is one right size for “baby steps”
- Mocks, mocks everywhere! There is nothing more
- Tests loosely coupled with code are reliable
What is Test Driven Development (TDD)?
Usually, you write a piece of code and then – at best case scenario – you write tests for it. Put simply, TDD turns this sequence around. First your write tests, then you write a code.
- is an evolutionary approach to development which combines test-first development where you write a test before you write production code to fulfill that test and refactoring (@scottwambler, agiledata.org),
- before writing any code that adds new functionality to an application, the developer first writes an automated test describing how the new code should behave (freeCodeCamp),
- makes you thinking through your requirements before you write your functional code (Agile Software Development…),
- helps developers to write clean code that works and is easy to maintenance,
- is controversial, among developers as well as the businesses.
In the next article, we will deepen the definition of TDD. In the 3rd post of this series, we will write about Red Green Refactor cycle which illustrates TDD short development cycles (it was an inspiration for the fidget spinner in our post’s main graphic).
TDD from the app owners and business’ perspective
If you are a CEO of a startup, app owner or you have an app concept, you may think that, in theory, TDD is a good practice, but that there is never enough time to really use TDD. And others may believe that it is basically a waste of time. If you feel this way, this post will change your mind. You will discover the advantages of test-driven development for business owners.
We want to advocate TDD as the right way to develop mobile and web applications. There are at least 4 huge advantages of TDD over other, non-TDD workflows.
Let’s describe them briefly (the last one may surprise you!) before discussing how exactly those advantages benefit your business.
1. Better internal code quality
The term “internal code quality” describes how easily you can change the code. Essentially it means how little the codebase slows you down in achieving business goals. The better the code, the less obstacle it makes. With the high-quality code, you can quickly add more features to the codebase and make fast and frequent deploys.
This metric is hard to measure but easy to compare. Experienced developers have gut feelings about how good or bad is a codebase.
TDD leads to better code quality. I think, public opinion agrees to that claim – if they have something against TDD, the debate usually start with: “Yes, you will have better code, but…”.
It is even told that if you follow TDD, it will make your design better. This is a slightly wrong point of view. TDD doesn’t make you anything particular. It’s only a technique.
But indeed, sticking to TDD will make your design decisions easier. This is because TDD makes developer thinks about design decisions early on in the process. That’s all you can ask for. Individual projects are different enough to always need to build their design independently.
One important caveat is that TDD works this way if your developers are experienced in TDD. Beginners will make their mistakes.
2. Developers‘ comfort
TDD is in many ways pleasant and convenient to developers (in what way? I write more about below in the paragraph “How you can see those benefits in everyday work?”). Happy developers are eager to work with the codebase. It usually leads to more commitment, better ownership, faster responding, rapid development, being proactive and self-sufficient.
It doesn’t matter if you hire employees, contractors or software house. If you want a successful software, you need to care about your team’s satisfaction.
It’s straight in the name. There’s no TDD without an extensive collection of automated tests (commonly called “a test suite”). This also implies a testable code. If you ever heard advantages of those, you can apply it to TDD workflow as well.
It doesn’t work the other way around – you can have tests, but it doesn’t automatically imply TDD. TDD is only one out of many ways to achieve testable code extensively covered by tests. However, with TDD tests are certain, while in other workflows, tests are typically treated as an extra (often neglected or abandoned in hard times).
With TDD, you save a lot of time, although, at first sight, it may appear otherwise.
This advantage is worth elaborating. It’s the most common accusation to TDD – TDD costs much time. From our point of view, it’s not true.
You need to understand one important thing. Time of writing tests is taken upfront. On the other hand, tests save time over the lifetime of the project. Therefore the benefit might be easy to overlook and hard to judge.
How TDD saves time in everyday work
TDD saves time in a lot of activities that happen in everyday work:
- understanding the domain layer of the project,
- understanding the technical layer of the project,
- refactoring (improving the structure of the code without changing its behavior),
- healthy checks (for example, no regression).
Developers have to do those things to have control over the codebase. But how often do you see Jira issues for such tasks? Probably very rarely. And yet these are things that burn your budget. And that’s the way it is – you can’t change it.
This is how it is typically handled – time for these routines are usually incorporated into other issues: “The fix itself is 1 hour, but I have to refactor this part first, then read up to that part, and finally test if nothing got broken; that will make 3 days total”. Sounds familiar?
It’s really not that uncommon to spend one or two days in a very simple fix if the codebase is low quality. Ask your developers if they haven’t faced such situations already.
We understand that such situations can be annoying to the business. The time spent on a feature is not related to its scope, but rather to the quality of the code.
Now if you compare it to TDD, those problems are usually gone. However, it’s impossible to measure how much time would have been spent on those issues without TDD. Therefore, it’s usually underestimated how much time TDD saves.
Tests are not an “extra work”
You may wonder if the time spent on writing tests is worth it. You might have heard from your developers that they are late with the feature because “they had to write tests”. This probably sounds to you like the tests are some kind of “extra work” for the feature itself. You can’t picture it like this. These two are inseparable.
Tests are proof of correctness of the code. There is no other way to prove it. Tests are part of a feature. If you think otherwise, you live in a lie. In other words, writing automated tests should be included in your Definition of Done, otherwise, you don’t know what is delivered.
If tests show that the code doesn’t work in 50% of use cases, that a big win. It’s better to find those issues during the development phase than after release by your users.
You shouldn’t blame tests for this discovery. You should blame people who claimed that the untested solution was correct. Fixing others’ mistakes is another byproduct of TDD.
If you or your developers want to “save time” by “not writing tests”, this is not only false, but it’s pure madness. The code might be delivered earlier, but a usually very poor code that does ⅓ of what’s required and keeps generating bugs and fixes; the code over which devs don’t have real control. The code very far from robust. If you think this is only an unlikely possibility, you are wrong. From our experience, this is the case with most codebases without tests.
TDD is time efficient not only in the long run
This all may sound like TDD is time efficient only in the long run, but it’s not totally true. Also on the scale of one feature, developing could be faster with TDD. However, some developers never saw a proper TDD, so they can’t even feel the difference.
When TDD won’t work
If the development of your app is in progress and your legacy code or its architecture is of poor quality, you may not be able to use TDD. Such code may be untestable, so TDD won’t work. If that’s the case in your project:
- Think again. Sometimes “not testable code” means “code hard to test” or “the code that my developers can’t test”. Maybe they need training, more experience, or a fresh pair of eyes to introduce TDD?
- Let go of TDD. It’s the best choice where TDD doesn’t fit.
However, if we are talking about new projects, where you are just beginning development, this problem doesn’t exist, so you have no excuse not to use TDD.
The advice of our Web Team is the following: We strongly suggest trying TDD in every project, but not being dogmatic about it.
How you can see the benefits of TDD in everyday work?
The advantages of TDD for business owners are noticeable not only in the long run but also in your day-to-day cooperation with the team.
- TDD leads to fewer bugs. Nobody wants sprints full of bugs. We should rather aim for sprints full of new features (quality, time).
- It’s not only about the numbers of bugs. Think of it this way: in typical projects without tests, you finish the feature, but in weeks, months, and longer, there are bugs found within it. Developers don’t have this feeling of “closure”. They can’t really close one feature and move to another one, because there’s always a fear of uncovered edge case (comfort).
- Extensive test base is often referred to as “a safety net” that can early catch mistakes when changing the code. With that “safety net” developers are free to improve code quality (refactor) on the fly, without asking for permission in the form of “refactoring task” or “refactoring sprint”.
What’s more, in TDD, there’s a precise phase when you perform refactoring, so they are encouraged to do constant refactoring (quality, comfort, tests)
- A better understanding of the domain. With TDD, you have to focus first on what the code needs to do. That typically leads to specific questions for business people. What lands on production is not domain knowledge, but devs’ understanding of domain knowledge. The more they know, the better decision they can make (quality, comfort).
- Partial delivery. In TDD, you can literally spend 5 minutes on the code and deliver value. Every phase of the TDD cycle (failing test – passing test – refactoring) can be sealed with git commit, and they usually take less than 5 minutes. This is virtually impossible in other development techniques (time, comfort, tests).
- Tests make great developer-friendly technical documentation. Why great? Because they can immediately check if they are still true. In TDD, there has to be plenty of tests (quality, tests, comfort).
- Easy onboarding. Solid test base is a tremendous help for new devs (time, comfort):
- The documentation mentioned in the previous bullet is gold. Other devs don’t have to spend much time teaching the new ones everything about the code.
- Typically, the first few commits in the first few days in a new job are dangerous. It’s easy to introduce bugs if you don’t know the domain and the codebase. With tests, it’s no longer scary, because they can run tests and check if anything gets broken.
- Code reviews are easier too. There’s always a bunch of tests along with the code that explains it and helps to understand the codebase and domain.
- For the same reasons, TDD makes it easy to learn unfamiliar areas of the project. That is helpful in devs rotations and keeping bus factor high (time, comfort).
- Not waste time on manual testing. Developers always test their code, I guarantee it. Sometimes they do it manually. Automated tests are just those, except written in a repeatable manner.
If you don’t have an extensive test case, you waste a lot of time on manual tests. And believe me, the software is so complicated that in order to not introduce bugs, developers MUST test it over and over again. Sometimes this can significantly unload your QA team (time, tests).
- Ability to quickly answer specific, technical questions like:
- How does our system behave if you pass parameter X here?
- Is it easy to add another type of Y?
- Can you change id type from string to integer?
With TDD you rarely need research tasks for such investigation, because you can quickly check it in your tests (time, comfort).
- More careful development. TDD process forces you to think of limited pieces of the app at a time and neglect the others for the moment. This means you automatically consider cases that could be overlooked otherwise. Written use cases of your code (a.k.a. tests) increase the chances of not missing nasty edge cases, when it comes to changing behavior, or refactoring (quality).
- TDD allows for continuous integration, continuous delivery, and continuous deployment. Without robust codebase, your continuous integration (CI) server is worthless, and the rest of the pack make no sense (tests, quality).
Now you see why developers insist on TDD. This isn’t only a “cool tool” from a technical point of view. It is more like a way to make the project more robust, and your business more profitable.
Let me leave with repeating a piece of advice from our Web Team: We strongly suggest trying TDD in every project, but not being dogmatic about it.