How to introduce ATDD in Legacy Code? (in 3 months)
Your codebase is Big Ball of Mud with no tests. Your team has to wait 3 weeks for Manual QA. Releases are delayed for months. How do you escape this nightmare?
📅 Join 100+ engineers at my next FREE live event Stop Breaking Production: ATDD in Legacy Code (Sep 17 at 5:00 PM CET)
🔒Hello, this is Valentina with a premium issue of the Optivem Journal. I help Engineering Leaders & Senior Software Developers apply TDD in Legacy Code. This article is part of the TDD in Legacy Code series.
You’re stuck in maintaining a Legacy Product. There’s no tests, you’re relying on the slow Manual QA. Most of your team’s sprint time is spent in fixing regression bugs and reworking features. Business is angry why nothing is delivered.
Everyone accepts this as “it’s the way things are, there’s nothing we can do about it“.
The “silver bullet” fallacies
So your team got together, and they all acknowledge these problems:
Delivery is too slow (and it keeps getting slower)
Too many regression bugs (and the bug count rises over time)
But then, when it comes to how to solve the problem, this is where it starts getting really messy. Everyone has a different opinion of what’s the root cause, and what needs to be done first.
Some people see the problem with code and architecture:
“AI is the solution to everything. If only we bought the next latest-and-greatest AI tool to write 90% of our code, then we’d be shipping fast.“
“We have an old tech stack. If only we moved to the next shiny programming language and the latest framework, then our problems would be solved.“
“The problem is that we have a monolith. If only we moved to microservices, then all our problems would be solved.”
“Our code is messy. We should focus on SonarQube reports. If only we had clean code, then all our problems would be solved.“
Some people see that the problem is with our process of working:
“The problem is our User Story tickets. If only the PO was writing more detailed tickets, then it would solve our problems. The PO is the root cause of all problems.“
“The problem is that we have too many Scrum meetings. If we eliminated those meetings, then developers would have more time to do real work.”
“The problem is JIRA, we have to spend too much time on the tickets. If only we moved to a simpler ticketing system, we’d have less wasted time.“
“The problem is we have a siloed organization and we’re not communicating well. If only we solved the people problem, then we’d have better delivery.”
“Our PR review process is not good enough. Let’s write a procedure on how to do it better. We also need to have multiple reviewers.“
“If only we had well-documented coding standards, then developers would do more quality work.“
Some people see the problem as we’re understaffed:
“We don’t have enough developers. If we hired more developers, then things would speed up.“
“We don’t have enough QA Engineers. If we hired more QA Engineers, then it would reduce testing time.“
Some people see the problem as being that we don’t have tests:
“Let’s automate E2E Tests. We could buy an AI tool to do that. Then we could get rid of Manual QA.”
“If we wrote Unit Tests and had 80% code coverage, then we wouldn’t have these bugs. It’s important to catch bugs early.“
Some give up, and say the only solution is to start from scratch:
“Everything is horrible. We should just fire everyone, hire 10X developers and rewrite everything from scratch.“
Do NOT start with Architecture Redesign.
You try to redesign Architecture, for example, by making your Monolith modular. Or you try to switch from the Monolith to Microservices. Or you want to redesign your Microservices to escape the Distributed Monolith. Or you want to restructure your database to support a modular system. Because you heard “modular“ means good.
❌ If you try Architecture Redesign, BUT you do NOT have Acceptance Tests (instead you’re relying on Manual QA), then you’re going to spend months fixing regression bugs caused by your “better“ architecture (and your architecture redesign branch redesign won’t ever be ready for production). You’ll end up with cleaner architecture, but it doesn’t work correctly, and isn’t deployed to production. This is negative ROI.
✅ The right way: Stay with your Big Ball of Mud (for now).
Do NOT start with Clean Code & Unit Tests.
You’ve probably heard Uncle Bob promoting Clean Code & Refactoring everywhere. SonarQube is reporting lots of code smells, so you have to fix them, right?
❌ If you try to refactor towards Clean Code, without Unit Tests, then you’ll cause regression bugs. So then it means you have to introduce Unit Tests first. But since the existing codebase is a Big Ball of Mud (everything is tangled up, business logic is coupled to I/O), then it’s not Unit Testable, so then you have to break dependencies to introduce Unit Tests. As you break dependencies (for the purpose of ensuring Unit Testability), BUT you do NOT have Acceptance Tests, then you’ll introduce lots of Regression Bugs (and your “big refactoring“ branches won’t ever be ready for production). You’ll end with cleaner code, that doesn’t work correctly, and isn’t deployed to production. This is negative ROI.
✅ The right way: Stay with your Messy Code (for now).
So what should we do first? ATDD.
It took me a decade to realize that the solution is to firstly introduce this:
Pipeline
Acceptance Testing
ATDD
When you have that foundation, then you’re ready for any other improvements. You’ll then be able to safely upgrade your Tech Stack, redesign your Architecture, introduce Unit Tests & clean up your Code.
How to introduce ATDD in 3 months?
If you’re a Senior Software Engineer or Engineering Leader, who has a strong level of self-initiative, and you want to introduce ATDD in your Legacy Project with guidance rather than trial-and-error, then I can help you:
Now I’m going to share with you my step-by-step for implementing ATDD in Legacy Code in 3 months, without disrupting your feature delivery: