Refactoring in software engineering

Hi coders, Welcome to our easy-to-follow code Refactoring course, Where i will teach you refactoring in software engineering

In this course, I will show you the difference between messy code and clean code. That will help you learn how to do code refactoring improving the design of existing code. We will discuss the different types of code smells that show “what not to do when writing code”. After that, we will learn lots of ways to fix and improve bad code and refactoring in software engineering

Good luck and have fun learning!

refactoring in software engineering

What is Refactoring in software engineering?

Refactoring is a systematic and disciplined process of improving the internal structure of code without altering its external behavior. Where we ensure the production of efficient, readable, and error-free code, especially crucial in object-oriented languages. It’s not about fixing bugs or adding new functionalities. It’s about transforming a mess into clean code and simple design.

NOTE: Performing refactoring step-by-step and running tests after each change are key elements of refactoring that make it predictable and safe.

How to Identify When to Refactor

A good developer always makes sure that the code is always in the best shape. But what’s the meaning of best shape? It means to make sure that everyone can easily understand and work with the code. If someone wants new features that can be added without much hassle, and that bugs can be fixed easily. Here I will tell you when you should take action:

Follow the Rule of Three

When doing something for the first time, it is acceptable to just write it. At this point, creating an abstraction might be premature since it’s not clear how often the pattern will be repeated. So just focus on completing it.
The next time you find yourself doing something similar, you should take note of the duplication but go ahead anyway.
But when a similar piece of code for the third time, that’s when you should start refactoring. You should write code into a generic solution, such as a method or class to reduce redundancy.

Let me explain to you with a small example of refactoring.

Suppose we have an application where we want to calculate the area of rectangles.

First occurrence

public class GeometryApp {
    public static void main(String[] args) {
        int length1 = 10;
        int breadth1 = 5;
        int area1 = length1 * breadth1; // calculating area directly
        System.out.println("Area of the first rectangle: " + area1);
    }
}

Second occurrence

public class DrawingApp {
    public static void main(String[] args) {
        int length2 = 15;
        int breadth2 = 10;
        int area2 = length2 * breadth2; // calculating area directly
        System.out.println("Area of the second rectangle: " + area2);
    }
}

Third occurence

public class LayoutManager {
    public static void main(String[] args) {
        int length3 = 20;
        int breadth3 = 10;
        int area3 = length3 * breadth3; // calculating area directly
        System.out.println("Area of the third rectangle: " + area3);
    }
}

After the third occurrence, we notice we are repeating the same logic, so we should refactor the code and create a Rectangle class with a method to calculate the area.

public class Rectangle {
    private final int length;
    private final int breadth;

    public Rectangle(int length, int breadth) {
        this.length = length;
        this.breadth = breadth;
    }

    public int calculateArea() {
        return length * breadth;
    }
}
public class GeometryApp {
    public static void main(String[] args) {
        Rectangle rectangle = new Rectangle(10, 5);
        System.out.println("Area of the first rectangle: " + rectangle.calculateArea());
    }
}

public class DrawingApp {
    public static void main(String[] args) {
        Rectangle rectangle = new Rectangle(15, 10);
        System.out.println("Area of the second rectangle: " + rectangle.calculateArea());
    }
}

public class LayoutManager {
    public static void main(String[] args) {
        Rectangle rectangle = new Rectangle(20, 10);
        System.out.println("Area of the third rectangle: " + rectangle.calculateArea());
    }
}

Here you can see all classes are using the Rectangle class to calculate the area. In this way, the code looks more organized, and maintainable.

When Adding a Feature

Refactoring plays an important role and it really helpful when you try to understand someone else’s code. If you have to deal with messy code from someone else, clean it up first. It makes the code easier to understand not just for you, but also for those who use it after you.

When Fixing a Bug

When a developer encounters a bug in code, it’s like a bug in real life. Most bugs are encountered in messy and complicated code places. So clean your code, you might find the bugs just reveal themselves.

During a Code Review

The code review may be your last chance to clean it up before other people see it or use it. Try to do the review with the person who wrote the code can help. You can check how much effort you have to do to fix those problems. Even you can fix small problems right away.

What is Code Smells

Code smells are like indicators of problems or symptoms in the code that possibly indicate a deeper problem, hinting at the need for refactoring. Code smells are signs of poor coding, but they are easy to spot and fix. Such as long methods, duplicated code (As we discussed in the example of Rule of Three), and inconsistent naming. In this course, I will explain a lot of code smells and tell you how to handle code smells in Java.

What is Technical Debt

Every developer tries to write excellent code. But at what point of time does the clean code become messy code? When a developer takes shortcuts and easy solutions instead of using a better approach that would take longer. It leads to technical debt and that is more difficult to understand and maintain. A developer can temporarily speed up with an unstable/quick approach, but it will gradually slow your work every day. You can identify the tech debt in our code and target them to refactor. Here I explained it in a separate post you can read from here.

Techniques for refactoring in software engineering

Refactoring techniques have their own pros and cons. Here we will discuss all the refactoring techniques.

Clean code

The primary objective of refactoring is to fight technical debt and code smells. It changes the messy code into clean code and simple design.

What are the features of clean code?

  • A clean code always has good names for variables, specific classes, and methods based on their operations.
  • Clean code doesn’t contain duplication.
  • Clean code has few classes and other components.
  • Clean code passes all checks.
  • Clean code is less expensive and simpler to look after!

Objectives/Goals of Refactoring

  • Enhance Code Quality
    Refactoring improves the code quality and improves readability, maintainability, and extensibility. It allows the developer to understand and augment the code effectively, leading to better and sustainable software architecture.
  • Reduce Complexity: As we know refactoring helps in simplifying the codebase by splitting complex classes and methods. It breaks the complicated part of code into simple code so that everyone can understand and work on it.
  • Remove Redundancies: Refactoring gives the chance to clean up your code and remove all duplication codebase.
  • Optimize Performance: As we know tech debt can slow down performance, so refactoring ensures that the software runs optimally by improving algorithm efficiency, and reducing memory consumption.
  • Uncover and Rectify Bugs: While cleaning up the code up the code, we often find and fix the code mistakes that can be a bug.

Recommendations for Effective Refactoring

  • Ensure Comprehensive Automated Testing
    In refactoring, we change the internal code structure, not the functionality. So before moving to refactoring, it is good if you establish robust automated testing frameworks to monitor any alterations in external behavior. We have to check all areas of our application to make sure we didn’t break anything while making changes.
  • Make Changes Incrementally: I would suggest changing things bit by bit which means making small changes one at a time. Multiple or large changes can make new mistakes in code.
  • Use Helpful tools: Use some good IDE that can help you to react more easily like IntelliJ IDEA or Eclipse, which offer substantial support and automation for various refactoring tasks.
  • Regularly Perform Code Reviews Post-Refactoring: You have to maintain a regular schedule of code reviews. After changing the code, you should create a post review and keep the person in review who is familiar with the code or functionality.

Leave a Comment