Bob is a developer. He has been asked to add a brand new feature to the application. He’d like to take this opportunity to refactor the code a little bit, since it doesn’t respect the good practices he learned from the last Software Craftsmanship meetup. However, Bob was told he couldn’t do it because there was not enough time to do anything other than produce features. So, Bob thought, “there is never enough time anyway”…

Sounds familiar? Indeed, refactoring is often seen as an activity without any value. Other things in life can also seem pointless. There is one that takes almost a third of our lives during which we literally do nothing: sleeping!

The number of things we could do if we didn’t sleep! However, after a few days, even hours, unpleasant events would start to appear. Without sleep, the most trivial tasks can become challenging to accomplish, and weird mistakes can take place (like pouring orange juice into your bowl of cereal). After a while, sleep would suddenly take over, leading to accidents (such as drowsy driving).

In the same way, postponing refactoring harms a project. Developments may take much longer than necessary, and bugs may occur in features very different from those modified. Moreover, there comes a point where refactoring forces itself upon you unexpectedly: the code can no longer be modified without risking significant regressions. This can happen at a critical moment in the project and jeopardize it entirely. At this point, the feared verdict may be rendered: “We must rewrite everything.”

In general, regular refactoring is necessary for a project’s good health, just like sleeping every night is for us. In this article, we will define what refactoring is, when it’s best to do it, how to prepare for it and what to do if time is short.

What does refactoring mean?

According to Michael Feathers, refactoring is “the act of improving design without changing its behaviour.”

It is not necessarily about changing an entire class hierarchy or implementing a complex design pattern, but it can be as simple as renaming a variable, method or class; extracting a private method into an external class; or grouping a method’s attributes into an object.

Furthermore, adding tests to an existing codebase can also be considered refactoring. Indeed, making code testable is the first step towards a better design.

When to refactor?

The idea is not to fix the entire system each time. This would be unproductive and impossible to carry out. Also, it would be hard to justify causing regressions in code unrelated to the feature being changed.

Refactoring is most effective when targeted at the code directly related to the feature being developed. Moreover, it’s preferable to refactor before adding new code, so you start from a clean foundation.

How to prepare it?

The first thing to do before refactoring is to ensure that tests cover the code you’re going to modify. Tests verify that refactoring doesn’t introduce regressions. If tests are missing, add them before starting.

Sometimes it’s impossible to test a portion of code in its current state. In such cases, perform the minimal refactoring required to make it testable.

What to do if time is missing?

If you lack the time, like Bob, you must be pragmatic and do small refactorings alongside each development. This allows you to improve the design incrementally without consuming too much time, while also preparing the ground for larger refactorings later.

Conclusion

Refactoring is essential in a project and should be done regularly. It ensures new features are developed within a reasonable timeframe and limits regressions by improving the design. Furthermore, it allows developers to (re)discover the pleasure of making the product evolve.

Let’s conclude with the Boy Scout rule that inspires us always to leave the code in a better condition than we found it. Applying this rule enhances overall code quality and helps reverse technical debt.