We all strive to design elegant solutions and write beautiful, easy-to-understand code. We love easy, safe deploys to production systems that scale. And yes, nothing screams confidence more than 100% automated test coverage.
And yet, more important than any of these is making progress quickly.
- Zen of Python
It makes sense to invest extra time on perfection only if it'll decrease the technical debt time by at least that much.
- Don't spend 10 hours refactoring bad code that will save the development team 2 hours in the future.
- DEFINITELY spend 10 hours writing unit tests that will save the development team 20 hours of debugging and fixing in the future.
- Chrstian Mérat
Don't build today what you don't need.
Today's designs should anticipate tomorrow's needs, but without actually building them.
Get it right the first time.
Using static analysis tools, great Pull Requests, and knowledge of design patterns, try to minimize the amount of technical debt that you're creating in the first place. This will prevent refactoring headaches in the future.
That being said, don't let The Perfect PR get in the way of progress!
Refactor incrementally over time.
Avoid refactoring large swaths of tightly coupled code in one sprint. Your goal should be to break off chunks and minimize the scope of refactoring, and make progress on it over time.
Even big, messy collections of code can be decomposed and refactored gradually over time.
Refactoring Guru has great tips and recipes for refactoring.
The nagging impulse to fix bad code is not a good reason to refactor.
If your engineering manager or business stakeholder is pushing hard for feature delivery and resistant to reducing technical debt, then learn to negotiate in ways that are persuasive to business stakeholders.
"It'll work better" is not persuasive. "It'll increase our development velocity by 15% over the next 3 sprints" is persuasive.