I’ve spent the better part of two decades writing software professionally. I could divide this time in any number of ways. For instance, I could do it by programming languages learned, tech stacks used or jobs worked. But I actually tend to divide it loosely in half, into my pre-TDD and post-TDD days.
Does that sound a little crazy? I suppose it could, but that’s how dramatically adopting TDD (test-driven development) affected my career. Describing what TDD is, exactly, would make an excellent blog post unto itself. But for our purposes here, I’ll describe it briefly.
TDD is a software development methodology with a very precise discipline and cadence. When writing code, you start work on any new functionality by writing a failing test. You then write just enough production code to make that test pass without breaking any other tests. And finally, when everything is passing, you refactor the code you’ve written (and any other code that needs it) to be cleaner and clearer. And that’s it. Rinse, repeat.
As simple as this is, it creates some incredibly powerful benefits. And because of that, I consider my adoption of TDD to be perhaps the most influential moment in my career of writing code. The practice provides so many benefits.
Recently, though, I’ve realized that these benefits don’t just apply to writing code. They apply to everything I do professionally. And so today I’d like to share some of those lessons.
Get TestRail FREE for 30 days!
Tighten Your Feedback Loop
First up, let’s take one of TDD’s most obvious and immediate lessons. I’m talking about the idea of a feedback loop in your work. Feedback loop is a specific engineering term, but the business world has borrowed it to talk about the time that elapses between performing an action and seeing the results of that action.
Traditionally in software development, you might work on the code for a feature for a day or two before finally putting it all together, running it, and seeing if it works. When you start doing TDD, however, you’re forced to tighten that feedback loop considerably. The fail-pass-refactor cadence forces you to look in much more granular fashion at the results of your work. Doing this, you catch mistakes earlier, and develop a much stronger association between good actions and their results (and bad ones and their results).
This is not, of course, limited to the programming world. You should aim, in everything you do, to reduce the time between action and outcome. Rather than meeting with your manager once per year at a performance review and only then learning how you’re doing, ask for weekly one-on-ones for faster feedback. Ask colleagues for early input on a few paragraphs of a report you’re compiling, rather than writing all 10 pages and hoping for the best.
You get the idea. With everything you do, look for the feedback as early as possible so that you can course correct if need be, without wasted time and rework.
Define Success Tangibly Before You Start
When you think about what it means to write a failing test before every bit of code, you’ll realize that what you’re really doing is defining success up-front. Think about it. You call out a deficiency (whether because of a bug or simply because you have a feature not yet implemented) in the current state of the software.
For instance, you’d write a failing test saying that the customer report should display an SSN when you want to add that information to the report. In so doing, you’ve defined success. “This test will pass, and we’ll be done with this feature, when the customer report displays the customer SSN.” That’s unambiguous and it’s easily evaluated.
Outside of the realm of programming, however, we do this all too infrequently. Perhaps we tell the marketing department to “grow our social media following.” Well, okay, but what does that actually mean? How will we know when we’ve succeeded and are thus done?
Taking lessons from TDD, you should start thinking of all of your initiatives in terms of “we’ll know that we’ve been successful at this when _____ is true.” This will not only help you evaluate your own performance, but it will also surface situations where people are setting hazy or nebulous goals for you.
Make It Safe to Constantly Improve
Think for a moment about the ramifications of preceding every change to a software system with an automated unit test. You’re going to wind up with a lot of unit tests. But more than that, you’re going to wind up with a lot of confidence in the code and in your ability to change it.
When you practice TDD, you feel safe in making modifications and in constantly changing, tidying, and refactoring the code.
Seek to recreate this confidence everywhere possible in your professional life. Do you have some “tricky” Word document or Excel spreadsheet that your whole team uses to track information? Are you terrified to use it for data entry, let alone to improve it? That’s not a reasonable situation — you should figure out how to get it to a state where you feel good about making changes to it.
The same thing applies to human interactions. Your team shouldn’t exist in a brittle situation where doing something like, say, switching to a more efficient communication platform, has dire and unpredictable consequences.
This situation may take some creativity both to recognize and to fix, but it’s important to do so. Systems that nobody wants to touch will degenerate as time goes by, failing to keep up with the evolving demands of the world.
Have an Early Warning System for Problems
Related to making changes safely is the idea of an early problem detection system. The unit tests resulting from TDD provide confidence, as I’ve just described. And they do that with an implicit guarantee that, should you make any problematic changes and break something, you’ll know about it right away.
In other words, TDD generates an early problem detection system when it comes to your code.
Seek to create the same thing in all that you do. Your car has one in the form of its trouble lights. Your house has smoke detectors and carbon monoxide detectors. And so your various business processes and should as well.
Make it a habit to ask yourself how you’d know if something went wrong. What if you missed an important email from a client? What if a deadline slipped your mind or you added some embarrassing mistakes into a widely distributed document? What would give you a heads up about this?
It could be simple things, such as daily checks of your SPAM folder, Outlook reminders, and spell check. Or, perhaps you do something more involved and unique to your situation. Whatever the case may be, however, you want to make sure you’re building processes and systems that prevent you from being blindsided much later.
You Can Only Solve One Problem at a Time
I’ll close with perhaps the most fundamental and philosophical lesson that I take from TDD, myself. And this is that you can really only solve one problem at a time. We’re kidding ourselves when we think that we expertly multitask.
Based on my description of TDD, this may not seem like an obvious lesson. But the cadence of TDD forces you to decompose large problems into many small ones. You then express those many small ones with tests and solve them sequentially. This is because you’re only ever allowed one failing test at a time, which means you’re only ever allowed one small, manageable problem at a time to tackle.
I’ve worked as a software developer, a software architect, a tech executive, a consultant, a writer, and a business owner. And in all of those varied lines of work, the lesson of tackling one thing at a time has always applied and always been extremely valuable. You can make all of your bigger problems into smaller ones, and you can then prioritize those smaller problems. From there, you might have elaborate systems for keeping track of them, but you can only meaningfully solve one of them at a time, checking each off and moving onto the next.
So apply the lessons from TDD. Solve one problem at a time, defining success clearly before you start, focusing on it exclusively as you go, feeling confident in your work, and learning quickly how it has gone. And then rinse, repeat.
This is a guest post by Erik Dietrich, founder of DaedTech LLC, programmer, architect, IT management consultant, author, and technologist.
Test Automation – Anywhere, Anytime