An age-old struggle between product and engineering teams is to find the balance between building new features and addressing technical debt that piles up over time from old code. Constantly addressing technical debt means you aren’t shipping new features fast enough, which can be a problem for the business side of things. However, completely ignoring technical debt and constantly building new features will lead to a much more complicated and time-consuming refactor down the road (the refactor is always inevitable).
What is technical debt?
Technical debt is the term that refers to parts of the codebase that need to be refactored to meet the standards of “best practice”. It can be incurred in multiple ways, the most common being that the team needed to expedite delivery of the feature and did not have the luxury of following the best practice approach at the time of its initial development.
Whenever I have to think to understand what the code is doing, I ask myself if I can refactor the code to make that understanding more immediately apparent. – Martin Fowler, Refactoring: Improving the Design of Existing Code.
Technical debt can also accrue automatically over time as previous versions of libraries and frameworks are deprecated and need to be updated. Updating these libraries to the latest version might sound simple, but they can introduce breaking changes, which requires refactoring the code to accommodate for new syntax or design patterns that may be introduced. It requires a lot of regression testing to ensure everything is working as intended after the upgrade.
When should you refactor?
Ideally, you will want to factor in a percentage of your time (~10–15%) during each sprint to address technical debt tickets that may be piling up in the backlog. This way, you can chip away at the tech debt without sacrificing the business goals of the product. However, if this practice isn’t followed from the start, and the product has reached a point where a major refactor of a component that has several dependencies is required, you may end up needing to dedicate an entire sprint (or two) to the refactor. This is quite disruptive, especially if you have a live product with customers. Ideally, you don’t want to find yourself in this scenario, but if you do, it is better to rip off this band-aid sooner rather than later. The more you delay a major refactor, the more difficult it becomes down the road.
That being said, it is important to pick and choose your timing for such a major decision. You want to pick a moment where the new features on the roadmap are not mission-critical (nice to have features, instead of must-haves) or an immediate need for your existing customer base. If the situation arises where a few weeks of not working on new features will not lead to churn, take advantage of it and do that major refactor that you’ve been putting off for months (years sometimes).
When should you not refactor?
All the above being said it is also important to determine whether the refactor is absolutely necessary, or if it’s something that is extraneous. One of the common tropes is that developers love to play with new toys, and refactoring the app for the sake of being on the latest version is simply not a good enough reason.
The most common example of this that we run into is Javascript vs. Typescript. A majority of web applications in production were built using Javascript before Typescript become all the rage. Now, Typescript has become the hot new toy – and with good reason. It provides several benefits and is a fantastic option moving forward. However, refactoring a massive Javascript codebase to Typescript is a huge undertaking, which the product may not even need. Furthermore, it will add a learning curve for the existing development team, slowing down their velocity for the next several sprints at least.
It is important to evaluate the pros and cons of each refactoring decision and make a sound decision based on the value that is being added for the tradeoff that is being considered.
If the refactoring is more along the lines of upgrading the framework’s version from 5.x to the latest version 9.x due to the sheer number of security fixes and performance updates that have occurred in the last 5 years since the product was first built, then you have a good case to refactor as soon as possible.
Need to build an enterprise grade product?
We replace old enterprise implementations with the latest technology, custom built for better scale, security, usability and value.
Conclusion
The decision to refactor a codebase is one that will require a judgment call from people who have intimate knowledge about the product’s roadmap, near-term and long-term business goals, technical debt backlog, its impact matrix, the current traffic, and performance of the app. Evaluating all these factors and more will lead to the ultimate decision, which may require buy-in from key stakeholders in the business, product, and engineering teams.