In many enterprise development teams, applications last for many years, if not decades. The technical debt of applications of this size tends to reach a critical point at which touching any aspect of the codebase represents a tremendous risk of introducing regressions. If any progress is to be made, management has to take action. This is most often in the form of a total rewrite by a newly formed "tiger team". The best and brightest of the department get to build the new system. Most development teams starting new projects like these manage to deliver fast throughout the first couple of months. Over time though, their speed drops precipitously, until reaching the same depressing lack of velocity as the old team experienced. The best and brightest of the tiger team tend to leave the company for more attractive challenges, and the folks in charge of the old system have to manage the new legacy of the replacement system.

It doesn't have to be this way. Throughout the past decades, practices have emerged that help to avoid the scenario outlined above. Pivotal, and later VMware Tanzu, specializes in these practices and has been very outspoken on why these practices work so well. At KOR, we share the same beliefs.

The best software is built through a process of gathering feedback and learning, which requires continuous delivery of software into the hands of users, getting their feedback, and iterating on the product in response to that. You can't do that if you're only fast at the beginning of a project. You need to embrace practices that allow you to go fast in a sustainable way.

There are lots of reasons a team slows down. But one thing that will always slow a team down is bad code. Teams tend to cut corners. You can go really fast if you cut all the corners – but only for a little while. It's false expedience. What made it easy to go super fast in the short term makes it impossible to go fast in the long term. The codebase very quickly resembles a ball of mud. And eventually, it reaches the point of no return, and those engineers will have no choice but to start over and try again. If you want to sustainably keep going fast, you need to have clean code. You need to consistently keep your code clean, throughout every single development iteration.

Every new feature you add to your codebase challenges the assumptions behind the code's design. You can either find a way to work around the invalidated design in your code, or you can take the time right then to fix it – to refactor it. Holding the behavior of the system constant while cleaning up the underlying design.

Most teams don't refactor – because they're afraid. They know the code is rotting, but they're not sure if everything will still work after they clean it up. To continuously refactor your code, you have to have confidence that the refactoring has still resulted in working software – that you haven't introduced regressions. The only way to get that confidence quickly is to write tests. Tests give you the confidence you need to refactor your code to keep it clean so that you can sustainably keep going fast.

So the question becomes: when do you do it? When do you write tests? And the answer is obvious. Everything depends on them. They're the most important thing. So when do you do the most important thing? Obviously, you do that first. That's why we TDD.

There are, of course, many more reasons why we write tests before, instead of after, we write the production code. Writing it first helps us tease out and think through our APIs. It forces us to clarify exactly what behavior we're trying to build since we can't write a test without that clarity—and it also lets us know when we're done. It helps us triangulate on simple, maintainable implementations, by making each test pass one by one and writing just enough code to make each test pass. Furthermore, writing the test before the implementation gives us the confidence that our test suites aren't giving us false positives; we first watch the test fail for the reason we expect, and then do the simplest thing we can to make it pass.

How come TDD isn't a universally applied practice?

Test-Driven Development is a practice that has been around for more than 25 years. One might wonder, if TDD is so powerful and beneficial, why isn't it a universally accepted practice? Great Agile trendsetters such as Kent Beck, Martin Fowler, Ron Jeffries have reflected on this very question. GeePaw Hill managed to capture its essence. By looking back at what forces shaped our field, we can start to understand some of the reasons why certain development ways have become the status quo.

Throughout the past 40 years, the software industry has been under tremendous, extraordinary forces. We've seen incredible technological advancement demonstrated by Moore's Law. Simultaneously, the number of practitioners has skyrocketed. In the '80s, the industry counted about 100,000 professional developers. Merely four decades later, we've well surpassed 25 million, destined to reach 45 million by the end of this decade. These are forces that shaped our trade and continue to do so in a myriad of ways:

  • About every five years, the number of developers doubles. This means that at any given time, more than half of the people practicing our trade will have done so for less than five years. In any skilled trade, experience and expertise come with the years. Ask anyone who has 20 to 30 years under his or her belt, how much they understood in their first five years.

  • For non-professionals, it is increasingly difficult to understand the complexity of the systems they use every day. Simply watching a Youtube video on your phone likely involves thousands of programs, created by separate teams in separate places at separate times.

  • Anyone entering the trade is very likely ill-prepared for the realities of professional programming. Computer science departments at universities focus on mostly different aspects than two of the most critical areas pertaining professional programming: collaboration and brownfield work.

  • Managers have a very hard time attracting talent and nurturing it. The average employment tenure for professional developers is two years. Simultaneously, short-term vision pressures developers into sacrificing quality, who won't be around to see the long-term effects either way.

Hence, the practices employed by the majority within the industry don't necessarily reflect what is right or advisable. If eating healthy is so beneficial, then why isn't it the default practice? If getting enough exercise is so beneficial, then why do people find it so hard to keep doing it?

TDD is like many other activities in that it has to be experienced, not only to be learned. It needs to have its value be revealed.

The distortions outlined above actively reduce even the possibility of getting that experience. And the greatest impact of those distortions is learned helplessness. The idea that, whatever experience you're having right now, is "just the way it is".

Seek experiences over bullet points. Take every chance to try a thing. Above all, don't assume what's going on now for you is "just the way it is".