Code refactoring is integral to every developer's daily routine. Thoughtworker Martin Fowler wrote the canonical text on refactoring and described it as a disciplined technique that involves restructuring existing code to make it better without altering the external behavior. Refactoring is particularly important in Agile development where design evolves incrementally.
Lately, however, I have come across certain misconceptions that disturb the developer in me. This post is my attempt to describe these misconceptions and offer solutions in dealing with them.
A Big or Large Scale Refactoring
This arises when developer teams mistake redesign for ‘Big Refactoring’. Let me tell you why this happens. Developers, sometimes erring on the side of caution, decide that a refactoring is needed so as not to alarm stakeholders. Other times, developers become lazy when it comes to calling out explicit needs and are comfortable using the generic ‘refactoring’ cover. In such cases, the developers are to blame for the misdirection. And the reasons could be anything from:
- Drastic change of requirements or increasing complexity of the domain over time
- A need to simplify the existing design
- Degradation of code/design quality over time - probably because the team was focused on delivering “more” with lack of code quality
The impact could be (m)any of the following:
- Fewer functional stories are picked up for development
- The app may not be 'testable' or ’stable' (during the period) which leads to restless QA's
- Regression testing if refactoring is taken up towards the end of a release; can make QA's jittery and question the need for such a change
The dev team should have called it, a ‘redesign’ instead of refactoring.
In case of a need to perform redesign, developer teams should minimize the redesign’s impact. The team would benefit from clear communication of the problem, the options available and the final decision taken with knowledge of all stakeholders. Develop in a separate code branch and time box the effort - the longer it takes, the more difficult it becomes to merge and test.
Unless such redesigns are a strategic call, modifications should always be a series of continuous, incremental changes that are part of regular continuous integration builds. This avoids the introduction of any big bang or breaking changes.
Refactoring Means you Designed it Wrong
Some developers might want to avoid refactoring by getting the design right the first time around. However, a basic Agile principle is getting a Minimum Viable Product into production, as early as possible. The bells and whistles can, and will, come in later. And in this scenario, we wouldn’t (and probably couldn’t) design upfront.
Instead, it makes sense to move forward with the design phase only for requirements with context and clarity. This means, the design will evolve over time and it applies to every class and method written.
This, however, does not mean that developers should restrict themselves to one requirement at a time. They can attack similar problems or requirements, together. It will bode well to have a broader discussion with the client or product owner, understand their vision, explore options and build a common roadmap.
It would still be smarter to ‘implement’ only for the present with extensibility for the future. Building smaller component rather than bigger ones will induce confidence at every step.
You’ll Go Faster if You Don’t Refactor
It is true that refactoring doesn't change or produce any new functionality. But it improves the efficiency and productivity of the developers. Refactoring is like removing barnacles off of a boat's hull.
Avoiding refactoring could appear to conserve capacity, but development will eventually slow down. Stories will take longer to complete. Code and application quality could deteriorate. The rest is history.
Create a Separate Tech Card for Refactoring
Refactoring is an incremental and continuous change to the code base. The entire team should refactor as part of every story development. Piling up refactoring tasks and bundling them up into a separate story means delay in project execution.
Additionally, when refactoring is taken up as part of a story, developer teams can avoid the risk of building something unwanted or complex. The structural changes can also be tested as part of the same story.
Estimate the Effort for Refactoring
Owing to refactoring, stories might take longer to complete. But, that does not imply that the story points or size increase from, say, a ‘S’ or 'Small’ to an ‘M’ or 'Medium’.
What it does mean is that an ‘S’ sized story takes longer to complete, so the velocity or the number of story points completed per iteration has reduced. But the team has improved the code base quality which makes further development much more efficient. If this is not the case, that’s an indication that the team is dealing with a completely different issue.
This obviously makes estimation of refactoring, difficult. How many 'buffers’ would the developers add upfront? This also implies that significant refactoring or redesign needs to be brought up during client showcases. This practice would ideally improve the team’s confidence.
Ultimately, What Does This Mean for You?
For non-developer stakeholders, especially decision makers and influencers, understanding the subtler aspects of development can help analyse the team's performance. Absence of this could lead to frustration, incorrect inferences or even unnecessary panic.
Developers, on the other hand should look at refactoring as a technique to maintain software hygiene. It is better to ‘clean up’ software, regularly rather than wait for it to 'stink' and then take up refactoring. Developers should also build a robust safety net from day one—it helps perform refactoring and redesigns with greater confidence.
Disclaimer: The statements and opinions expressed in this article are those of the author(s) and do not necessarily reflect the positions of Thoughtworks.