Code Refactoring: Turning Good Code into Great Code

Alya Azhar Agharid
8 min readMar 17, 2023

--

Photo by Blake Connally on Unsplash

Refactoring is a technique used to enhance the quality of previously produced code. The goal of improvisation is to restructure and optimize code without fundamentally altering the resulting behavior. Refactoring makes it easier to comprehend, write, and maintain software that is constantly expanding and under constant project management, thereby raising the product’s overall quality.

Refactoring is a software development approach that seeks to increase the quality of previously created code. The goal of improvisation is to restructure and optimize code without fundamentally altering the resulting behavior. Refactoring makes our code easier to read, write, and maintain software that is constantly expanding and being worked on by various parties, thereby raising the product’s overall quality.

Refactoring by Martin Fowler

Martin Fowler is a well-known software engineer and author, and he is widely credited with popularizing the concept of refactoring in the software development community.

Refactoring, as defined by Martin Fowler, is the process of improving the design and quality of an existing codebase without changing its external behavior. It involves making modifications to the internal structure of the code to improve its readability, maintainability, and scalability while preserving its overall functionality.

The main goal of refactoring is to make the codebase more manageable and easier to work with, while reducing the risk of introducing new bugs or unintended side effects. This is achieved by breaking down large and complex functions into smaller, more focused ones, removing duplicate code, simplifying control flow, and eliminating unnecessary dependencies.

Refactoring is an iterative process that can be performed on any part of the codebase, from individual functions to entire systems. It should be done regularly as part of the software development lifecycle to keep the codebase clean and maintainable, and to avoid the accumulation of technical debt.

The Need of Refactoring

As was previously stated several times, the primary goals of structuring code without altering its functionality are to improve design, increase code readability, and decrease complexity.

Even more details upon that necessity of refactoring is given below:

  1. Improved Code Quality
    Makes the code easier to understand and read because the goal is to simplify code and reduce complexities.
  2. Maintainability, Spot Bugs!
    Makes it simpler to find bugs and make additional modifications while improving maintainability.
  3. Know your Code Better
    A deeper comprehension of coding. Developers must consider how their code will interact with existing code in the code base.
  4. Focus: Functionality
    Functionality is the main focus. The original project will remain within its intended scope if the functionality of the code is left untouched.
  5. Better Performances
    By optimizing code, reducing redundancy, and eliminating unnecessary code. This can lead to faster execution times code and improved efficiency.
  6. Easy to Collaborate
    With the code already refactored, it is easier to understand and collaborate together, because the code is already well-organized and follows its best practices. It’s easier to other people to work on different parts in code and integrate the change without causing conflicts or introducing bugs.
  7. Cost Effective
    Refactoring save time and money by reducing time and effort required to maintain and modify code by reducing the risk of bugs, this also reduce the cost of fixing the problem and potential impact for users.

When Should Refactoring

Refactoring can be performed after the product has been deployed (basically as part of day-after programming). But here’s the situation when we might want to consider refactoring our code:

Based on Refactoring Guru, there are several conditions:

  1. Rule of Three
    — When doing something for the first time, just get it done first.
    — When something similar for second time, repeat it.
    — When it’s the third time, start refactoring.
    It means that if we have code that are repeating for the same written code 3 or more times, we should immediately refactor the code.
  2. Adding A Feature
    If we have to deal with other’s dirty code, clean it up or refactor it first. It helps to easier ourselves later or the people after us. And also when the code is clean, it’s easier to add new feature.
  3. Fixing Bug
    Cleaning the dirty code will make us easier to find the bugs and errors themselves.
  4. Code Review
    The code review phase happens before the code is available to the public.

In other situations also including Performance Issues: If your code is running slowly, refactoring can help improve performance by optimizing algorithms or data structures.

Refactoring Techniques

There are A LOT of refactoring techniques, see this. But here are some examples of some refactoring techniques that usually happened in our code unconsciously:

1 — Extract Method

The problem that can we solve with this technique is when we have a code fragment that grouped together which particularly has a different function. We need to refactor after finding this problem because the more lines in a method or function will makes us harder to figure out what the function of the method does.

The solution is with separating the method or function into different method, also replacing the old code with a call function/method to the other one. Here is the example of the code below:

Before refactoring:

@login_required(login_url='login')
def dashboard_verif(request, id:int, action:str):
user = requests.user
if user.role_id == 3 or user.role_id == 4:
lowongan_obj = Lowongan.objects.get(role_id = id)
if action == "verifikasi":
# do method for verifikasi
elif action == "tolak":
# do method for tolak
else
# do for unrecognize method
return render(request, "dashboard_proposal.html")

After refactoring:

@login_required(login_url='login')
def dashboard_tolak(request, id:int, action:str):
user = requests.user
if user.role_id == 3 or user.role_id == 4:
lowongan_obj = Lowongan.objects.get(role_id = id)
# do method for verifikasi
return render(request, "dashboard_proposal.html")

@login_required(login_url='login')
def dashboard_tolak(request, id:int, action:str):
user = requests.user
if user.role_id == 3 or user.role_id == 4:
lowongan_obj = Lowongan.objects.get(role_id = id)
# do method for tolak
return render(request, "dashboard_proposal.html")

2 — Inline Method

The problem that can we solve with this technique is when we have a code in the method body is more obvious then the method itself. We need to refactor after finding this problem is because there will produce many such methods and confusing if the method is not really that important and too short.

The solution is to replace the calls to this method with its content and delete the method itself. Here is the example of the code below:

Before refactoring:

class Lowongan:
# ...
def close_lowongan(self):
return "Lowongan berhasil ditutup" if is_applicant_full() else "Belum mencukupi pendaftar"

def is_applicant_full(self):
return if self.applicant > self.max_applicant

After refactoring:

class Lowongan:
# ...
def close_lowongan(self):
return "Lowongan berhasil ditutup" if self.applicant > self.max_applicant else "Belum mencukupi pendaftar"

3 — Rename Method/Variable

The problem that can we solve with this technique is when we have an unexplainable name of the method or variables. We need to refactor after finding this problem because poorly named variables/methods is such not good descriptor and make the readers of the code feel unease to understand the code.

The solution is to rename the method/variables into a descriptive one. Here is the example of the code below:

Before refactoring:

@login_required(login_url='login')
def respdash(request):
u = requests.user
if u.role_id == 3 or u.role_id == 4:
# display dashboard

@login_required(login_url='login')
def respver(request):
u = requests.user
if u.role_id == 3 or u.role_id == 4:
# display dashboard verifikasi

After refactoring:

@login_required(login_url='login')
def dashboard_response(request):
user = requests.user
if user.role_id == 3 or user.role_id == 4:
# display dashboard

@login_required(login_url='login')
def verifikasi_response(request):
user = requests.user
if user.role_id == 3 or user.role_id == 4:
# display dashboard verifikasi

4 — Replace Magic Number with Symbolic Constant

The problem that can we solve with this technique is when we have a random or magic number that use in code. We need to refactor after finding this problem is because the magic number appears without obvious meaning. The refactoring process will improve the readability of the code so that the magic number will be more descriptive.

The solution is to replace the random magic number with a constant that has descriptive explaining meaning of the number as the constant variable name. Here is the example of the code below:

Before refactoring:

def ind_phone_validate(phone):
if len(phone) in val_length:
if int(str(phone)[:2]) == 62:
# validate

After refactoring:

IND_NUMBER = 62
def ind_phone_validate(phone):
if len(phone) in val_length:
if int(str(phone)[:2]) == IND_NUMBER :
# validate

5 — Replace Temp with Query

The problem that can we solve with this technique is when we have an expression in local variable that will use later in our code. We need to refactor after finding this problem is because it also has groundwork applying Extract Method and separating the same expression on repeating.

The solution is move the entire expression into other separate method and return the result from it. Here is the example of the code below:

Before refactoring:

def count_salary_total(employee):
salary = hour*price
if employee.status == "junior":
return salary + 25000
elif employee.status == "senior":
return salary + 100000
else:
return salary + 5000

After refactoring:

def count_salary_total(employee):
if employee.status == "junior":
return salary.formula() + 25000
elif employee.status == "senior":
return salary.formula() + 100000
else:
return salary.formula() + 5000

def salary_formula():
return hour*price

and… many more!

The Challenge

Overall refactoring is the process on making changes to the internal structure of code to improve its readability, maintainability, and scalability. It could be beneficial in the long term, but it super challenging!

  1. Risk of Introduce Bugs
    Change code means there is always risk on introducing bugs or breaking the existing functionality. It appears when doing refactoring is because it involves on changing the large portion of code. Without clear objectives, refactoring can lead to delays and extra work.
  2. Time-consuming
    When working on large codebase, it can be tome-consuming because it needs to have careful planning, testing, and validating to make sure that the changes do not impact the functionality of the code. This also will take extra time if a development team is in a rush and refactoring is not planned for.
  3. Resistance to Change
    If the developers have been working for a long time with the codebase, it has potential of resistance on changing the codebase
  4. Balancing Priorities
    Refactoring is important, but sometimes does it has more priority scale after delivering new features or fix critical bugs? What do you think?

Here, Let’s Sum Up!

Refactoring is the practice of enhancing an existing piece of code’s design and quality without altering its function. Refactoring enhances the readability, maintainability, and extensibility of the code and, in the long run/term, it helps reduce technical debt and speeds up development.

Refactoring should be done when the codebase becomes difficult to understand, modify, or maintain, or when new features need to be added. Refactoring however can be challenging, such as it may time consuming as well, particularly in large codebases with plenty of interdependent components.

Assuring that refactored code continues to behave correctly, preventing the introduction of new problems or regressions, and minimizing disruptions to existing development and testing procedures are a few common concerns. Therefore, it’s important to balance the potential benefits of refactoring with the costs and risks involved.

--

--

Alya Azhar Agharid
Alya Azhar Agharid

Written by Alya Azhar Agharid

girl who likes to read, write, and tell.

No responses yet