Low investment TDD—Be conscious of your "digital transformation"
A remedy for teams overwhelmed with tech debt
TDD survey on your preferred adoption style or hesitancy is still active. Make your opinion known. Only takes 60 seconds!
Consistency. No overwhelm. Slow is smooth.
For the past 6 months I have been working with Omniconvert. The goal was simple: support their product engineering and tech leadership culture by having regular coaching and mentorship on topics including and surrounding Test-driven development and Domain-driven design. Typical stuff.
They have the blessing and the curse of working with hundreds of clients, including dozens of big ones. You know what this means:
An enthusiastic team
Frequent product experimentation
Large amounts of data to process
Wide array of features
Rich per-client customization
A plethora of legacy code
And tons of support tickets
Such a team naturally doesn’t have a lot of time to invest in new methodologies. Especially one that would signal other downstream issues. I always say TDD won’t solve all your problem. But it will strongly signal everything that can be and should be improved in your tech culture.
In a way, it is the tip of the ice berg. Beneath the surface you’ll find everything that makes product engineering hard:
Refactoring skills
Software design skills
Object-oriented design knowledge (not the patterns)
Code smells
Domain-driven design: tactics and strategy
Event modeling and storming
Shaping a common non-technical language with domain experts
Negotiating and pushing back on unrealistic demands
How to facilitate more teamwork
How to work as a team, constantly improving processes
Fixing and improving the SDLC and CI/CD pipeline (We’ve seen major shifts in the 2020+ era)
How to triage support and free up your calendar
That’s what we’ve been improving in these 6 months. Low intensity: a few hours every week in an ensemble. Slow and smooth. Tackling one problem at a time and building on theory and practice on the actual code base. It wasn’t always easy, but the level of confidence and process quality is starting to show dividends.
Start with the hard decision: Trade offs
You might be facing yourself in a similar situation as Omniconvert’s teams above. Your legacy codebase that is hard to test and refactor was born in a difficult world. Under challenging circumstances and real deadlines. Congratulations. You survived. You likely aren’t working with an ideal team in an ideal setting on an ideal legacy system. For a reality check, here is a typical common situation:
Messy, legacy codebase
Original authors are no longer with the team
Limited refactoring knowledge
No tests
Tests that are there are unreliable
High coupling
Hard to replicate data in complex environments
Microservice coupling hell
Features take days or weeks, not hours
Simply put—you’re too busy to improve anything. Improving anything will slow you down even more for a short term. It gets worse before it starts getting better. This is the hardest part of leadership: confidently nurturing the team through this transition. A coach helps. Upper management support helps even more.
Here are the trade offs you can make:
Don’t rewrite the entire application. Only refactor what is on the critical path that enables new features the team adds.
Minimise amount of tests written at first. Any test written should be of high value to company and product operations. Test important formulas and business rules, invariants and transactional guarantees. Don’t test weird edge cases like nullable fields and minus infinity.
Don’t speculate. Focus on the challenges and improvements at hand. Today. This week. Improve on what was hard yesterday. Minimise your timeframe of decisions. Anything else in a large codebase will quickly lead to overwhelm.
Treat the codebase as append-only. Try not to touch old untested functionality. With any new feature, follow the rules of branch by abstraction. Copy the old functionality, introduces a minimal feature-toggle to induce the split. Then refactor the new copy while leaving the old intact. Sandi Metz presents this style of refactoring very diligently in her talks.
Be candid and support the team.
If this is all overwhelming, worry not! I’ll be covering them in detail on our live streams end of this month as we focus on 4 weeks of Refactoring. For now you can read more on branch by abstraction and Sandi Metz below:
Be okay with coding mistakes, place attention on naming tests and new types
No magic in tests. No magic string, no magic numbers, no test structs that look “real”. No primitive obsession. This is important in production code, it is even more important in test code. You don’t want the next developer looking at a -1 try to figure out if that numbers has significance or if it was chosen because it is smaller than 20.
Naming well is a skill that is enabled by having clear product understanding. Your teams’ engineers need to speak the non-technical jargon of your business. This language is the strongest quality element that you can introduce in tests. Forget Gherkin. Forget BDD-style “frameworks”. Set incentives for the team to learn the language of the business and the products they are building—or maintaining.
The outcome is worth it
In the end, it’s hard to quantify productivity. It won’t appear on your CFO’s balance sheet immediately. But you’ll notice positive impact on:
Your team members’ confidence levels
Increased job satisfaction
Higher retention rate
Willingness to take and own risks
Reporting on their mistakes and learning from them
Making cycle times shorter and testing easier
Dealing with less failed launches, demos and releases
Lowered release anxiety
No more old-school 2000's cowboy engineering
No more overbooked calendars and roadmaps