Software development is a field that isn’t short on debates. But if I were hard-pressed to pick the most heated one, that would be the “refactor or rewrite” dispute. As a quick Google search can show you, there are as many opinions as there are software developers, so coming to an understanding is something close to a utopia.
Yet, software engineering teams find themselves before this choice more often than not, so it’s not uncommon for people to turn to those opinions in search of help. However, with the points of view being so varied, doing that ends up feeling like a leap of faith.
I (or anyone else, for that matter) can’t provide you a straightforward answer because there isn’t one. As it happens with many of the things in software development, it all depends on several factors that are specific to each situation. In other words, there are no general rules about whether you should refactor or rewrite your code – even when many experts or seasoned developers are claiming that one or the other is the best course of action.
In my opinion, it’s better to develop a critical mindset to approach any given project that might lend itself to refactors or rewrites. Armed with it, you can assess any scenario you find in the wild and define the best way to go. Read on to discover which things you need to keep in mind. But first, let’s make sure we’re on the same page.
Refactor And Rewrite
Criteria | Refactor Code | Rewrite Code |
---|---|---|
Main Role | Improve the design of existing code without changing its external behavior | Replace existing code with a new version that provides the same functionality |
Key Tasks | Code clean-up, optimization, removal of redundancy, improving readability | Starting from scratch, designing, coding, and testing |
Required Skills | Understanding of codebase, good knowledge of the programming language, refactoring techniques | Strong knowledge of the programming language, software design principles |
Time Consumption | Usually less time-consuming, done incrementally | More time-consuming, the entire codebase has to be rewritten |
Risk | Lower risk, as changes are small and incremental | Higher risk, new code may introduce new bugs |
Cost | Generally lower, as it doesn’t require a complete rewrite | Higher, as it requires complete redevelopment |
Existing Bugs | Can help identify and fix some existing bugs | Existing bugs may be eliminated, but new ones might be introduced |
Code Understanding | Increases understanding of the codebase by developers | Might improve or decrease understanding, depending on code complexity |
Impact on Functionality | Doesn’t add new features, focuses on improving existing code | May add new features and enhancements along with rewriting existing code |
Testing | Requires testing, but usually less extensive due to small, incremental changes | Requires thorough testing of all functionalities |
Best for | Codebases that need minor improvements or have maintainability issues | Codebases that are hard to maintain, understand, or are poorly structured |
Outcome | Improved code quality, maintainability, potentially better performance | New codebase, potentially with better structure, performance, and new features |
One of the most common issues you’ll find with the articles tackling this debate is that their authors don’t usually clarify what they mean by refactor and rewrite. Maybe that’s because they believe that developers know what they are talking about. While that might be true (any developer knows about these practices, regardless of their experience), the thing is that there’s no universal definition of them.
So, to avoid any confusion, I’ll let you know what I think of them. It might differ from your definition, and that’s ok. I’m not trying to convince you about using these definitions. It’s mainly to clarify what I’ll be talking about when I refer to both of them later on.
I’m more of the Martin Fowler school when it comes to refactoring. That means that, whenever I talk about refactoring, I refer to changing the design of something without impacting its behavior. It’s about retouching the code to increase its quality while the software stays the same. Thus, the result looks the same but offers better performance, security, integrates better with newer technologies, and is more scalable, among other things.
A rewrite, on the other hand, it’s scratching off all the existing code and starting from zero to get to the same place (or even a better place). This means understanding the software as it is and recreating it via a new code. You could say that this is the “nuclear option” in that you get rid of what you have to provide a better alternative.
In general, developers love to rewrite things. There are several reasons why: it’s easier to start from scratch, you don’t have to worry about things breaking because you’re tweaking specific chunks of code, you can create a better product – you can even write better documentation for it while you’re rewriting it! Yet, believing that rewrite is superior because of those things means voluntarily ignoring other crucial aspects that come with the decision of rewriting in the first place.
Let’s see some of those.
Beyond Rewriting Siren’s Song
All of the reasons I’ve mentioned above are the first things that come to mind when software engineers are in front of an underperforming, old piece of software. It all ends up in the same way – engineers wanting to rewrite to start with a clean slate. However, developers are rarely the sole deciders on the fate of a software. In fact, some considerations are often more significant when deciding the way to go.
Of those, business drivers are at the top of the list. A rewrite (especially of complex software) can be a time-consuming task that can end up costing a lot of money for no real advantage from a business standpoint. Maybe rewriting the software uses up too many resources that prevent the team from focusing on more valuable tasks. Maybe the rewritten software doesn’t have enough ROI to justify the rewriting in the first place. In that way, rewrites can often be against business objectives, a major reason why they are rejected.
This leads us to the associated risks that come with rewriting. Perhaps rewriting the whole software can make a business impact but, in the time it takes to get completed, it allows for the competition to release a similar product to the market more quickly. There might be new competitors in the market once you complete the rewrite. Or maybe the money you invest in the rewrite prevents you from investing in a more strategic asset (be it technological or not).
Finally, there are certain aspects related directly to the software itself. Maybe the software you want to rewrite isn’t easily maintainable, but it’s resilient, offers a good deal of security, and has an excellent performance. If you aren’t entirely sure you can replicate all of that, rewriting it might end up backfiring. You can finish with a more easily maintainable software that isn’t as resilient, secure, or that performs worse than what you had before.
Introducing these considerations doesn’t mean that rewriting is a bad option (I’m trying to avoid the extremes at all costs). Instead, they provide necessary information to take into account when making a decision. Thus, they help paint a more realistic picture of what rewriting might mean.
Designing A Critical Approach
Since rewriting is what most software engineers consider when in the need of improving an existing system, it’s essential to start there. Considering the business drivers and the associated risks can be a great way to decide whether a rewrite is right for you. In plain terms, you need to define is a rewrite is a viable option for you before considering the technical aspects of the whole thing.
There’s one tricky thing about doing that, though. You might be considering a rewrite or a refactor because you have too much technical debt, or your software is close to obsolete. In such a scenario, both options are risky. If you stay the same simply because things work, you risk that your software won’t hold up for long, will be impossible to maintain in the near future, or won’t be scalable. If you rewrite it, you might not get the same capabilities.
This means that there isn’t a risk-free option – consider yours and be aware of them but don’t base your decision only in risks (or the absence of them), simply because there’s no scenario where you will be free of them.
So, the best way to look at it, in my opinion, is as follows:
- Consider the business implications of either option. What are their potential consequences?
- Analyze and assess the risks. One of the options might be riskier than the other, but not necessarily. Do you understand what it means to go one way or the other?
- Outline the reasons why you want to refactor or rewrite. What are you trying to accomplish?
- Identify how far your current software is from those goals. Make it as detailed as possible.
- Define a clear path that takes you from where you are to where you want to be. Is it even possible? Maybe there are incompatibilities with new technologies or there aren’t any paths to remodel outdated software into modern hardware.
- Break down both processes following that path. What is involved in refactoring the code? And which are the ones included in a rewrite? This is a key part of the assessment, so don’t try to express the process in how much time you think both processes will take. Instead, try to think of tasks and their complexities, as that will better allow you to compare both options.
- Compare the paths in front of you. Maybe you see that, while refactoring might take more steps, those steps are easier than the fewer included in the rewrite. Or maybe it becomes clear that refactoring is an insurmountable endeavor because of the many tasks it implies.
- With a clearer view of both paths, reassess your business drivers and your risks. After factoring in all these considerations, you’ll be better prepared to make a final decision.
The refactor vs. rewrite debate is a sterile one when it comes to daily operations in that it often deviates into the theoretical terrain. As no two projects are the same, it’s vital to go over these practical steps to better approach the subject and define whether one road is better.
One final recommendation on my part. Even if you see that an approach presents better results for your projects, resist the temptation to fall on that option as a default, as you might come across a specific project that may benefit from the other approach. It might seem tiresome to do this analysis every time you work with old code, but I guarantee you that it’s the only way you can get to the best outcomes for your projects.