Refactoring for Beginners: Part 1

Refactoring is a practice aimed at improving existing code without altering its external behavior or functionality. Its purpose is to enhance the overall structure, readability, and maintainability of the codebase. Refactoring encourages clean and reus…


This content originally appeared on DEV Community and was authored by Mina

Refactoring is a practice aimed at improving existing code without altering its external behavior or functionality. Its purpose is to enhance the overall structure, readability, and maintainability of the codebase. Refactoring encourages clean and reusable code that reveals intent, thereby helping to create well-structured design patterns.

A common misconception is that the design patterns of a project should be determined upfront, and one must strictly abide by them. However, continuous refactoring allows the codebase to evolve more naturally, forming better design patterns that more effectively accommodate the app's requirements.

So where should we begin when refactoring? Detecting 'code smells' can be the first step. 'Code smell' is a term used to describe code that not only contains repetition but also lacks clarity of intent and is overengineered to the point of being overly complex to understand. These involve duplicated code, names that don't clarify their purpose, global data, long methods, parameters, and classes, as well as complex conditional/switch statements, among others.

Although duplicated code is not always a problem but could be necessary at points that it helps readability, let’s consider the following example.

  for (const lesson of lessons) {
    if (lesson.subject === 'english') {
      total += lesson.price
    }
  }

  for (const lesson of lessons) {
    if (lesson.subject === 'spanish') {
      total += lesson.price
    }
  }

This repeated code could be extracted into a function with a descriptive name that clearly communicates its purpose. If performance isn't a primary concern, higher-order functions like 'filter' and 'reduce' could be used to make the code more readable.

funciton calculateTotalForSubject(lessons, subject) {
  let total = 0;
  for (const lesson of lessons) {
    if (lesson.subject === selectedSubject) {
      total += lesson.price;
    }
  }
  return total;
}

Global data is often viewed as a code smell: it can alarm developers as it can create potential problems. There are situations, especially in frontend development scenarios like logging and configuration settings, where a single source of truth for the entire application's state is necessary. The singleton pattern can be useful, but the global data should be maintained immutable (much like in Redux implementations) or read-only. The singleton pattern can raise concerns because the data is susceptible to modifications from anywhere in the codebase, and if it is mutable, it can cause unexpected changes.

Image description

In situations where global data poses a problem, encapsulation is a useful refactoring strategy as it allows data to be stored locally within specific scopes rather than globally. By doing so we can better control how and where the changes occur.

This approach can be accomplished through the techniques of extracting and inlining classes. To extract a class, we simply identify the methods to be relocated and extract them into new classes. On the other hand, inlining a class is like taking the methods and properties from one class to another and integrating them directly into the new class.

class CourseSingleton {
    constructor() {
        if (CourseSingleton.instance) {
            return CourseSingleton.instance;
        }

        this.courses = {};
        CourseSingleton.instance = this;
    }

    addCourse(name, subject) {
        if (!this.courses[subject]) {
            this.courses[subject] = courseContent;
        }
    }

    getCourse(name) {
        return this.courses[name];
    }
}

Inlining singleton looks like this.


class Course {
    constructor() {
        this.instance = new CourseSingleton();
    }

    addCourse(name, subject) {
        return this.instance.addCourse(name, subject);
    }

    getCourse(name) {
        return this.instance.getCourse(name);
    }

    displayCourses() {
        return instance.displayCourses();
    }
}

In the client code, you would then reference Course instead of CourseSingleton.

To be continued...


This content originally appeared on DEV Community and was authored by Mina


Print Share Comment Cite Upload Translate Updates
APA

Mina | Sciencx (2023-06-02T04:10:13+00:00) Refactoring for Beginners: Part 1. Retrieved from https://www.scien.cx/2023/06/02/refactoring-for-beginners-part-1/

MLA
" » Refactoring for Beginners: Part 1." Mina | Sciencx - Friday June 2, 2023, https://www.scien.cx/2023/06/02/refactoring-for-beginners-part-1/
HARVARD
Mina | Sciencx Friday June 2, 2023 » Refactoring for Beginners: Part 1., viewed ,<https://www.scien.cx/2023/06/02/refactoring-for-beginners-part-1/>
VANCOUVER
Mina | Sciencx - » Refactoring for Beginners: Part 1. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2023/06/02/refactoring-for-beginners-part-1/
CHICAGO
" » Refactoring for Beginners: Part 1." Mina | Sciencx - Accessed . https://www.scien.cx/2023/06/02/refactoring-for-beginners-part-1/
IEEE
" » Refactoring for Beginners: Part 1." Mina | Sciencx [Online]. Available: https://www.scien.cx/2023/06/02/refactoring-for-beginners-part-1/. [Accessed: ]
rf:citation
» Refactoring for Beginners: Part 1 | Mina | Sciencx | https://www.scien.cx/2023/06/02/refactoring-for-beginners-part-1/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.