What is Refactoring and How Do We Do It?

As we maintain a code base for a long time it tends to get harder to read and in turn harder to maintain. This is generally because we rush to add new features and fix bugs and don’t take time to clean up our code and make it easier to maintain in the future. Eventually, we run into a situation where any change to the code is a headache and progress grinds to a halt.

In this article, we’ll discuss why we need to use refactoring to make our code easier to maintain and a couple of methods to get us started refactoring today.

What Is It and Why Would We Do It?

Refactoring is the process of restructuring existing code without changing its external behavior. This refactoring process can be used to remove duplicate code or just make it easier to read with the end goal of being able to quickly add new features and fix bugs.

Ideally, we would be using Test Driven Development (TDD) to make all of the changes in our application. Part of the TDD cycle involves looking at the code we’ve created and removing any duplicate code. This process of removing duplication is refactoring.

There’s also a good deal of refactoring that should occur as features are removed from our application. This tends to get missed but removing features can create lots of dead code paths. Taking a breath and refactoring as we remove features allows us to reduce the chance of that happening.

How Do We Do It?

Unit tests are the foundation for making sure our refactorings don’t change the behavior of our code. If we’re working with an application that has 100% code coverage we can easily make changes to the internal structure of the code and be sure it’s still going to operate the same way.

If we’re not working with 100% code coverage this can be a little more tricky so the process we recommend is the following.

  1. Comment out the section of the code that is going to be refactored
  2. Run all the tests to make sure at least one test failed
  3. If no tests failed create a new test to test the commented out code
  4. Perform the refactoring
  5. Run our tests and make sure they all pass

We’ll see “Run our tests and make sure they all pass” come up over and over again because it’s so important.

Basic Refactoring Techniques

The book “Refactoring” by Martin Fowler is an excellent source for refactoring techniques and common “code smells” (things that seem wrong and should be cleaned up) to get us started in refactoring. Some of them are a little esoteric but we think a lot can be done with just five basic techniques.

Extract Function (Method)

The first technique is “Extract Function”. In this technique, we take a section of code and make it it’s own method. This should be done when we have code that’s duplicated in multiple places or when we can isolate a portion of a larger method so the larger method becomes easier to read.

This is by far one of the refactorings that has the biggest benefit when it comes to code readability. Especially for breaking up long and complex methods.

To perform this refactoring in PHP:

  1. Copy the section of code we’re extracting and then paste it into a new method
  2. Look for any local variables and add them as parameters to the method
  3. Replace the extracted code with a call to the newly created method
  4. Run our tests and make sure they all pass
  5. Look for places where we can use the newly extracted method

Remove Flag Argument

A flag argument is when we have an argument to a method that the caller uses to indicate the logic that should occur in the method. This is a bad design because it forces the programmer reading the calling code to have to stop what they’re doing and read what the method is doing.

To perform this refactoring we’ll:

  1. Create a new method for each value of the flag argument
  2. Replace the calls to the old method with one of the new methods
  3. Delete the original method
  4. Run our tests and make sure they all pass

Extract Variable

Extract variable is used when we have a complex expression that is hard to read. By separating the portions of the expression into individual variables it can be easier to read.

To perform this refactoring we’ll:

  1. Ensure that the expression we’re working with has no side effects.
  2. Create a local variable with the expression we’re extracting
  3. Replace the original expression with the new variable
  4. Run our tests and make sure they all pass

Rename Method

Clearly naming things is the way to make our code as clear as possible and as we modify our code we’ll run into situations where the method is no longer doing what it says it does or the name of the method is hard to understand. By renaming the method we can make our code easier to read and thus easier to maintain.

To perform this refactoring in PHP we’ll:

  1. Check to see if the method is defined in a superclass or subclass. If the method is defined in either we’ll need to repeat these steps in those classes.
  2. Duplicate the existing method but with the new name.
  3. Change the old method so its body just calls the new method.
  4. Find all the references to the old method and replace them with the new method
  5. Delete the old method
  6. Run our tests and make sure they all pass

Pull Up Method

As we’re working with class hierarchies we’re going to run into situations where we find duplicate methods and it’s best if we move them into a superclass to reduce duplication. To do this we can “pull up” the method into a superclass.

To perform this refactoring in PHP we’ll:

  1. Check that all methods are identical.
  2. Check that any methods called and attributes accessed by the method are accessible in the superclass.
  3. Copy one version of the method into the superclass
  4. Run our tests and make sure they all pass
  5. Delete one of the copies in a subclass
  6. Run our tests and make sure they all pass
  7. Repeat steps 5 and 6 until all the copies are gone.

Have Fun!

Refactoring is one of the key concepts that will allow us to create more maintainable code. These methods outlined in this article are a good starting point but aren’t the end of our journey in learning how to refactor our code.