Refactoring [Vol 1/3]

Amir Doreh
Coinmonks
5 min readOct 15, 2023

--

When we mention ‘refactoring,’ what springs to mind for you?

As an experienced software developer, I thought I had a solid grasp of the concept of refactoring.

In my opinion, it seemed that whenever I encountered Duplication, non-orthogonal design, outdated knowledge, or performance issues in the codebase, it was a clear signal that some refactoring was in order!

Indeed, it’s absolutely correct, but certain factors must be taken into account when discussing the topic of refactoring and initiating the process in your codebase.

Before we delve into anything else, let’s discuss the essence of Refactoring itself.

The Essence of Software

Well, software doesn’t quite follow that linear construction model. Instead, it’s more like tending to a garden — a dynamic and organic process. Initially, you plant various elements in a garden based on a plan and the prevailing conditions. Some flourish, while others ultimately become compost. You might rearrange plants in response to the play of light and shadow, the influence of wind and rain. Overgrown plants are divided or pruned, and colors that clash may be relocated to more visually pleasing areas. Weeding is essential, and underperforming plantings receive extra attention in the form of fertilization. Continuously monitoring the garden’s health, you make adjustments to the soil, the plants, and the layout as necessary.

Business people tend to prefer the metaphor of building construction: it’s more systematic, repeatable, and adheres to a strict reporting hierarchy for management. However, software development isn’t about erecting skyscrapers; it operates with fewer constraints from the laws of physics and the physical world.

The gardening metaphor aligns more closely with the realities of software development. Perhaps a specific module has grown too unwieldy or is attempting to do too much; it should be divided into two. Elements that deviate from the original plan need to be pruned or weeded out.

The processes of rewriting, reworking, and re-architecting code are collectively referred to as Refactoring.

Code Refactoring Frequency: Striking the Right Balance

So, imagine approaching your boss or client with a request: ‘This code is functional, but I need an additional week for some refactoring.’ We can’t share their response here.

Frequently, time constraints are used as a justification for avoiding refactoring. However, this rationale doesn’t stand up to scrutiny. Delaying refactoring only leads to a more significant time investment in the future when dealing with a multitude of dependencies. Can you count on having more time then? In our experience, that’s rarely the case.

Consider explaining this concept to your superior using a medical comparison: think of the code in need of refactoring as a cancer. Removing it requires an invasive procedure. You can address it now, while it’s still small, or you can wait as it grows and spreads. However, removing it later will be both costlier and riskier. Waiting even longer might result in losing the patient altogether!

As stated in the Pragmatic Programmer book:

Guidelines for Refactoring Your Code

Refactoring is redesign. Anything that you or others on your team designed can be redesigned in light of new facts, deeper understandings, changing requirements, and so on. But if you proceed to rip up vast quantities of code with wild abandon, you may find yourself in a worse position than when you started. Clearly, refactoring is an activity that needs to be undertaken slowly, deliberately, and carefully. Martin Fowler offers the following simple tips on how to refactor without doing more harm than good:

  1. Avoid attempting to both refactor and introduce new features concurrently.
  2. Ensure that you possess robust tests in place prior to commencing the refactoring process. Regularly execute these tests to promptly identify any potential issues resulting from your modifications.
  3. Proceed with concise and intentional actions: shift a field from one class to another, consolidate two similar methods into a superclass. Refactoring frequently entails multiple small adjustments that collectively bring about a significant transformation. By keeping your steps brief and conducting tests after each one, you can steer clear of extended debugging sessions.

Testing or Refactoring: Which Should Lead the Way?

What crosses your mind as you read this?

If you find yourself saying, ‘I understand that testing is highly crucial, and writing tests is essential, but sometimes we need to make immediate changes, starting with refactoring,’ then you may be mistaken, just as I was.

We should consistently ensure that we’ve written tests prior to initiating refactoring. When making any changes, especially minor adjustments, this practice helps verify that our modifications don’t introduce unexpected issues. Therefore, before delving into refactoring, it’s essential to have tests ready for the specific area we intend to begin refactoring.

In conclusion

If you encounter a segment of code exhibiting any of the issues I discussed in the initial section of this article, refrain from immediately jumping into refactoring. It’s crucial to ensure that we have all the necessary preparations in place and have a comprehensive understanding of the steps outlined throughout this article before commencing the refactoring process.

The next time you encounter code that falls short of its ideal state, address not only the problematic segment but also everything reliant on it. Embrace the discomfort: if it’s painful now, but delaying will only intensify the pain, it’s better to tackle it head-on.

This article marks the initial installment in a series dedicated to the topic of refactoring. Stay connected for forthcoming parts on refactoring.

A big shoutout to Andrew Hunt and David Thomas, whose book ‘The Pragmatic Programmer’ served as the primary source of inspiration for this entire series.

discord: am.dd#3991

--

--