Refactoring or Rewriting Code?

Software development is a field that is not without controversy. But if we had to choose the most contentious one, it would be the debate of "refactor or rewrite." As a quick Google search shows, there are as many opinions as there are software developers, so reaching a consensus is something close to a utopia.

Nevertheless, software development teams often find themselves facing this choice, so people frequently turn to these opinions for help. However, given the diversity of viewpoints, this becomes akin to a leap of faith.

We cannot give a definitive answer because there isn't one. Like many things in software development, it all depends on several factors specific to each situation. In other words, there are no general rules about whether refactoring or rewriting code is better—even if many experts or experienced developers claim that one way is better than the other.

In our view, it's better to develop critical thinking to approach any project that may undergo refactoring or rewriting. Armed with it, you can evaluate any scenario that comes your way and determine the best course of action. Read on to learn what to keep in mind. But first, let's make sure we're on the same page.

Criteria
Code Refactoring Rewrite Code
Primary Role Improving the design of existing code without changing its external behavior Replacing existing code with a new version that provides the same functionality
Primary Tasks Cleaning code, optimization, removing redundancy, improving readability Starting from scratch, designing, coding, and testing
Required Skills
Understanding of the codebase, good knowledge of the programming language, refactoring techniques Strong knowledge of the programming language, software design principles
Time Consumption Usually less labor-intensive, done incrementally More labor-intensive, entire codebase must be rewritten
Risk Low risk, since changes are small and incremental Higher risk, as new bugs may appear in the new code
Cost Generally lower, since it does not require full code rewrite Higher, as it requires a complete overhaul
Existing Bugs
Can help identify and fix some existing bugs Existing bugs can be fixed, but new ones may appear
Code Understanding Improves developers' understanding of the codebase Can improve or worsen understanding, depending on code complexity
Impact on Functionality Does not add new features, focuses on improving existing code Can add new features and improvements along with rewriting existing code
Testing
Testing required, but generally less extensive due to small incremental changes Requires thorough testing of all functionality
Best Suited For Codebases needing minor improvements or having maintainability issues Codebases that are difficult to maintain, understand, or are poorly structured
Result Improved code quality, better maintainability, potentially higher performance New codebase, potentially with improved structure, performance, and new features

One of the most common issues in articles about this discussion is that their authors usually do not specify what they mean by refactoring and rewriting. Perhaps this is because they assume developers know what they are talking about. That may be true (any developer knows about these practices regardless of experience), but the fact is there is no universal definition for them.

Therefore, to avoid confusion, I will share with you what we think about them. It may differ from your definition, and that is fine. We are not trying to convince you to use these definitions. This is mainly to clarify what I will be referring to when I discuss both definitions later.

When it comes to refactoring, we lean more toward Martin Fowler's school of thought. This means that whenever we talk about refactoring, we mean changing the design of something without affecting its behavior. It's about polishing the code to improve its quality while the software remains the same. Thus, the result looks the same but has better performance, security, integrates better with new technologies, scales better, etc.

On the other hand, rewriting is deleting all existing code and starting from scratch to achieve the same (or even better) result. It means understanding the software in its current state and recreating it with new code. You could say it is the "nuclear option" because you get rid of what you have to offer a better alternative.

In general, developers love to rewrite. There are several reasons for this: it is easier to start from scratch, no need to worry about breaking something by tweaking individual pieces of code, you can create a higher quality product—you can even write better documentation while you're at it! However, thinking that rewriting is better because of these things means willingly ignoring other important aspects that are inherently tied to the decision to rewrite.

Let's look at some of them.

Beyond the Siren Song of Rewriting

All the reasons listed above are the first things that come to software engineers' minds when they encounter a broken, old software product. It always ends the same way—the engineers want to rewrite the program to start with a clean slate. However, developers are rarely the sole deciders of the software's fate. In fact, some considerations often prove more significant in the decision-making process.

Among these, business factors come first. Rewriting (especially complex programs) can take a lot of time and ultimately cost a pretty penny without providing real business value. Perhaps too many resources are spent on rewriting the software, preventing the team from focusing on more important tasks. Maybe the rewritten software does not have sufficient ROI to justify the rewrite. Thus, rewriting often conflicts with business goals, which is a primary reason for avoiding it.

This brings us to the associated risks of rewriting. Perhaps rewriting the entire software could benefit the business, but during the time it takes to complete, it could allow competitors to bring a similar product to market faster. Maybe new competitors will emerge after the rewrite is finished. Or perhaps the money invested in the rewrite will prevent you from investing in a more strategic asset (technological or otherwise).

Finally, there are some aspects directly related to the software itself. Perhaps the software you want to rewrite is not so easy to maintain, but it is resistant to external influences, provides a high degree of security, and has excellent performance. If you are not sure you can replicate all of this, rewriting may end in failure. Ultimately, you may get software that is easier to maintain but not as resilient, secure, or performant as what was there before. Raising these considerations does not mean that rewriting is a bad option. On the contrary, they provide necessary information to consider when making a decision. Thus, they help paint a more realistic picture of what rewriting might entail.

Developing a Critical Approach

Since rewriting is something most software developers consider when needing to improve an existing system, it's best to start there. Examining business reasons and associated risks can be an excellent way to decide if rewriting is right for you. Simply put, before considering technical aspects, you need to determine if a rewrite is a viable option for you. However, there is one complication with this. You might be considering rewriting or refactoring because you have too much technical debt or your software is close to becoming obsolete. In that case, both options are risky. If you leave things as they are just because they work, you risk your software not lasting long, being unsupportable in the near future, or not being scalable. If you rewrite it, you might not achieve the same capabilities. This means there is no risk-free option. Consider it and be aware of it, but don't base your decision solely on risks (or lack thereof) simply because there is no scenario where you are free from them. Therefore, in our view, the best way to look at it is as follows:
  • Consider the business consequences of either option. What are their potential outcomes?
  • Analyze and assess the risks. One option may be riskier than the other, but not necessarily. Do you understand what each option entails?
  • Outline the reasons you want to refactor or rewrite. What do you want to achieve?
  • Determine how far your current software is from these goals. Do this in as much detail as possible.
  • Define a clear path that will take you from the current state to the desired one. Is it even possible? Perhaps there is incompatibility with new technologies or no way to adapt legacy software to modern hardware.
  • Break down both processes along this path. What does refactoring the code entail? And what does rewriting entail? This is a key part of the evaluation, so don't try to express the process in terms of how long you think both processes will take. Instead, try to envision the tasks and their complexity, as this will allow you to better compare both options.
  • Compare the paths before you. You might see that while refactoring may require more steps, those steps are simpler than those involved in rewriting. Or it may become clear that refactoring is an insurmountable task due to the many tasks involved.
Once you have a clearer picture of all the paths, reassess the business drivers and risks. With all these considerations in mind, you will be better prepared to make a final decision.
The debate between refactoring and rewriting is sterile when it comes to daily work, as it often shifts to a theoretical plane. Since no two projects are the same, it is very important to consider these practical steps to better approach the question and determine which path is best.

Even if you see that one approach gives better results for your projects, don't be tempted to default to it, because on a specific project you might face a different approach. It may seem tedious to run this analysis every time you work with legacy code, but I guarantee that this is the only way to achieve the best results for your projects.