4 min reading time
4 Feb 2021
I went all in on TDD
TDD has always been at the back of my mind as a skill to adopt since starting programming. But I have never taken TDD seriously enough, minding almost no developer around me was practising it regularly, so I said to myself, heck I will have to get onto myself! So, I decided to go all-in on TDD this year. Here are the reasons I will never go back and what I learned.
Image by Martyn Cook
🏋️ The hardest thing about TDD
As you might have seen yourself, it's hard to learn something new, but even harder to unlearn. Going all-in on TDD, I had to unlearn a few things like writing code like a mad bull because you know I know Swift as a back of my hand. I thought I can write an extension that parses a float from a currency string in roughly 2 minutes, why bother with too many tests? It's just that it doesn't take localisation or numbers higher than 1000 in account because of that silly comma(,) (in the UK at least). So I had some work to do, think what kind of strings I would typically want to convert to floats, then think smaller, think bigger, think edge cases, think weird characters that could appear in my string, think currency sign and I would write a test to cover each one of those cases. And that was the hardest bit -> being really critical of my code before I was finished with it. Beyond that it was easy, turn that red into green, job done.
✅ Writing more tests gives higher coverage
First and obvious pro was that by writing tests first, I easily achieved 90%+ test coverage in my code. Mainly because coming from writing tests first, you cannot really go another way. If you want to write some code, you have to write the test for it first. That's the rule of the game. It's resisting the temptation of just wanting to write that piece of code that does that thing, and actually writing a comprehensive test that should validate what that piece of code does.
✅ Confidence in my code
By thinking deeply about even a small change and small pieces of code, like above converting a String to a Float, I noticed a thing that gives the most gain writing in TDD -> confidence in my code. As I am the first person challenging that bit of code, trying to stretch it and play a red -> green -> refactor, catch me if you can game I developed a lasting bit of a relationship with the code that I have just written. And that gave me confidence in its behaviour. It's like mini parenting experience with every bit of code, you give it free rein, see what it does, if it breaks a test, fix it right there, and then keep doing that until I cannot think of any more ways to break it. Now I know what frame that code will operate in and precisely what it will do. I help that bit of code in parenting sense to grow up to withstand challenges thrown at it.
✅ Taking modules / frameworks seriously
TDD also led me to port some code into its own reusable frameworks which contain code and accompanying tests. This brought me additional benefits like more access control by using open/public accessors in Swift. Tests running much faster inside its own framework target in Xcode -> think a 1000 unit tests for the whole App could easily take 15seconds (that's if they are fast!) and running about a 100 of them inside its own framework takes less than 2 seconds. The benefit of using frameworks is obvious. I noticed that the faster my tests are running, the more often I run them, which allows me to really quickly refactor code!
❌ Test coverage != realiable tests
Here is where my previous belief that tests coverage matters a lot was shattered into pieces. Don't misunderstand me, test coverage does matter, however, it doesn't indicate how reliable test suite is. Think of the example above converting a String into a Float, we could quickly achieve a 100% coverage by writing a couple of assertions. In that case, a couple of assertions wouldn't nearly cover all the edge cases, so in this case, test coverage would be misleading and relying on it might break a part of the App the worst time.
✅ Way less manual testing
Since going full in on TDD, I noticed I am doing way less manual testing by launching the App and making sure it behaves as expected. My tests confirm if what I am doing is working correctly, and I have found numerous bugs which I (or the team) haven't spotted previously. Hence why tests allow me to have full confidence in my code before seeing the final result coming together when running the App.
I know going all-in on TDD I will never go back mainly due to the confidence it gives me in my code and fact I can now trust my past self of taking care of a bit of code written in the past. This way, I can move on, solve new challenges and just have more fun at the work that I love!
I hope you enjoyed this article and learned something new on the way.