So now we come to the true confessions part of the story…
You calmly lean back in your chair for a moment, taking in the news. “Wow, this is a pretty big change at this point in the release cycle, but I’m sure Management has considered those risks and the potential for a negative impact. They’ve committed to this course of action?” “Yes, and they’re not willing to make any compromises at all – this is a mandate.” says the PM.
For a brief moment, your mind flashes back to the meetings from last year when the team discussed development process, coding standards, and other related practices, unanimously voting to adopt TDD. You also recall standing your ground in a few conversations with upper management, helping them understand the value of TDD despite their initial impression that it was just busywork. Your mind then leaps to memories of the initial implementation, how the team had to expend additional effort building test infrastructure, shift their mindset to consider testability, and fully commit to architectural standards. At first, you recall, the learning curve was brutal but that effort paid rich dividends as the project matured, requiring less and less testing infrastructure while still providing appropriate code coverage. “And now,” you muse to yourself, “we’ll get to demonstrate to business and management how TDD also mitigates risk from unexpected changes.”
Although outwardly calm, internally you break into a cold sweat, thinking of all the changes they’ve just dropped into your lap. Your gut clenches, thinking about the explosion of possible side effects those changes will have. Since this is a non-TDD environment, regressions can only be detected manually, adding days to the QA testing schedule. As a slight silver lining, you do have some tests, but they’re a combination of low-value unit tests and slow-running integration tests, so they will be generally unhelpful in this endeavor.
The more pressing issue, however, is that the existing codebase was written sloppily. The team ended up leveraging many shortcuts like tightly-coupled classes and lack of dependency injection. Because of this coupling, removing the feature will have far-ranging effects on the codebase, putting the release at risk.
Let’s use a hypothetical scenario to explore TDD vs. Non-TDD development and how it may affect the outcome of a software project.
You are the lead of a small team of engineers working on an established product. One of the feature requirements for this release cycle involves a fairly significant amount of infrastructure work, which is already underway and about 40% complete. The project is currently on-time and on-budget with a release date scheduled for 3 months out. Under normal circumstances, pre-release certification consists of approximately 4 days regression and ad-hoc testing by QA staff.
Thursday, 4PM: Dave, your Business Analyst comes into your office accompanied by Patti, the project manager. Both have an ashen look about them, looking as if they’d seen a ghost. Dave pipes up: “So, we just had a stakeholder meeting that resulted in a release schedule change. They want us to stop work on the new feature, revert the infrastructure changes, and at the same time pull in the release schedule by 3 months. They’re pressuring us for an estimated release date, so we’re coming to you to find out when you can have the code ready to ship.” Dave then collapses into a chair, out of breath.