Refactoring - Common Misconceptions
Code refactoring is an integral activity of every developer's day to day routine. It is a disciplined technique that involves restructuring existing code to make it better without altering the external behavior. It is all the more important in Agile development where design evolves incrementally.
Of late, I have come to hear about things that really disturbs me as a developer. In this post, I try to describe the 'misconceptions' and how we should deal with them.
1. Big or large scale refactoring
This situation arises when the dev team calls out a need for "big refactoring". The impact could be (m)any of the following :
1. Fewer functional stories to be picked up for development
2. App may not be 'testable'/'stable' (during the period); leads to QA's becoming restless
3. Regression testing of all functionality built so far (after the period); can make QA's jittery and question the need for such a change
The devs are to be blamed for misdirecting every one here. What they intend to do here is a "redesign" and not refactoring. The following could be reasons:
1. Requirements change drastically or the domain gets more complex over time
2. Unifying design to simplify architecture and reduce complexity with the experience and lessons learnt so far
3. Code/design quality has degraded over time; no semblance of team focussing on quality aspects but mainly focussed on delivering functionality
The 3rd reason could only mean the team was overworked simply because they didn't have time to focus on engineering practices.
There could be occasional instances for reasons 1 and 2. In such cases, we should try to minimize the impact of redesign. Devs should clearly communicate the problem, options available and decision taken to all stake holders. Develop in a separate branch and time box the effort - the longer it takes, the more difficult it becomes to merge and test. Such redesigns though, could be important more from a strategic point of view. But otherwise, modifications should always be a series of continuous, incremental changes that are part of regular Continuous Integration builds without introducing any big bang or breaking changes.
2. Avoid refactoring (or) Did the design go wrong ?
A few devs may believe in avoiding refactoring totally by getting the design right the very first time. In agile development, the approach is always to a get a Minimum Viable Product to production as early as possible. The bells and whistles come in later. In such a context, you don't (probably can't) design upfront. Instead do it only for the current set of requirements which have more context and clarity. Hence, the design evolves over time. This definitely includes almost every class and method you write.
Of course, this doesn't mean you should restrict/constrain yourself to 1 story at a time. You can attack similar problems or requirements together. Ensure to have a broader discussion with your client/product owner, share the vision and boundaries, explore options and build a common roadmap. But implement only for the present with extensibility built for the future. In other words, build many smaller components rather than few big ones. Build up confidence at every step.
3. Let's de-prioritise refactoring, we can go faster !
It is true that refactoring doesn't change or produce any functional behaviour. But it improves efficiency and productivity of developers. It is similar to removing any scale deposits on heating elements or barnacles on a boat's hull. Without any refactoring it may appear you are going to be fast capacity wise but soon development will slow down. Stories will take longer to complete than expected. Code and application quality could seriously deteriorate. The rest is history.
4. Let's do refactoring part of a separate tech card
Refactoring is incremental and continuous change to the code base. The entire team should do it part of every story development. So, to pile up refactoring tasks and bundle it up as a separate story could mean further delay in project execution. Additionally, there never is a risk of building something unwanted or over-complex when done part of a story but exists when done in isolation. The structural changes can also be tested part of the same story.
5. Let's estimate refactoring
Owing to refactoring, stories may take longer to get completed. This doesn't mean the story points/size increases say from 'S' (small) to 'M' (medium) for a story. Instead, it means that it took longer to finish a story of size 'S'. Hence, the overall velocity (story points done per iteration) has reduced. But, the team has improved the code base quality and hence, future development should become more efficient. If this cannot be observed, it is an indication of possibly a different issue.
Hence, you can't really 'estimate' for refactoring or add 'buffers' upfront - how much will you add ? It becomes important to call out any significant refactoring or redesign taken up by teams during showcases to clients. This can improve overall confidence on the team. Of course, depends on the way you present it.
What does this mean to me ?
For a non-dev stake holder (especially decision makers and influencers) : Understanding these suttle aspects of development can help you better analyse your team's performance. Absence of this could lead to frustration, incorrect inferences or at times, panic for unnecessary reasons.
For a developer : Look at refactoring as a technique to maintain software hygiene. You better clean it up regularly rather than wait for it to 'stink' and then resort to tactics. Build a robust safety net from day 1, it can help big time.
Remember, postponing refactoring makes it harder and harder with every code commit - code always moves to a disorderly state when left unnoticed.
Good one Sivasubramanian Venkataramamoorthy
Good one Sivsu