I hear "refactor" used when developers mean port or rewrite far too often. It's important to use specific terminology here because each of these carries different risks and does different things for your application.
- Risk: Low
- Benefit: Readability, manipulability
As the most effective tool for creating a more understandable code base, refactors are low-risk and high reward. A refactor is taking some portion of the code and, without changing functionality, improving the code in some way. The area of improvement is most often readability or speed.
We understand that when we write code the first time, it won't be laid out well. Just like writing a book, or painting a wall, you're going to have to go over the code multiple times in order to get a well-organized code base.
Make refactoring part of your routine. The better your code base is, the easier it will be to add new features. Reduce the risk of refactoring with sufficient testing. If you're using unit tests, make sure you write for the very outside like Ian Cooper mentions in this talk.
- Risk: Medium
- Benefit: Tech debt decrease
Porting code is taking code from one language, framework, technology and changing (or upgrading) it. In a port, you leave the code as close to the original as possible while following new syntax rules.
Make sure you're doing a port for the right reason. Ports are more exciting than refactors, but don't produce the same results. Ports decrease tech debt. That could mean less security liabilities or better abstractions, but 90% of the time the code is the same or harder to work with.
Be disciplined with your ports. If you're anything like me, you'll want to perform a port at least once a month. Before you do, make sure the area of the application you're going to port is easy to read. If it's not, refactor your code first so that the port is easy and less risky.
- Risk: Extreme
- Benefit: ...
"A complex system that works is invariably found to have evolved from a simple system that worked. A complex system designed from scratch never works and cannot be patched up to make it work. You have to start over with a working simple system."
- John Gall
Rewrites are by far the trickiest to pull off successfully. They can be good when the portion of the system you're trying to rewrite is small enough that you know exactly how it's supposed to act and the code is 10x more complicated than it's responsibilities. Rewrites differ from refactors because refactors take the existing code and improve it, while rewrites throw away the old code before starting on the new.
Instead of rewriting code, learn better refactoring techniques. Most of the time, you can make small improvements to the code until it is in a readable-enough spot to make more significant changes safely. If you're dead set on a rewrite, make sure you have sufficient testing.
Go research code smells. Practice refactoring every day. Whenever you can, leave the code base better than you found it.