Best Practice - Refactoring

2024-09-14 16:37:13
Kelsea
Original 311
Summary : Refactoring is a structured technique for restructuring existing code without altering its external behavior, aimed at improving maintainability and extensibility through small, incremental changes. It should be integrated into daily programming practices and performed during feature additions, bug fixes, or code reviews, rather than being scheduled separately, especially as deadlines approach.

Definition

Refactoring is a formal technique used to restructure existing code without changing its external behavior.

At its core, it consists of a series of small behavior-preserving transformations. Each transformation, known as a "refactor," has a minor impact, but the sequence of these transformations can lead to significant restructuring. Because each refactor is small, the likelihood of introducing errors is reduced. After each refactor, the system remains fully operational, minimizing the risk of severe disruption during the refactoring process.

Origin of Practice

The term "refactoring" was first used in published literature in a September 1990 article by William Opdyke and Ralph Johnson. Dr. Griswold's dissertation and Dr. Opdyke's 1992 paper also utilized this term.

Why Refactor?

Refactoring activities offer two main categories of benefits:

Maintainability: It becomes easier to fix bugs because the source code is readable and the author's intent is clear. This can be achieved by breaking down large monolithic routines into a set of concise, well-named, single-purpose methods. It can also involve moving methods to more suitable classes or removing misleading comments.

Extensibility: If the application employs recognizable design patterns, it becomes easier to extend its functionality, providing flexibility that may not have existed previously.

Source: Freepik

When to Use Refactoring

Martin Fowler specifically mentions the timing of refactoring in section 2.3 of his book "Refactoring":

"When I talk about refactoring, people often ask how to schedule it. Should we set aside two weeks every couple of months for refactoring?

I generally oppose setting aside specific time for refactoring. In my view, refactoring should not be something we allocate special time for; it should happen anytime. You shouldn't refactor just for the sake of refactoring; you refactor because you want to accomplish something else, and refactoring helps you do that."

Thus, the appropriate times to refactor include:

  1. As part of daily programming.
  2. When adding new features.
  3. When fixing bugs.
  4. During code reviews.

Avoid refactoring as the final deadline approaches.

How to Use Refactoring

  • Encapsulate Field: Rewrite variables used only within the class as private member variables and provide accessor methods. This hides variables irrelevant to external callers, reduces coupling, and minimizes the chance of unintended errors.
  • Extract Method: Extract a portion of code from a large block to create a new method. This improves the overall structure of the code, enhancing readability. This also applies to functions.
  • Generalize Type: Abstract common types from multiple classes/functions into a shared base class, using polymorphism to add specific functions as needed. This refactoring clarifies structure and enhances maintainability.
  • Pull Up: Move methods from subclasses to their parent class.
  • Push Down: Move methods from a parent class to its subclasses.
  • Rename Method: Change method names to better reflect their purpose.

Source: Freepik

Output

Refactored code.

FAQ

When should you not refactor? Sometimes, you shouldn't refactor at all, such as when the entire codebase needs to be rewritten. If the existing code is too chaotic, rewriting it may be simpler than attempting to refactor.

A clear sign that you should rewrite rather than refactor is when the current code is fundamentally broken. You might find that during testing, the code is rife with errors and fails to function reliably. Remember, before refactoring, the code must work correctly in most cases.

A compromise approach is to refactor large monolithic software into well-encapsulated small components. This way, you can decide whether to "refactor or rewrite" individual components. This is certainly a good direction for significant legacy systems.

Additionally, avoid refactoring as deadlines approach. Unfinished refactoring can be seen as "debt." Many companies take on debt to operate more efficiently, but debt incurs interest—excessive maintenance and extension costs due to overly complex code represent that interest. It's essential to manage debt wisely and pay it down through refactoring.

If a project is nearing its deadline, you should avoid distractions from refactoring, as time is limited. However, multiple projects have shown that refactoring can indeed enhance productivity. If you find you don't have enough time to refactor by the end, it often indicates that you should have refactored much earlier.

References

  1. Martin Fowler: Refactoring: Improving the Design of Existing Code, Addison-Wesley Professional 1999, ISBN 978-0-201-48567-7
  2. CNBlogs
  3. Wikipedia
  4. Chinese Wikipedia
Write a Comment
Comment will be posted after it is reviewed.