Every single software has some “legacy”, somewhere. You (or someone else) did things differently to what you believe is best to do now. Refactoring is the art of increasing the maintainability of a piece of code.
No refactoring to do?
If you don’t have any refactoring to do, it’s very likely that you are either over-spending (i.e. you spend far too much time on quality for the sake of it) or you don’t realise that you could be much faster.
“Technical debt” is complete part of the development process and especially in fast-moving environments such as startups where the focus is more much on trying things. As nicely stated in this article:
It’s called technical debt, because it’s like taking out a loan. You can accomplish more today than you normally could, but you end up paying a higher cost later.
“Global” refactoring (don’t do this)
Global refactoring means you will replace an entire layer of your software. Let me give you a few examples:
- Replace the front-end framework on all pages. Let’s imagine replace Bootstrap by Tachyons.
- Replace the Redux reducers so that they don’t create duplicates. There are very good reasons of using libraries like Galette (let’s say its store module in this example)
These examples are good ideas. It might even be needed to do what they describe. The approach (replace) is wrong, though. Doing so (replacing the existent) will require you to change a huge amount of things at the same time and you can be pretty confident that you’ll face the following issues:
- The refactoring pull-request takes ages because it is too big. Nobody is excited to read thousands of lines of code.
- So many merge conflicts because you can’t stop the rest of the team working while you’re spending days changing all the templates or usages of the Redux store everywhere. And this will be annoying.
- Introduce bugs. Very much related to the previous two points, huge huge refactoring often comes with regressions because you didn’t have every side-effect in mind.
To refactor effectively, you need to refactor bit by bit, per region.
Do it, per “region”, not per layer. A region is one or a set of feature, while a layer is for example the “front-end” or the “validation” or the “storage”, etc… You need to refactor entirely (i.e. all the things you believe needs to be refactored) on one single region of your code.
The interests are multiple:
- You will identify mistakes earlier. Regardless of the amount of time you’ve spent on the code base, it is likely that while planning the refactoring you forgot something. And this might force you to redesign part or the entirety of your refactoring place. It’s much better to identity it early.
- You will set a precedence for refactoring. The first to refactor usually is the most confident developer, because it’s really hard work. But you need to bring the other team members up to speed and there’s nothing better than having them contribute to the refactoring. With this approach, other team members can go and apply the same patterns that you’ve done on other “regions” of the codebase.
How do I chose the region? The point of refactoring is to ease the maintenance and usually to increase the quality (from a user/client perspective). Go and refactor the most painful region of your code.
Really, refactor a small region of your code, well. Ship this regional refactoring as fast as possible. And iterate again. :)