Test-Driven Development, or more simply TDD, is a development technique of writing tests prior to writing code to fulfill those tests. It's a technique that's reputed to be underappreciated and underused, however, there are many excellent benefits to using it, especially when it's implemented correctly.
A lot of developers might skip over test-writing because they feel it's tedious and time-consuming. They may believe that manual testing and debugging tools are sufficient enough for gauging the functionality of their code, and that all the time spent writing tests could instead be put towards just building and completing their tasks sooner.
But before I share with you the benefits of TDD, allow me to first share a couple of personal experiences and scenarios where this sort of mindset I described can actually be debilitating to your workflow, your productivity, and your mental health.
What I mean by that is that with skills and knowledge aside, I have many personal qualities that contribute to making me a good developer. For example, I'm organized and meticulous, and I try to prevent mistakes by planning ahead before starting any writing.
But...I'll fully admit that my "planning" sometimes only takes place in my head...
...so sometimes, I might get sidetracked as I'm working...
...then sometimes, I'd fall down a deep, deep rabbit hole, and eventually lose track of what I'm doing...
...I might entirely forget what I was doing to begin with.
And just like time itself, the task I was working on passes with it, silently and without me ever noticing.
I like to believe that for the most part I think critically and carefully. I enjoy problem-solving and building, so it's fun and satisfying for me to write a few lines of code, run it, and instantly watch it work. I also like the challenge of writing longer, more complex lines of code. By manipulating multiple moving parts, finding ways to bring and bind them together into a smoothly operating machine, it feels like I'm performing the perfect juggling act. However, if there's so much as a single-letter typo, I get a broken, non-functional app and wasted hours filled with frustration and humiliation.
Like any person when given enough time, I'll make the occasional mistake here or there while writing long snippets of code. I'll continue building up, manually testing, sometimes even blindly trusting my code. And everything seems fine until I find a bug. Not a big deal, though. Bugs are common. I'll just patch it up. Easy peasy.
But I debug it, I'll find something else that was previously working perfectly fine now broken. Then I'll work on that bug and effectively break something else. That chain will continue, and by then it'll be especially clear and visible to me that the problem did not simply stem from just one small bug, but from a series of bad foundational habits. At that point, it feels near-impossible to draw a clear line between the buggy feature and the single-line of code that caused it, and what follows may be many anxious hours of debugging and scanning through hundreds of lines of code.
And during those long tension-filled hours, I'll also spend deeply and regretfully reflecting on how I could've made better choices and better spent my time.
But, but, BUT... I had reasons for doing things the way that I did.
I was on a deadline! I just didn't always have time to write out careful, detailed plans!
And it seemed easier and more productive to just tap into my manic energy and type frantically as I things came to my head! I swear, it really felt like I'm getting things done faster.
And mistakes happen! They're natural! And I thought I was sharp and SMART! With my massively-oversized confidence, I thought I'd make fewer mistakes. With my eagle eyes, I was sure I'd see errors as they presented. And with my powerful brain, I knew I'd eventually find some way to debug them!
Besides, I may not have known exactly everything that I wanted and needed to do right at that moment, but I understood the bigger picture, and I knew what I wanted to do next. I figured that everything in the middle would eventually fall into place.
I know now that all of those reasons were just excuses for poor habits and mediocre outcomes. After my last couple of experiences developing small projects using TDD, I've truly grown to appreciate tests and the time that I take to write them. And it's remarkable how much it's improved the way that I think about problems and progress through my code development.
Despite most people's attitudes towards Test-Driven Development, I have experienced these upsides to using the technique.
- It's helped me think critically about my code.
- It encourages me to plan ahead before blindly diving into a project.
- It creates a tighter, faster feedback loop, allowing me to catch errors more efficiently and code more confidently.
- It is 100% supportive of my experimental endeavors and efforts to improve and refactor my code.
- Continuing on from the previous two points, it helps keep my code tidier, DRYer, and less prone to bugginess.
- It doubles as documentation that clearly communicates to you and others who read your code what you're trying to accomplish.
- It helps me set goals, and keep me focused and on task.
- It's an objective communicator that helps bring transparency to where my code is functioning correctly and where it's not.
- It brings clarity to my workflow and minimizes my stress.
- Most of all, it improves my happiness.
I want to focus on the happiness aspect of TDD. Without sounding like some cheesy self-help author, I honestly feel that Test-Driven Development has helped my mental health.
As I used to code out projects, I often watched my confidence like a rollercoaster dramatically rising and dipping, and it exacerbated a lot of my problems with anxiety and my self-image.
Encountering surprise bugs or ones that were time-consuming to fix led me to believe that I wasn't a strong developer. That, in turn, made me frequently second guess my decisions and question my knowledge and abilities. And as I was consumed by imposter syndrome, I would become paranoid about making mistakes, and then I would have extreme anxiety about my poor time-management and my lack of focus.
I wasted a lot of time overthinking a problem to make sure I got a solution right the first time (and as would be expected, it rarely happens that way), or I wasted time debugging my way through a chain of broken features. And no matter how much I tried to compensate for all of those issues, no matter how hard I worked to keep my code functional and clean, nearly 100% of the time, I had to accept my work as it was, brittle and fragile, and there was no room to improve without risking the chance to completely break everything. I was utterly saturated with stress.
Test-Driven Development can prevent this downward spiral from happening. In a way, TDD is a lot like journaling. I document my goals, and then I focus on them. And as I accomplish those goals, I celebrate my success with a checkmark, and I move on to the next task.
But what makes TDD even better than that is that my tests instantly communicate with me, signaling back and forth between red and green, letting me know what's going wrong or right. And so, instead of coding blindly and helplessly, I'm actively being guided and encouraged by my own tests.
TDD helps give me many reasons to be happy. It helps me stay focused and productive and saves me time from debugging, which means I can use that time to do other fun and enjoyable things. It provides a clear sense of progress and acknowledges my wins and successes. Most of all, it helps me shed my anxiety and allows me to code with greater confidence.
If you haven't had a chance to try out Test-Driven Development, I really recommend that you do! Here are a few free resources where you can learn about a few of the testing frameworks and libraries available out there.
If you had to choose to look through only one of these, I highly, HIGHLY encourage you to check out Fun Fun Function. The host of the channel, MPJ, does a fantastic job acting out all of the thoughts, feelings, and perspectives around TDD as he teaches Jest basics.
- Fun Fun Function - Video Playlist on Unit Testing
- The Odin Project - Testing Basics with Jest
- freeCodeCamp - Information Security and Quality Assurance Certification with Chai