The False Gods of Refactoring
A while ago I worked on just another task, and while being constantly overwhelmed with the amount of technical debt the project carried, I overstepped the line again and committed to a "quick refactoring". It landed so destructively, that I've told myself "Damn, never again", and decided to reflect on this a bit.
Most of the time I find myself falling into the same vicious cycle, that makes me end up ass deep in refactoring.
- A new task arrives, and the initial assessment shows there are two possibilities:
- Do it quick and dirty, but rather fast. Basically add some more garbage on top of already existing garbage and move on.
- Take some technical debt away and make our project a better place.
- "Ah, finally, a chance to nail it. Challenge fu**ing accepted!" - say I, and commit to the second option.
- I manage to do some part of it, endorphins spike, butterflies flutter, unicorns nibble the grass.
- Three days after, as the situation unfolds and the PR goes over 1k lines, the first seeds of doubt start to arise.
- One week in, during dailies I keep repeating the same mantra "It's going, it's on track.". My engineering manager expresses concerns, my teammates too.
- Two weeks in, I feel depressed and cursing myself for committing to the thing, questioning my sanity and asking why the hell do I even need this. But it's too late to turn back or wrap it up half-done, so I am pushing through.
- To finish it I sacrifice a couple of weekends and time that could have been otherwise spent with my family or on my private agenda, I get it done through misery and nervous fatigue. The PR has hard time being reviewed, but eventually, after N sessions of conflict resolution it gets finally merged.
- I breathe out and expect gratitude from my team and my manager, but there is none. No one even noticed something has changed.
- I end up mentally broke and burned out, questioning the very essence of existence of myself and the world around...
- Till the next time!
That was an example of unhealthy refactoring gone savage. Clearly there are some psychological aspect to letting myself fall into the same trap again and again. It's totally worth exploring the reasons for that, to pray to the False Gods of Refactoring no more.
After giving it some thought I realised, that it turns out I have my personal reasons for the thing (yours can be different though):
- To prove myself. I suffered from this for quite a while, due to sense of underappreciation, and also because of certain psychological traumas.
- To stick my banner in. When I can't contribute in a meaningful, weighted way, a "bright" idea may come to my mind - to improve something and call it "My contribution".
- To raise above my colleagues. Yeh, sometimes it's not without that. "You, simps, have no idea how to make it right. I know better, so let me show you how it's done.
- To make the code aesthetically beautiful, pleasing the eye. Engineering is craftsmanship, so sometimes I can spend awhile slacking over beautifullness of the code I just wrote. "Ah, look at that indentation. So readable now!"
To avoid be known as "the guy who always refactors", make sure at the refactoring you are planning to pull off checks at least one of the boxes:
- ✅ Improves performance.
- ✅ Improves code readability & maintainability.
- ✅ Unlocks opportunities to do XYZ.
- ✅ Reduces code complexity (instead of bloating it).
If nothing checks out, then why would you even need to refactor something?
Refactoring looks like a snack at the beginning, a cheap source of endorphins, because the brain is tricked into thinking it's doing something meaningful, while it's not. Refactoring is never as easy as it seems, and if pulled till the bitter end, it turns into a massive energy sink.
Don't snack, focus on the most impactful tasks instead.
Tell me: What is better: to do a task that lets the company save 150k a month, or do a task that reduces the codebase size by 2%? The answer is obvious.
Refactoring usually won't let you earn many scores for promotion, because in 99% of cases it doesn't let to save any money and also doesn't produce impact visible to stakeholders.
There must be a strategy in place, for addressing technical debt without too much struggle. For example, during the quarterly planning we can say, that 10% of work time can be reserved for cleaning up technical debt. Then you create tickets, estimate them and plan for the sprint. Bottom line, it doesn't have to be chaotic and happen from time to time, there are always ways to have it done in a systematic way.
All members of the team must be onboard with the upcoming change. Ideally, there must be an ADR in place, written down and accepted by each team member. Forcing new changes generally speaking won't do much good even if you manage to pull it though, as people won't stick to the agreements and continue writing new code in the old way, either because they secretly rebel against the change, or they didn't understand it, or they simply don't care and see no value.
Having a written ADR also helps, because it serves as a binding document, should someone start deviating from the prior agreements.
When you spot questionable code, don't rush into accusing its authors right away. You don't know the reasons why this code was written this way. Maybe the resources were stretched thin, or people were delivering under tight deadline, or maybe not all the requirements were in place, and the team had to improvise.
The code, though imperfect, could be someone's hard-won delivery, and you, sort of, don't have moral right to disregard it just like that. The best way would be to contact the author (if they still in the company) and 1) ask for reasoning, 2) let them know about the upcoming changes, 3) try to plan for improvements, together.
Sometimes small changes in the code subsequently lead to greater changes, for example when you suddenly realise the project does not compile and additional work has to be done. Then the changes start to accumulate like a snowball rolling downhill, and you end up with a 2k lines PR before you know it.
It's reasonable to understand where your limits are. Be wise, and tell yourself and others "Okay, this is where I draw the line".
Sometimes people leave review comments that could persuade you to re-think your approach in the direction of greater change. Well, know how to hold your ground. People ask questions and raise concerns, this is normal, but don't let others lure you into making too drastic changes, far beyond reasonable amount.
If you are new to the team, earn trust by making impactful tasks first. Then, after a while, the team will start listening to your ideas little by little.
Don't let the project rot either. Promptly spot areas that could use some improvement, propose the changes and get them aligned, get the buy-in. If the change takes less than 1 hour, you can probably propose this as part of a feature PR, but be ready for pushbacks.
Sergei Gannochenko
Golang, React, TypeScript, Docker, AWS, Jamstack.
19+ years in dev.