My first encounter with Test Driven Development (TDD) was a real head-scratcher. I found myself working for this small-time tech reseller that deals with government contracts. We were tackling some bone-dry, highly technical stuff, where even the slightest bug could easily evade detection.
To accurately meet requirements, the team adopted something called Test Driven Development, or TDD.
At first, I was scratching my head, wondering why we needed all this red tape in our development process.
But there was this senior developer, a true TDD evangelist, and he was all in.
As days turned into weeks and weeks into months, a transformation occurred within me. The discipline of the team's approach began to reveal its hidden beauty.
TDD wasn't just a set of rules; it was a philosophy that demanded a meticulous mindset. It forced us to think ahead, to anticipate potential pitfalls before they could cast their shadows. It transformed coding from a frenzied race against time to a methodical and calculated endeavor.
I can now say that my journey into the world of Test Driven Development was like a slow-blooming flower, unfurling its petals to reveal the splendor of its purpose.
The lessons learned and the mentorship received were not just about coding; they were about a profound appreciation for the meticulous art of sustainable software development.
“TDD applies a pressure to create code that is objectively “higher quality.” This is irrespective of the talent or experience of the software developer. It doesn’t make bad software developers great, but it does make “bad software developers” better and “great software developers” greater.”
― David Farley, Modern Software Engineering: Doing What Works to Build Better Software Faster
☯️Input and Output
Let me tell you something fundamental about code – it's got this beautiful symmetry to it, like yin and yang. You've got your inputs, and you've got your outputs.
They dance together, and that dance is what we call a testable unit.
You see, inputs can be as elusive as a shadow sometimes, and outputs, well, they can be hidden away like buried treasure.
But make no mistake, they're always there, lurking beneath the surface.
Now, TDD, my friend, is like a spiritual journey for developers. It's about transcending the mere lines of code, going beyond the allure of syntax highlighting.
It's about stripping away all assumptions and finding a higher meaning within the code itself.
It's like reaching a higher plane of existence.
So, you take an input, any input, and you expect an outcome, a result.
Let me give you an example – this random number generator, it takes two inputs, and in return, it spits out a random number between 0 and 1.
You can put that function under the microscope, test it in isolation, because it's a single unit. The input could be something as grand as a global variable
or as humble as a function parameter.
And what's that output, you ask?
The output might be sending data to an SDK, calling a callback function,
or maybe setting some value on an object.
See, the input and the output, my friend, they define the boundaries of that unit.
In my TDD world, I like to keep things simple.
Fewer inputs, fewer expected outputs – it's like trimming the excess and finding the essence of what you're testing.
So, testing a unit, it's all about setting up that expected output based on your input. It's a dance of balance, a symphony of code, and in the end, it's about finding that harmony between what goes in and what comes out.
That, my friend, is the art of TDD.
🏋️♂️Test Resistance
Let's talk about test resistance. It's that initial hurdle you need to clear just to start writing a test. Setting up the testing runner, dealing with codebases that weren't exactly built with dependency injection in mind – it can feel like you're wading through quicksand sometimes.
I won't deny it; there are moments when it seems like an overwhelming ordeal for a developer.
But oh, when you see that test go green, when you witness the triumphant passing of the test baton, it's like tasting victory.
And once you've had a taste of those highs, you'll find it hard to go back to full integration testing.
You see, full integration testing, while it has its merits, can be a bit like fumbling in the dark. The whole application crashes, and you're left scrambling to find the root cause.
Sure, a good debugger tool can help you in that maze, but there's a sneaky bug lurking in the code, hidden in plain sight, waiting for someone to stumble upon it in the debugger.
The problem with not writing tests is that these bugs can live undisturbed in your code until they're accidentally unearthed.
They're like dormant volcanoes, and nobody wants an unexpected eruption.
But here's the thing, my friend – like anything worthwhile, it gets easier with practice. The more you delve into testing, the more you conquer that initial resistance, the more you'll appreciate the power of pinpointing issues right from the get-go.
💼Test Suites
Every team has their own TDD. There’s no canonical TDD.
But you know what's at the core of all TDD? It's as simple as this: test your code. Until you see that code run and do its thing, you can't be sure it's functional.
💡So, the golden rule is always this – find ways to confirm that functionality.
Now, don't get caught up in the formality of it all. Your tests, they don't need to be all decked out in tuxedos and top hats.
Heck, they could be scrawled out in the REPL of your browser for all I care.
The key is to confirm the output of your code, to make sure it's doing what it's supposed to.
Formality, my friend, it's a secondary concern. When your project is a barren wasteland devoid of testability, formality becomes a luxury you can't afford.
I've seen teams swimming in a sea of capital, flaunting test suites with 90%+ code coverage.
But don't be fooled by the glitz and glamor of it.
Sometimes, those test suites are like fancy curtains, masking the chaos behind them – untested code, a tangled web of confusion.
You want to know a codebase that's truly testable?
Look at the number of dependencies each module carries.
Can you manipulate the inputs and capture the outputs?
Are the units clearly defined?
Having a test suite, that's just the tip of the iceberg.
Here's the bottom line – there's no need to get all formal about TDD.
What matters is that your code can stand the test as a unit, and that you've actually put it to the test. So, keep it simple, keep it practical, and never lose sight of the real goal – making sure your code works the way it's supposed to.
🪐We're All Stardust, After All
You know, when it comes to life and code, there's a universal truth - nothing is too big to fail. In the grand scheme of things, we're just specks of dust, fleeting in the infinite cosmos.
But hey, in the midst of this cosmic journey, our tests ran and passed today.
In the world of software, that's a small victory, a moment of assurance that our creations are doing what we intended. So, let's savor these little triumphs, knowing that in the grand tapestry of existence, we're all just dust in the wind.