Learn more about Velocity Partners offshore software development company
There’s no doubt that writing unit tests for our code is an excellent practice that results in great benefits. But in this article I want to touch on the subject about of writing the tests before the production code (a technique known as Test-Driven Development, or TDD), or if I should cover the code with tests (write tests after production code).
Last year there was a great discussion on this subject. The subject triggers passions and there are who suggest that not writting the tests first is unacceptable.
When I’m asked about if I use TDD on a daily basis, my response is it depends. As all practices that we use in agile, the context influences many things, and we cannot be close-minded and think that TDD applies in all cases. I generally don’t have enought time to elaborate my answer when asked, that’s why I’m writing this article. The following are some factors I consider when deciding to apply TDD or not :
New project vs. legacy project
It is easier to apply TDD when we have a new project, because there’s no architecture defined yet and there are no bad practices already present in the code. But the reality for a lot of us is that the projects we work on were created several years back when testing was not taken into account, resulting in code with strong coupling and excessive inheritance. For these type of projects, I generally don’t use TDD but rather make the coding change and try to cover it with a test. If there are existing test, I evaluate the quality of those, to decide if it’s possible to write a test first, but my experience is that tests in legacy projects are not very expressive or are very cumbersome (due to strong coupling).
But if I need to do a relative complex change where many variables have to be considered, I prefer to apply TDD to create a new component that handles this business feature, and then refactor the legacy code to use this component. This helps me create better questions about the conditions (which are the inputs to my tests) and be sure about the expected results. It evens help the client to understand all possible scenarios. The result is a TDD designed component injected into the legacy code.
Even for new projects, I’ve found it’s not optimal to start with TDD at the very beginning, where there is much uncertainty about the requirements. I tend to focus on building a walking skeleton to start making early architecture decisions and understanding a little more about the type of objects I’ll be designing through tests, which at early phases may not be totally clear and may change a lot. This helps to greatly reduce the uncertainty and to understand the business better, which results in a better application of the TDD technique later on.
Once you understand better the core business, you can start covering your objects with tests and start using TDD to add new features to the application, while refining your starting design.
Language and testing tools expertise
As a passionate developer, I like to test new languages and their testing tools. I work with Java on a daily basis, so I have total command of the tools and am very proficient writing tests and doing TDD in this language. But when a try a new language, I need to take enough time to understand the language and it forms. If I try to start with TDD I’ll surely fail to understand both the language and the tools, because I’ll bring my Java-ish knowledge and try to apply it, which can make no sense.
So when starting with a new language, I prefer to start doing small projects to get the feel of the language style, and then try to cover the code with tests and learn about the testing tools. Once I feel comfortable writing code and tests in the language, I start thinking about writing tests first.
The expertise in a language doesn’t necessarily ensure that you’ll be proficient in writing tests, because you need to be proficient in both things before even attempting to apply TDD. I think a lot of people have a hard time applying TDD with their languages because they don’t spend the quality time to fully learn and understand the language’s testing frameworks.
Finally, there are some businesses that are easier to understand than others which are more complex. When complexity increases, being able to isolate parts of the system and have a good understanding of the way they work is something where TDD can helps us a lot, because of it’s progressive way of adding features having covered the previous cases, which allows us to make safe steps towards the final solution.
If you have been writing tests and code in a language for a long time, it’s possible that you can start skipping TDD’s baby steps, and start trying to code the final solution from the start. Be aware! Sometimes to advance, we have to return to the basics!