How to find time for refactoring
Do you find the codebase you work with an unreadable mess and do you want to make it better? Do you keep proposing to your manager or product owner to include refactoring tasks in the next sprint, iteration, etc., but you never get heard?
Don’t search further how to convince them, you don’t have to! Let’s discuss here what to do!
Should you really refactor?
First of all, why do you want to refactor? Is it simply because you don’t like the style it was written in? Or is it because you find it difficult to understand the code? Maybe it’s difficult to change it?
“Code refactoring is the process of restructuring existing source code—changing the factoring—without changing its external behavior. Refactoring is intended to improve the design, structure, and/or implementation of the software (its non-functional attributes), while preserving its functionality.” - Wikipedia
If you just don’t like its style or you find it old-school, you should probably not change it. As the old adage goes, if it’s not broken, don’t touch it…. If the code hasn’t changed in years, leave it alone, it probably won’t change anytime soon. On the other hand, code that is changed once tends to be changed several times, so it’s worth concentrating on those areas.
The only valid reason to still change unchanged code, in my opinion, is to modernize code in a specific way. But before you close the tab and run to modernize, wait a second and read on. I don’t mean that you should move old, unchanged modules to nice, modern architecture and introduce extensive changes!
On the other hand, if you’re introducing a new language or standard library feature, such as concepts in C++20 and you’re replacing older, less readable constructs such as std::enable_if, then yes, just go ahead and introduce the same changes everywhere systematically - unless there are way too many of them. In any case, don’t start introducing structural changes on a whim.
If there is an area in the codebase you often have to go through and it’s difficult to understand it, yet it doesn’t change, then you probably feel like you have to refactor it. If it’s well-tested, maybe you could, but I still think that you probably shouldn’t. On the other hand, you’d help everyone if you documented the code once you understood it so that you or someone else doesn’t have to restart the mental process the next time.
But if the code needs to be changed and is difficult to understand, test, and/or change, then it’s probably time to refactor!
But…
When to refactor?
If you follow the three steps of Test Driven Development (TDD), you know that refactoring comes at the last step
Write a test for the next bit of functionality you want to add.
Write the functional code until the test passes.
Refactor both new and old code to make it well structured.
You might think that first, you complete your task - a.k.a. you fix a bug or introduce a new feature - and then you’ll take some time to improve the surrounding code. Maybe before sharing with the others that you finished your task…
That’s not bad, but not the best approach either.
Remember that the three steps of TDD are connected circularly and assume you start with a clean slate. In other words, you don’t start with messy code.
But there is a fair chance that you don’t start with something clean, but rather with a big bowl of spaghetti which hopefully passes all the tests in the pipeline. If so, you are before step 1 and after step 2. You’re right, that’s step 3.
Start with refactoring!
If it’s difficult to introduce your change because the surrounding code is messy and difficult to change and test, then first make it better, make it simpler! Why would you do it the other way around?
But how much time to spend on refactoring?
In an online course by Kate Gregory, I learned a great strategy. Let me share its essence.
Most probably there is an estimation belonging to your task. Let’s say it’s 2 weeks. Take half of it - in our imaginary case, that’s a week - and spend it on refactoring. Aim to make it easier to introduce the actual change.
What are the possible outcomes?
You succeed by making the code easier to understand and maintain and introduce changes faster. So you spend some time on refactoring, but then you introduce the change faster. Overall, you would spend around the same amount of time as estimated, yet you had a better impact on the codebase.
The other outcome is failure. You might fail to make the code better, refactoring doesn’t turn out well. At least you timeboxed the refactoring step and you started implementing the feature in the original codebase after having spent 50% of the time. It means that you’ll spend about 50% more time on the task than it was allocated to it. It’s not ideal, but in most cases, it’s not a big deal. Even without trying to refactor, that is often the case and some overrun won’t be surprising to anyone. At least you tried to do something useful and you probably already got more familiar with the codebase and you will have more ideas the next time.
How to communicate it?
In brief, just don’t say anything.
If you work in an environment where what you read until now is not embraced, where product or engineering management doesn’t foster an environment where maintainable code is one of the goals, probably you shouldn’t brag about having spent time on refactoring.
Just do it.
Do it and make it a habit.
It will have a compounding effect on the code base. This means that you won’t immediately see how great the codebase has just become, but sooner than later, you and other engineers will see the effects.
While you shouldn’t discuss this technique with your management if at the coffee area some other engineers ask you how you manage to refactor code, share this technique with them.
Conclusion
Refactoring isn’t something you need permission for—it’s a skilful, strategic habit that makes your daily work easier and improves the maintainability of the codebase. Instead of waiting for approval, build refactoring into your natural workflow. Start by making small, impactful changes when you touch messy code. Timebox your efforts to avoid getting lost in endless and meaningless gold-plating. And most importantly, keep your focus on writing maintainable, readable, and adaptable code.
Over time, these incremental improvements will compound, making future development smoother and reducing technical debt without the need for massive, risky rewrites. Don’t wait, start refactoring today!