Take the pruning shears for a walk
As I’ve discussed in previous articles, taking care of a codebase is, in many ways, akin to tending a garden. As we grow the garden, as we plant more and more trees, we gradually lose control. In addition, weeds start to appear every time we water or implement a new feature. Without good routine maintenance work, software, like a field, can get out of control.
Watch for signs of weeds
The first step a good gardener should take in taking care of his field is to look carefully for signs that may indicate that weeds are growing. In a software project, these signals can take many forms.
If we start reading code that has been written for a while and we have a hard time understanding what it does, it probably needs a refactor and a naming improvement that simplifies the task of reading it. A well-written code can make sense when it is programmed, but the necessary context at the time of its creation makes it difficult to understand after a while. Refactoring it to make it more accessible to revisions is one way to improve it and reduce the cognitive load when reading it.
Sometimes a certain part of our code starts to become unstable. We realize that the latest incidents we’ve had have to do with a particular part of our system. Something that had been working before has started to make noise. That can be a sign that something has degraded. It may be because the amount of data it was designed for is now much greater, or that some change in a third-party dependency has made it more vulnerable. The appearance of errors can be a good sign for us to revisit that part of the system and take the opportunity to make a refactor here and there.
Other times we throw ourselves into developing the next feature and realize that it wasn’t as simple as we thought. What used to be an isolated system has been growing and now depends on several things that you didn’t count on. That makes making changes more delicate and costly. Software grows out of control like bushes that are not taken care of, it’s time to take out the pruning shears and give the code a good review.
As we can see, there are many signs that may indicate the need for refactoring. A good rule of thumb is that a refactor may be necessary when we’re struggling to do something more than we should, whether it’s understanding code, making a change, fixing a bug, etc. That added cost is the one that cries out “Refactor me!” as if it were a plant asking for water.
Get the job done
Once we’ve identified where we have a problem with technical debt or degradation of our software, it’s time to get down to work. Refactoring and maintaining our code is one of the most important tasks of developing software, as it makes it more maintainable and easier to change.
There are different types of refactor: simplify, optimize, restructure, etc. Each type of change affects the code in a different way and we need to know what type of refactor we need to apply to solve the problem. As with product development, when we are dealing with a refactor, the first step is to know what problem we are solving. It’s no use identifying that something is going a little weird and deciding to do a complete rewrite of that part of the system. It is, as they say, using a sledgehammer to crack a nut (although sometimes it’s necessary).
Therefore, identifying what is going wrong is the first necessary step to move on to the next step: focusing on it.
Don’t you understand what each method does? Let’s improve the naming. Do you understand, but we still can’t keep track of what’s going on? Let’s simplify what each thing does and reduce complexity. Do we have everything crammed together and full of dependencies that cause a lot of things to break with each change? Let’s restructure the code to make it more modular and less coupling.
Time has taught me that not paying the attention it deserves to the maintenance of our software can lead us to disastrous situations where we can only get out by digging upwards. There is one very important thing that we should all do in our projects: refactor continuously.
You don’t have to wait for your field to turn into a forest to start pruning. We can start today, little by little. Here are some tips that can help you better manage your crops:
- Refactor continuously: As I said, it’s a task that has to be done continuously. After each new feature hits production, when you’re going to get in touching old code or when you’re going to leave new code stable. It’s not like if it works, you don’t touch it, because if you ever want to touch it again, you’ll be in trouble.
- Prioritize well: obviously we can’t refactor everything, nor can we devote most of our development time to it. We must be selective with what will add more value to the maintainability and evolution of the product we develop or will develop. In the end, we do it so that we can deliver value to our users without our own software getting in the way.
- Have a refactoring backlog (or technical debt directly): everything you don’t prioritize, write it down in a backlog that allows you to have well mapped out what may give you problems in the future to attack it when the time is right.
- Do it step by step: one change, one PR. Don’t put big refactorings along with behavioral changes, you’re just going to mess things up. If you want to refactor first, do it in a previous PR and if you realize that the code you just wrote can be restructured to better fit the project, do it in a later PR.
- Do boy scouting: closely related to continually refactoring is boy scouting. This is making things look better than they were everywhere you go. Many times it is a matter of clarifying naming, applying new consensuses that had not been applied in that area of the code, etc. Since you’re in the area, why not make things better?
- Update your dependencies: take my word for this one, if you don’t want to spend a month updating language versions, necessary dependencies that are breaking, keep them updated. Your future self will thank you.
And last but not least: do it as a team. There is no better task to do in pairing or mob than refactoring. Taking a piece of code that is embarrassing and leaving it pristine is one of the best feelings of developing software. There is no better team building activity. Good pruning and enjoy!
Continuous refactoring is an essential practice for the health and evolution of our code, like caring for an ever-growing garden.
Early identification of signs of weeds in the form of comprehension difficulties, instability, or increasing complexity serves as a focus for the necessary refactoring. The diversity of refactoring types, from simplifying to restructuring, demands an accurate understanding of the problem to be addressed.
In addition, practical tips, such as smart prioritization, step-by-step execution, and team collaboration, highlight the importance of integrating this task as an ongoing routine.
Not only does refactoring improve maintainability and changeability, but it is also a collaborative activity that strengthens the bond between team members. Good pruning and enjoy the process!