Refactoring good practices
Refactoring is some kind of restructuring. Technically, it arises from maths, a cleaner technique to show an expression, is to write an equivalence expression by factoring. Refactoring suggests sameness; the first and last products must do exactly the same. In some way it has to do with changing a design once and the same functionality is developed and coded.
The idea of refactoring is to improve the design of an application that is already running. Therefore, it would be a good term redesign, but unfortunately is not very usual. The trouble with refactoring is that it is risky, because we know we are changing code that works with one that, although we presume it will be better quality, we do not know if it will work.
To make sure the refactoring will be safer and less stress, a good practice is to work with automated unit testing, test the changes in an isolated environment, before implement it. Therefore, the refactoring as stated before, try to improve the design of the code already written, its internal structure without changing the observable behaviour. In other words, any client object should realize that something changed. Hence what we are doing is to modify the internal structure of a piece of code without changing its external functionality.
Once we have defined what refactoring is, the question that remains is perhaps why we do this. The underlying reasons are:
- Try to improve the code, making it more understandable and easy to read, taking into account that the times you will read the code will be a lot compared with the times you write a code (only one).
- We have to be sure that there is not any duplicated code, in order to be sure that each change affects only one portion of the code.
- This is important, to maintain high quality design.
In other words, we want to control the entropy. The term entropy, originally from thermodynamics, means disorder, a gradual and unstoppable disorder which is reached by inertia and which is very hard to leave. In the case of software, the entropy increase usually occurs when a good design evolves through successful adaptations and becomes incomprehensible and impossible to maintain. And so it is important to keep entropy low to be able to easily do changes, fixes and optimizations. We would want to refactor the code in the following situations:
- Before we change the existing code
- Every time after a new functionality is added to the system.
- Before we try to optimise the design.
- While the debugs are running.
- As a result of peer reviews
It is often criticised the practice of refactoring, because in some way we are trying to anticipate to the future needs without knowing whether what we are thinking is correct or not. In fact, the truth is that it does not make any sense to refactor if you will never change the code. And although the code is changed, can I be sure that one hour spend in refactoring ensures at least one hour in the future maintenance? The truth is that there is no way you can guarantee that. However, historical data shows that the vast majority of applications are continually modified, consequently it is a medium term benefit but unfortunately many people avoid it. This is because although it has short-term benefits, the majority of the advantages come in a medium-long term. However, when problems arise, it’s too late to quick solutions, and we must choose more complex alternatives to solve them.
Another problematic arises when we have to deal with the maintenance of an existing application, the most common situation in software development, and usually we argue that we do not have enough time to refactor. However, empirical evidence shows that it is in these cases that suits refactoring, and that time is gained instead of losing it.
On the other hand, there are also people who try to use refactoring as a solution for everything. For instance, people who say that refactoring is an alternative to the previous design. They argue that refactoring allows an incremental design that evolves alongside the code, and it remains in good quality through refactoring. Even though this may apply to small projects, or projects with quite disciplined developers who combines this with other good practices, but it is not the case when these conditions are not met.
Refactoring in a safe way
As it was mention before, the risk of refactoring is high. In fact, we are changing code that is actually working for code that, even though will have a better quality we cannot be sure that it will work. There is a famous quote that says: “If it ain’t broke, don’t fix it” which means that when we are trying to fix something that is working properly, there is a chance that we make new mistakes.
The advice to prevent doing traumatic refactoring are:
- Do only one step at a time
- Keep automated tests and run them before to refactor, does not matter how small the change will be. Those can be unit testing, integration testing and functional testing.
- Use the refactoring tools in the development environment, if any.
- Program the best, always.
- Try that the refactoring is made by the person who wrote and debugged the code, or someone accompanied by him.
The main risk about refactoring are big changes or many small changes together, because if something goes wrong, we will never be able to know what caused the failed. Therefore, each refactoring should be small and reversible.
Refactoring tools are always more reliable than a person cutting and pasting code. For a long time there were not too many. But nowadays there are many free development environments that provide good typical refactoring, and there are additional tools also help find problems, proposing refactoring and perform even more complex tasks.