The importance of refactoring in code readability cover image

The importance of refactoring in code readability

Oziel Rea • March 25, 2024

clean-code

I'm back after a long time since my last post (and the first one), I have been very busy with my work and personal projects, but I have not forgotten about this blog.

Today I want to talk about the importance of refactoring in software development with some real examples I have faced in my career.

What is refactoring?

Okay, refactoring is a fancy word, but what does that mean? according to wikipedia:

Refactoring is the process of restructuring existing computer code without changing its external behavior, it is intended to improve nonfunctional attributes of the software. Refactoring is a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior.

So what I can get from this definition is that if we change some part of the code in order to improve it, but the external behavior of the code remains the same, we are good to go.

Why is refactoring important?

Refactoring is important because it helps us to understand the code better also it helps us to keep our code clean, but what does it mean to have clean code? I like some words on this from refactoring guru:

Clean code is obvious for other programmers...

Clean code doesn’t contain duplication...

Clean code is easier and cheaper to maintain!...

I love the part of "Clean code is obvious for other programmers", because we have to remember that we are writing code for humans to read, not for machines, you can write a mess of code but as long as it works, the machine doesn't care if is clean or not, but other programmers do.

Real examples

Okay too much theory, let's see some real examples of refactoring in code readability. Don't worry too much about the business logic, just focus on the method structure.

# Before
def period_in_force(main_periodicity, period, investment)
  main_periodicity.zero? &&
    period.id.present? &&
    ((period.id + 1) % investment.other_periodicity).zero?
end
# After
def period_in_force?(period, main_periodicity:, other_periodicity:)
  return false unless main_periodicity.zero?

  return false unless period.id.present?

  period.should_pay?(other_periodicity)
end

We even take advantage of the named arguments and the method naming in ruby to make the code more readable. so we can use the method like this:

# using the method
period_in_force?(period,
  main_periodicity: 1,
  other_periodicity: investment.other_periodicity)

Also, we took away the investment parameter because we need only the other_periodicity from investment, not the whole object. We also extracted some logic of the interval to a method called should_pay?

Let's see another example:

# Before
def next_payment
  payment = next_interest_payment
  other_kind_of_payment = next_interest_payment_of_other_kind
  return payment unless other_kind_of_payment.present?

  return other_kind_of_payment unless payment.present?

  aux_date = [other_kind_of_payment.date, payment.date].min
  if payment.date == aux_date
    return payment
  else
    return other_kind_of_payment
  end
end
# After
def next_payment
  payment = next_interest_payment
  other_kind_of_payment = next_interest_payment_of_other_kind

  return payment if other_kind_of_payment.nil?
  return other_kind_of_payment if payment.nil?

  [other_kind_of_payment, payment].min_by(&:date)
end

First, we changed the present? method to nil? because we only expect instances of a Period class or nil values, this allows us to change the unless condition to an if condition, which makes the code more readable in this specific case. We also removed the aux_date variable and used the min_by method to get the object with the minimum end_date value.

Okay this is good but I think we can go further, let's change the code a little bit more:

def next_payment
  [
    next_interest_payment_of_other_kind,
    next_interest_payment
  ].compact.min_by(&:date)
end

We removed the payment and other_kind_of_payment variables and used an array to store the values, then we used the compact method to remove the nil values from the array, and finally we used the min_by method to get the object with the minimum date value.

In closing

The examples I showed are very simple, but I hope you get the idea of how little changes can make a big difference.

There is no perfect code, we can always improve it, and refactoring is a great way to do that, so don't be afraid to broke things but remember to have automated tests! 😅

I'd love to hear your thoughts on this, do you have any refactoring tips? let me know, get in touch with me on my contact page.