A Tale of (Continuous) Refactoring to non-specialist people



Have you ever played the code kata exercise called “Sing a song”? In this simple yet effective exercise, developers are asked to take over an existing codebase without tests to cover a straightforward business case. The purpose of practicing code kata is not only about improving coding skills but also about fostering a mindset of continuous improvement and learning among team members and stakeholders.

In part one I will explain why (continuous) refactoring plays a crucial role in the software developement lifecycle. I will discuss my experience using the code kata to effectively communicate the importance of the practice to various stakeholders.

The Necessity of Refactoring

Refactoring is the practice of restructuring existing code without changing its external behavior. It allows developers to improve the internal design of their codebase providing several benefits:

  1. Improved code quality: Helps to eliminate technical debt and improve overall code quality.
  2. Faster development time: A cleaner, more maintainable codebase allows developers to write new features more efficiently.
  3. Reduced maintenance costs: Refactored code is easier to understand and modify, reducing long-term maintenance costs.
  4. Enhanced team collaboration: Consistent refactoring practices help to ensure that everyone on the development team is working with a high-quality codebase.

However, refactoring might not always be a straightforward task. In some cases, it may be necessary to implement a feature or even complete a project before the codebase can accommodate the desired changes. In many cases, a codebase may not initially support a new feature due to outdated design or poor organization or just because it was not useful.

As the following Git history shows, any team was able to fully implement the requested feature before doing a big step of refactoring:

* 53617bb feat: Make the song configurable for different list of animals.
* 6908eae refactor: Put breaking line inside intro to avoid unecessary code.
* 106e86b refactor: Encapsulate intro inside Animal.
* f56c2c1 refactor: Use named constructor and fluent interface to ease readibility.
* 626303d refactor: Extract code in dedicated classes and ghet rid of static.
* fd7077f refactor: Remove unecessary function.
* 3c5580f refactor: Get rid of all remaining replace using string interpolation.
* 2542a12 refactor: Remove ultimate replace of first animal.
* afe46f4 refactor: Remove ultimate replace of last animal.
* a74ec51 refactor: Rename some variables.
* 794caae refactor: Build last paragraph inside common function.
* 3226cb5 refactor: Encapsulate animal inside a dedicated class.
* 7f3be87 refactor: Factorise intro of each paragraph.
* 6c71183 refactor: Encapsulate building paragraph.
* 6e5c4f8 refactor: Revert intro and outro.
* 5c1d5a6 refactor: Encapsulate intro and outro.
* 4b0b2a5 refactor: Encapsulate repition in a loop.
* 7801f39 refactor: Encapsulate middle paragraphs.
* 2019f25 refactor: Encapsulate repeated part inside paragraph into function.

Stakeholders noticed immediately. They projected themselves into real-life conditions and started asking lots of pertinent questions. Among them, how can we avoid ending up in this situation?

Fostering continuous improvement

Do It Continuously

Refactoring requires developers to invest significant time and effort into improving the existing codebase. When developers inform stakeholders that the pace of new feature deployment will need to slow down, it may cause frictions for several reasons:

  1. Misaligned expectations: Stakeholders might have set specific timelines and goals based on the initial development estimates. When these deadlines are delayed due to refactoring efforts, they could feel disappointed or frustrated.
  2. Perceived lack of progress: Refactoring might not be as visible or tangible as building new features, leading stakeholders to perceive it as a lack of productivity or progress in the project.
  3. Increased development costs: Refactoring can be time-consuming and require additional resources, which may result in increased development costs that could impact the overall project budget.
  4. Delayed time-to-market: New features are postponed, potentially delaying the product’s time-to-market and allowing competitors to gain an edge.
  5. Inadequate communication: Developers may not have effectively communicated the importance of refactoring and its impact on new feature development to stakeholders, leading to misunderstandings and potential conflicts.
  6. Resource allocation concerns: Stakeholders might question the priorities if they see developers spending significant time on refactoring rather than building new features that directly contribute to revenue growth.

Sometimes, it can escalate to a point where it becomes challenging to distinguish between the refactoring phase and a complete rewrite of the software. This scenario is typically the result of neglected maintenance and a lack of prioritization of continuous refactoring efforts in the development process.

As Martin Fowler puts it, Frequency Reduces Difficulty. In software engineering, there’s a well-known paradoxical advice that could apply to refactoring: “If it hurts, do it more often.” This seemingly counterintuitive statement is based on the idea that addressing pain points early and consistently can lead to long-term benefits.

Conclusion

In a nutshell refactoring plays a crucial role in maintaining the quality, performance, and sustainability of software products. Despite ad hoc refactoring usefulness, doing it continuously is most of the time a preferable way because it avoids having dedicated phases that can last for an extended period.

Developers integrate refactoring into their daily development routines, consistently ensuring that the codebase remains in good shape.

Martin Fowler expresses continuous refactoring under the name of “Opportunistic Refactoring”. The name change but the principle stays the same.

From the beginning I’ve always seen refactoring as something you do continuously […]. Yet there’s a common misconception about refactoring in that it’s something that needs to be planned out. Certainly there is a place for planned efforts at refactoring, even setting aside a day or two to attack a gnarly lump of code that’s been getting in everyone’s way for a few months. But a team that’s using refactoring well should hardly ever need to plan refactoring, instead seeing refactoring as a constant stream of small adjustments that keep the project on the happy curve of the DesignStaminaHypothesis.

Next part of the “Sing a Song” Kata journey is in progress

The article was written with the help of Mistral AI.