Embracing a Proactive Refactoring Engineering Culture by William Ramirez
Refactoring is a critical process that plays a significant role in enhancing code quality and maintainability. Despite its importance, it tends to get sidelined and lost in the priority queue.
Misconceptions often mar the path to teams taking on a more pro-refactor culture. Stakeholders, including product owners and developers, can get fixated on immediate deliverables and view refactoring as a secondary task that detracts from feature development. This perception, coupled with the belief that refactoring implies poor initial quality or design, creates a reluctance to create tickets and allocate time and resources to this vital process.
If, by definition, refactoring does not create any noticeable change in the software's behavior, why should we develop a culture of embracing refactoring?
When projects are greenfield, it is easy to be productive. Less code needs to be understood before one can start making meaningful contributions. As the applications grow, they inherently become more complex. It is common for teams to have only a fraction of the velocity they once had after a codebase reaches a considerable size. Regular refactoring makes codebases easier to work with, which is a powerful way to mitigate this loss of developer productivity.
The rise of Agile project management methodologies has created an even greater need to embrace a proactive refactor culture. Agile methodologies prioritize flexibility, adaptability, and responsiveness to changes in requirements or circumstances. Adopting Agile methodologies implies there will be changes to the roadmap, and trying to adhere to a completely pre-designed architecture is not a realistic option. The need to be adaptable to change forces developers to be open to evolving requirements, making a solid case for developers to incorporate a more proactive refactor culture. Appreciating that there will be sprints in which teams need to focus purely on deliverables, a well-manicured, healthy codebase will pay dividends by adding velocity to a sprint when teams really need it.
Additionally, software is a team sport, and contributors will undoubtedly come and go. A more proactive approach to refactoring allows new members to make more meaningful contributions sooner and gets members up to speed faster. Conversely, as members leave teams, authors will not be around to give explanations, leaving the new maintainers at the mercy of the health of the codebase.
Refactoring aims to give the developer time to understand the code and to transfer those insights back into the body of work so that the next reader can more easily come to those same conclusions about how the program works. Some refactoring efforts may be to decouple services and make features more modular so that the next developer can modify one program and not have to understand what is happening in the other. Still, all refactors should have the same intent - to facilitate the coding process for the next person.
As a bonus, this process does wonders for fixing bugs. Like in real life, bugs thrive in the dirtiest and darkest places. Code bugs linger in the areas in your code base that are the most difficult to make sense of, and just like our basements, the more frequently it is cleaned, the less likely you are to attract pests.
For this reason, teams should optimize for readability above performance. In almost all cases, preventing a program from running another cycle and shaving off a third of a second is not as beneficial as saving a developer hours, if not days, of development time to add a feature or fix a bug. Optimizing for readability first may even lead to insights on how to tune the program for performance later.
So, what does this process look like? Imagine you are tasked with adding a new feature. Since you want to look for ways to improve the code actively, you would search for "smells" in the code with which your new feature would interface. An example of a "code smell" would be some confusing logic nested in a switch statement that is difficult to understand.
By taking the time to improve that bit and making it easier to understand before adding the new feature, you are leaving the campsite better than you found it, as Martin Fowler would put it. This approach is contrary to the more common act of surgically adding a bit of code to get the job done and going about our way.
It may not seem intuitive to modify already functioning code. A change like this could be seen as a criticism of the original work or simply unnecessary. Some might be reluctant to touch it to avoid the risk of causing a regression. If that is a concern, proper automated testing to verify the program's behavior effectively meets expectations will be your faithful companion on this quest. With proper tests in place, you can confidently make incremental changes, ensuring no setbacks occur.
Embracing a proactive refactoring culture is embracing the process of making small changes to improve the codebase proactively to make it easier for the next person, which will, over time, significantly improve the overall health of the codebase. As a result, teams will not lose velocity as the codebase increases in size, enjoy time savings, and be more productive with less effort.
Conclusion | Take AwayS
Refactoring is a core aspect of software development culture. By embracing a refactor-positive mindset, teams can build more resilient, adaptable, and high-quality software. The key is to shift perceptions, recognizing that refactoring is as much a part of software development as writing new code.
A refactor-positive culture ensures that codebases remain clean, understandable, and adaptable to changing requirements. Such an environment enhances developer productivity and accelerates the development cycle. It simplifies onboarding for new team members and fosters better collaboration, making the codebase a shared and well-tended asset rather than a liability.