What is code refactoring?
Code refactoring is a concept well known in software development and it is the process of restructuring code without changing its external behavior. This means the implemented changes do not necessarily serve to expand functionality, but rather to assure the quality of code is maintained and any technical debt that your codebase has accumulated is paid off (see below for more on technical debt). Refactoring is most commonly done by developers working closely with QA specialists, and at a high level, it is a process of assessing the code, implementing changes in line with the most recent standards and testing for their impact on the remaining parts of the product.
Why is refactoring your code important?
Code refactoring should be an integral part of scaling-up a digital product. This is because adding new functionality may impair the performance of existing features, or simply prove to be much more time-consuming than expected. In extreme cases, it might even be impossible, with new features deployed to production crashing the entire build. Refactoring directly impacts your codebase’s ability to accept changes and ensure the effective scaling of your product.
Security tends to be an issue as well. An out-of-date codebase is prone to security breaches in times when its inherent safety loopholes have not been patched and have become well known to the public.
Lastly, there is a concept known as technical debt - a circumstance in which a codebase may suffer from problems caused by opting for “shortcut solutions”. They might shorten the time necessary to achieve a functionality goal, but are suboptimal and limiting in the long term. While simplifying things in early development (e.g. in proof-of-concept projects and/or MVP builds) is recommended, unaddressed technical debt builds up and accumulates “interest” that will have to be paid back in refactoring later on.
At least several more issues would easily make the list of all undesired things that may happen if you leave your codebase without care. Unsurprisingly, these problems are best not swept under the rug if you’re aiming for a product that’s there to stay. Regardless of whether your codebase suffers from one, or all of the above issues, what you need to do is to refactor your code.
How to know whether or not your codebase needs refactoring?
It’s an easy assessment for developers, but what if you’re a startup founder between development teams? In that case fear not, as this is exactly the question I’ll answer in this post.
The easy way would be to contact a software house and purchase a few hours of code review from them. Code review is an offering specifically made for assessing existing codebases and creating a report on all findings - good and bad.
At Merixstudio, we examine code and look for potential problems in code quality, performance, and security. All issues are assigned a severity level and described in the report. It’s a quick way to determine the state of your product’s code. You can find out more about how we deal with taking over the development of existing digital products in our article on how to take over the development of an existing codebase.
If you're a non-technical person that is not set on speaking to a software house yet, you may look for a few clear signals your codebase sends out when it's in poor shape.
1. Library versions are out-of-date
In your repository, look for configuration files. Every technology used to code your product should have a package manager, which is responsible for listing and managing project dependencies. Within the listing, you’ll find information on the version of the libraries used to build your product. Using the power of Google, find out if it’s the latest version. If not, it is recommended to update it for reasons such as publicly known security loopholes, support and backwards compliancy for past versions being limited, or even ceased.
2. Commits have been done a long time ago
Every code repository tracks changes done to the code - this listing is called commit history. Commit history in the repository is one fairly simple way that doesn’t require much know-how. Look for the latest commit, if it's been months since the last change, the chances of your code being updated and requiring refactoring before any further work can be done are high.
3. Lack of documentation and readme files
This one might not be as straightforward as the previous signs, but it is something you can use nonetheless. If your code is documented, it means it has the business context around it explained in a text file or on an interactive website. You might want to look for readme files and instructions on how to set up the project next.
Why is it worth checking? If your codebase doesn’t have all the above, there are two things to potentially expect. One, shortcuts have been taken during development to speed up work and if so, it is expected to find problems with upholding high standards of code structure. Two, if there is no business context given around specific parts of the code, a development team that’s new to the codebase might have difficulty navigating it and working on it as a result.
4. No unit tests coverage
Unit tests are tests written by developers for an isolated piece of functionality used to automate validating its proper performance. Once programmed, these remain in the codebase and become increasingly helpful in scaling it, since they detect any issues that are a result of changes made in the code interfering with live features.
Without unit tests, providing information on failures in code execution, assumptions on what went sideways would likely turn out to be hit or miss, with “blind” refactoring being the usual follow up.
With no unit test coverage, we have no way of telling whether the features have been coded properly and how they will react to further scaling, in which case refactoring and subsequent unit test coverage is necessary.
5. Repository structure is messy
Repository structure is not just a subjective thing and should never be a result of an artistic vision of an individual. There is a method to follow with this and it bases on a few principles.
Repository structure should most of all be clear and easily understandable, even for a non-technical person (assuming, of course, they know the basics of what is contained within the structures of a code repository). Its core components should be a breeze to identify and it should provide clear differentiation between code verticals (modules). Repository hygiene is crucial to maintain, otherwise, no developer will be able to navigate it, let alone work with it.
6. Code does not meet essential programming principles
Well-written code is easily readable with each script hinting at what it does - this follows a pattern called the Single Responsibility Principle. Functions and objects should suggest what they do and what results they produce. It is done for ease of navigation and work. Take that away and working on a codebase turns out to be increasingly difficult and unpredictable with every change you make.
7. An excessive amount of commented out code
Code that’s been commented out is a part of code that’s “out of order” and not executed. That's usually a predictor of poor quality. These kinds of “notes” often contain changes to the code waiting to be implemented in an undefined time in the future, or there were problems with a specific script that no-one ever had the time to explain and settled for just commenting it out.
8. Comments with excuses rather than context
Comments to the code are something different than commented out code and don't necessarily translate into a need for refactoring. In their application, they are not too dissimilar to comments to paragraphs in e.g. Google Docs.
These comments tend to be either good or bad depending on their content. If a comment serves to add context that wouldn’t be otherwise deductible just by screening a function or a script, it’s considered a valuable insight and is best kept for the future. However, if a comment was left by a developer explaining their thought process (which we would normally call “making excuses”), that most likely means refactoring is due.
9. Making changes in code takes years
If making changes or adding features to the codebase consumes more time (than one would expect compared to e.g. building a codebase from scratch) with each commit made due to bugs, unpredictable code behaviour, and crashes, it is probably the most convincing signal that refactoring is warranted. This usually comes accompanied by comments such as “we did not foresee that”, or “we have no idea why this happened” coming from the delivery team.
It most certainly means that the code suffers from technical debt and that it probably lacks unit test coverage. Continuing work with a codebase in this state will inevitably result in the application malfunctioning in nearly all of its domains and source code so beyond saving, that it leaves a developer with no choice but to scrap it and start anew.
10. App’s code is not optimized to the current traffic
Performance problems are a solid indicator of inherent problems with the product’s source code. If your application’s performance slows down or crashes under heavy user traffic, users contact you with feedback to dragging load times, it probably means your application’s code has only been optimized for light traffic and the current load is beyond its capabilities. Refactoring is necessary to remedy this and it would be a good decision to work with a solid delivery team on identifying good performance and bottleneck detecting tools to implement in order to avoid future problems of this sort.
Ready for code refactoring?
Hopefully, the 10 above points will help you assess the state of your codebase without help from a development professional. These were compiled to serve even non-technical product owners as a high-level guide to code quality.
Please keep in mind though, that while these points are good markers for your codebase’s state (some being more definitive than others), they are supposed to expose a need for refactoring that otherwise wouldn’t come to your attention.
To reliably determine the scope of changes required during refactoring work to remedy problems with a codebase, it is still strongly recommended to contract a development expert. Learn how to find a reliable modernization partner.