Code Refactoring Best Practices: When (and When Not) to Do It
This is a guest story by Sydney Stone, a writer for a software development company iTechArt.
Code refactoring is a process used in the DevOps software development approach that involves editing and cleaning up previously written software code without changing the function of the code at all.
Refactoring is not unlike the editing process of a writer. An inspired and focused writer will furiously type their characters’ thoughts and actions into a manuscript, and then go back later to perform several rounds of editing. In some cases, they may even have a professional editor do the job. Editing is what helps the book or article make sense to the reader.
For a developer working on updates or adding new features to an application, reading previous code that hasn’t been refactored is akin to reading a novel that hasn’t been properly edited. It’s difficult to understand, time-consuming, and frustrating.
And this is why there is a need for routine code refactoring.
Why is code refactoring so important?
Code refactoring is important if you want to avoid to the dreaded code rot. Code rot results from duplicate code, myriad patches, bad classifications, and other programming discrepancies. Having a revolving door of different developers writing in their own styles can also contribute to code rot, as there is no cohesion to the overall coding script.
The basic purpose of code refactoring is to make the code more efficient and maintainable. This is key in reducing technical cost since it’s much better to clean up the code now than pay for costly errors later. Code refactoring, which improves readability, makes the QA and debugging process go much more smoothly. And while it doesn’t remove bugs, it can certainly help prevent them in the future.
When should you consider software refactoring?
The best time to consider refactoring is before adding any updates or new features to existing code. Going back and cleaning up the current code before adding in new programming will not only improve the quality of the product itself, it will make it easier for future developers to build on the original code.
Another time to think about refactoring is right after you’ve delivered a product to market. Yes, that sounds ridiculous. You’ve finally launched a product you’ve been working on for months, maybe even years, and now you have to go back to the beginning? This is actually the perfect time to do a little housekeeping, as chances are developers now have more availability to work on refactoring before moving on to the next job.
How to perform code refactoring: the main techniques
As mentioned previously, the best way to refactor is to do it in small steps. It is also important to do it before adding any new functionality or features to the solution. Code refactoring should not change anything about how the product behaves.
That being said, there are many different approaches and techniques for code refactoring. Some of the most popular include:
One of the most widely used techniques for code refactoring is the red/green process used in Agile test-driven development. Applying the Red-Green-Refactor method, developers break refactoring down into three distinct steps:
- Stop and consider what needs to be developed. [RED]
- Get the development to pass basic testing. [GREEN]
- Implement improvements. [REFACTOR]
Refactoring by Abstraction
Branching by abstraction is a method used primarily when there is a large amount of refactoring to be done. Abstraction involves class inheritances, hierarchy, and extraction. The goal of abstraction is to reduce unnecessary duplications in software code.
One example of abstraction is the Pull-Up/Push-Down method. These are two opposite forms of refactoring involving classes. The Pull-Up method pulls code parts into a superclass in order to eliminate code duplication. Push-Down takes it from a superclass and moves it down into subclasses.
Composing involves streamlining the code in order to reduce duplications. This is done through various processes, including extraction and inline methods.
Extraction involves breaking down the code into smaller chunks in order to find and “extract” fragmentation. The fragmented code is then moved to a separate method and replaced with a call to this new method. In addition to the method, extraction can involve class, interface, and local variables as well.
Inline refactoring is a way to reduce the number of unnecessary methods while simplifying the code. By finding all calls to the method and replacing them with the content of the method, the method can then be deleted.
The older code gets, the more garbled and complicated it tends to be. Consequently, it makes sense to go in and simplify a lot of the logic. This can be done in a variety of ways, including consolidation of conditional fragments and expressions and replacing conditional with polymorphism.
Simplifying method calls involves tweaking the interaction between classes. Adding, removing, and introducing new parameters along with replacing parameters with explicit methods and method calls are all aspects of simplification.
Moving Features Between Objects
This method involves creating new classes and moving functionality between old and new classes. When one class has too much going on, it’s time to move some of that code to another class. Or, on the other hand, if a class isn’t really doing that much, you can move its features to another class and delete it altogether.
In his book Refactoring: Improving the Design of Existing Code author Martin Fowler talks about the process of preparatory refactoring. This is done when a developer notices the need for refactoring while adding a new feature, so it’s actually a part of a software update as opposed to a separate refactoring process. By noticing that the code needs to be updated at that moment, the developer is doing his or her part to reduce future technical debt.
Software developer Jessica Kerr provides a great illustrative explanation for preparatory refactoring:
“It’s like I want to go 100 miles east but instead of just traipsing through the woods, I’m going to drive 20 miles north to the highway and then I’m going to go 100 miles east at three times the speed I could have if I just went straight there. When people are pushing you to just go straight there, sometimes you need to say, ‘Wait, I need to check the map and find the quickest route.’ The preparatory refactoring does that for me.”
There are dozens of other methods for code refactoring that can be found at Martin Fowler’s website and at Refactoring.com. The one that will work best for you will depend on the size and scope of your solution, the time-frame you have to perform refactoring, and the number of people available to assist in the overall process.
When you don’t need refactoring
Earlier we stressed that refactoring should never affect the performance of an application and that it should only serve as a clean-up effort. There are times, however, when an application needs to be completely revamped from the start. In these cases, refactoring is not necessary, as it would be much more efficient to simply start from scratch.
Another situation in which it would be wise to skip refactoring is if you are trying to get a product to market within a set time frame. Refactoring can be like going down the proverbial rabbit hole: Once you start, it can become quite time-consuming. Adding any additional coding or testing to an already tight timeline will lead to frustration and additional cost for your client.
Best practices for code refactoring
There are several best practices and recommendations regarding code refactoring. One of the smartest ways to approach it is to apply the Agile method and do it one step at a time, followed by testing. This is why so many developers utilizing Agile methodology are big proponents of code refactoring.
Breaking down the refactoring process into manageable chunks and performing timely testing before moving on to other updates always results in a higher quality application and a better overall development experience.
Here are a few other best practices:
Refactor first before adding any new features
It is always a good idea to perform refactoring whenever you’re asked to add new features or updates to an existing solution. Yes, it will take
longer to finish the project, but it will also reduce the amount of technical debt you or the product owner will have to deal with in the future.
Plan your refactoring project and timeline carefully
One of the hardest parts of code refactoring is finding the time to do it properly.
Think about your overall goal. Do you just want to change the variable names to improve readability? Or do you want to do a full-on cleanup? What are the best ways for you to optimize the code within a reasonable timeframe?
The most important outcome of refactoring is that not only is the code cleaner but that it actually works. And remember, it’s going to take longer than you think, so plan accordingly and give yourself a little extra cushion of time.
The last thing you want to do when refactoring is mess something up in the process and create bugs or problems that affect the functionality of the product. This is why testing throughout the refactoring process is imperative.
Make sure you have proper tests in place before starting any refactoring project.
Get your QA team involved
It’s always a good idea to get your QA and testing team involved in the refactoring process. Whenever you’re making changes to existing code, even as a clean-up project, it can affect testing outcomes.
Changes in classification done during refactoring can cause old tests to fail. In addition, new tests may have to be created for outdated legacy software systems. Both in-depth and regression testing should be performed as part of a refactoring effort. This will ensure that the functionality of the solution was not affected in any way.
Development teams using the Agile method for both programming and testing will most likely already be on the same page involving refactoring.
Focus on progress, not perfection
All code eventually becomes the dreaded legacy code.
Accept the fact that you will never be 100 percent satisfied. The code you’re currently refactoring will become stale and outdated in the near future and will require refactoring all over again.
You have to start thinking about refactoring as an ongoing maintenance project. Just like you have to clean and organize your home throughout the week, you will need to clean and organize your code on many different occasions.
Try refactoring automation
As with most processes, the more it can be automated, the easier and faster refactoring becomes.
Automating some or all of the refactoring processes is becoming more and more popular with developers. There are many shortcuts and tools to make refactoring less painful. A lot of them can be learned by reading Martin Fowler’s book.
Two IDEs (Integrated Development Environments) that have built-in automated refactoring support are Eclipse and IntelliJ IDEA. Look for more refactoring automation in other IDEs in the near future as refactoring shortcuts continue to be a major concern for the development community.
Think of code refactoring as keeping a clean, orderly house. When you have a clean and well-organized home, you’re less stressed because everything is just easier to find and operate. On the other hand, a home with unnecessary clutter can lead to a chaotic and stressful environment.
The same is true for written code. Make it a point to do regular “spring cleaning” on your code and you’ll be rewarded with a better product and a more peaceful and productive work environment.
Sydney Stone is a freelance writer and editor. She has written for various startup and B2B technology companies, currently writing for iTechArt, a NYC-based company specializing in custom software development services for startups.
Want to write an article for our blog? Read our requirements and guidelines to become a contributor.