As apps evolve and scale over time—the case for refactoring large, unwieldy, and clunky blocks of code gets stronger and stronger by the day. Functions added to handle edge cases and errors, classes bolted on to meet changes to an API—these “fixes” add up to reach a tipping point. Sooner or later, the decision to refactor will be inevitable.
Reshaping your existing codebase into a smaller and more efficient form-factor, however, isn’t as easy a decision as it sounds. Owning a clunky codebase that works is infinitely better than having a clean solution that doesn’t.
Yet, monolithic blocks of unmaintainable software do more than just slow down your systems and teams. Clunky applications, even when they’re performing well, limit your organisation’s ability to scale or respond to issues as needed. They prevent forward progress and hamper your organisation in ways that are hard to define for companies that haven’t experienced inheriting a legacy codebase before.
In our guide to refactoring web apps, we take a look at when to refactor existing applications to maintain good design practices and the factors that should go into understanding the code you have.
Understanding Web Apps
When taking on a legacy project, technical teams are inevitably left with just a few choices available to tackle its challenges.
- Leave the software as-is. If a bad solution serves its purpose then it’s not really a bad solution at all, right? Doing nothing is often exceptionally limiting and leaves technical debt to be paid with interest on another day. Yet, it does leave services as functional as they were before and prevent teams from getting bogged down in re-inventing the wheel
- Refactor existing code. Rather than throwing away a valuable codebase, teams may choose to restructure the project to create more modular and encapsulated components. This should leave existing code more performant and easier to maintain in future if done wisely
- Rewrite the codebase. A costly and time-consuming route, teams may find the existing code and its dependencies unable to be salvaged. The economic option may be to start again with new ideas and modern technologies to build a new solution
In most cases, you can make a strong argument for each of these three options. When it comes to web apps, working code has significant value and the temptation to leave your code as it is can be a strong one.
Improving App Design: Refactoring
The process of refactoring web apps can improve performance, create an interface to integrate third-party solutions, and allow for future upgrades and maintenance to be done with ease. Improvements are made by creating code that is more modular, encapsulated, and readable than the existing solution.
Just updating the libraries and dependencies of your codebase can go a long way to guarding against many potential issues.
Ideally, refactoring is already a part of the maintenance scheduled on your existing web apps. When approached as part of good app design rather than a one-off project, the process of refactoring web apps is far less costly and time-consuming for teams.
Good design practice involves a process of continual improvement, updating, and restructuring to extend and improve the lifetime of a web app.
Unfortunately, this isn’t the process many teams first think of when asked about refactoring a codebase. Most often, this is a process of taking a large, poor quality legacy app with strange and undiscovered dependencies and re-building it into something that wouldn’t look out of place in a modern tech stack.
The decision taken on whether or not to refactor in the first place, however, is one that doesn’t get enough attention.
Immediately jumping in to refactor simply because software is bulky, unwieldy, or even just ugly might not be the best solution. Working code has a lot of value. If an inherited solution is still doing the job it’s designed for then it’s rarely as bad as it looks. If it’s reasonably performant and reliable too then even better still. The advantage of functional web apps isn’t something you want to give up lightly.
Don’t dive in to refactor code until your i n-house or outsourced teams have had a chance to get familiar with the app’s design. By the time the decision is made to jump in and refactor, you should have a good idea of how it works, exactly what needs to be improved, and a clear plan of how you’re going to improve it.
When to Refactor an Existing Codebase
Four great reasons to justify jumping in to reorganise and rearrange your code to work better with your existing web apps include:
1. There Are Lots of Bugs and “quirks” in the Code
One of the easiest ways to create five new bugs in legacy code is to fix the one you just found. Without refactoring, maintenance can be risky and uncertain for teams.
The safest way to address these issues is to take the time to discover all the hidden dependencies, code repetition, side effects, and obsolete libraries that plague an ageing web app. Once teams understand a system, plans for its upgrade can be made much easier.
2. Updates Have Unintended Consequences
When you update features within an application and unrelated components break or change, your application is giving a clear signal that refactoring is both necessary and urgent.
Refactoring code to adhere to SOLID principles can be an investment well worth the time in creating dependable software more resilient to change. For teams, this investment pays off repeatedly in simplifying the process of applying updates and maintenance with a reassuringly strong foundation.
3. Repetitive Code
One of the biggest headaches for developers tackling legacy code is repetition throughout the app. A problem that can become especially common where multiple developers have worked in a project at various points in time—features can often be found implemented two or three times over.
The side effects that result from repetition are often strange and unpredictable. Changes taking hold in one area of an app while another component remains entirely unaffected is an exceptionally common and frustrating result.
Repetition within the codebase is a major indicator that refactoring is necessary for a cleaner app design.
4. Excessive Technical Debt
Much like monetary debt, the costs of technical debt compounds over time. Eventually, the price in performance or maintenance is going to reach a height that is simply too large to ignore.
Agile development is built around consistent refactoring during development to guard against growing technical debt. Unfortunately, legacy projects inherited into teams rarely have this measure built-in. The sooner you can tackle the issues plaguing your web app, the lower the cost of handling them to create a robust and reliable app design.
When Not to Refactor an Ageing App Design
1. Poor Understanding of the Code
To successfully refactor a large and complex app takes time and expertise to understand how the various components function and interact. In practice, a developer refactoring a web app is going to need to know the codebase almost as well as if they’d written it themselves.
When you jump in to refactor you should have an understanding of what needs to be fixed as a priority and what you’re going to do to address it.
2. Poor Code Coverage
When you make changes to an app, particularly one that is unreliable, you need to verify those changes do only what you think they should. Without good code coverage, your tests can’t verify your code and your developers could well be doing more harm than good.
When it comes to refactoring, test-driven development is a key driver of project success.
3. You Don’t Know What to Improve
When inheriting legacy code that looks like a mixed bag of solutions, it’s not always clear where to start. Developers often find themselves in a position of knowing improvements need to be made but unsure of where to make them.
Refactoring should only ever be tackled with a clear and obvious plan of what’s going to change and what’s going to remain the same for now. Without having this in place, developers are better off leaving the code as it is—provided it’s functioning to a reasonable standard.
4. You Need a Rapid Turnaround
If you need your code to be operating in a short period of time then it’s relatively safe to ignore refactoring for the time being. While this does build technical debt that will have to be paid later, working software with flaws is undoubtedly better than having no software at all.
If getting into the market, getting to a working prototype, or getting ahead of the competition is priority number one, then re-factoring can be postponed for a short time at least.
How to Refactor Code for Better App Design
When you jump into refactoring your web apps the first thing you should be thinking should be to test first and test often. Start by creating the tests for existing code that shows the system meets the requirements and functionality expected. Only once you have good code coverage can you begin to replace legacy code with modern solutions to meet these tests.
To prioritise the areas of the app that need to be replaced, identify the flaws and the data flows within your application. Improving web apps effectively should start by addressing the root problem from which several others might flow. By identifying how dependencies are related within the app, building encapsulated solutions in the future will be made much easier.
When making these changes, start small. Take discrete chunks of the codebase and refactor it with as little impact as possible. Great web app developers should be well-practised in this area. Create modular components that can take over small areas of the codebase and build from there. Ideally, small individual changes should have little outward impact yet result in a cleaner architecture underneath.
The goals of refactoring systems and code should be to break down monoliths of code into smaller, simpler sub-components. The primary side effects should result in code that is more readable, testable, and easier to understand for developers coming into the project.
When to Refactor and when to Rewrite
The other solution developers can take when improving inherited software solutions is to throw out old code and replace it with an entirely new and more modern app design. By default, this solution comes with good design practices built-in and the latest technologies available to developers.
Rather than going through the testing, debugging, and refactoring process to refresh an old codebase, many developers would rather throw the whole lot out and start again from stage one.
This can be a strong option if you want to make drastic changes to the underlying architecture or move away from an obsolete or unsupported framework.
AngularJS, for example, was recently discontinued by Google. Refactoring the framework’s apps to support Angular instead would be time-consuming and cost-prohibitive for many. This might be a situation where re-writing may be the better option.
By rewriting an app, developers get a chance to learn from the previous solutions and apply some of the best parts of the design to a fresh approach. Being able to throw away code that would be all but impossible to unpack in favour of more modern technologies can be a real boost to the right projects.
Improving App Design
Refactoring legacy code can be a great way to revitalise ageing projects and bring fresh new technologies into your codebase. It’s a solution capable of taking previously unmanageable code and making it scalable, easy to understand, and maintainable for far less than the cost of developing an entirely new project from scratch.
It’s also an approach that must be handled with care. Far from being a free-for-all for developers to jump in and make improvements where they see fit—effective re-factoring takes careful planning, organisation, and a methodical approach that should be applied for the lifetime of your web app.
Done well and often, refactoring should become easier and easier over time. Soon, it could well be your team’s secret weapon in giving your developers and their apps the competitive advantage when it comes to creating and maintaining high-quality apps on the web.