.

What are the Refactoring Techniques and Tools You Should Use?

Refactoring is a process of changes that ultimately allows you to achieve code that is readable, easy to develop, and maintain. During these improvements, its behavior shouldn’t change. Therefore, you should approach the subject with a lot of caution and consideration.

Refactoring techniques

There are many specific ways to refactor individual elements of an application. The selection of appropriate techniques for the problem under consideration is key to the optimal execution of the process. One of the basic rules to follow is that the code after refactoring must be cleaner, and all tests must pass. Then again, new functionalities should absolutely not be introduced during the process.

Refactoring techniques are numerous, or even very numerous. In this article, we’ll list a few of them. Not every method is applicable to all programing languages. Refactoring techniques are divided into groups depending on the problem they solve.

Extracting, composing, and simplifying methods and calls

If your code contains long, complicated, and difficult to maintain methods and a lot of responsibilities, this group of refactoring techniques will help you clean it up.

Extracting the method

If the method is long and difficult to understand, the specific groupable part should be separated and transferred to a separate method.

Before refactoring:

public function printVariables() {
  $this->printFoo();

  print "bar: " . $this->bar;
  print "foobar: " . $this->foobar;
}

After refactoring:

public function printAll() {
  $this->printFooRelated();
  $this->printBarRelated();
}

public function printBarRelated() {
  print “bar: “ . $this->bar;
  print “foobar: “ . $this->foobar;
}

Extracting the variable

During the refactoring process, we may encounter complex expressions that can be difficult to understand at first glance. In this case, we try to separate individual parts of the expression and transfer them to variables.

Before refactoring:

if ($item->isPriceSet() && $item->getPrice() <= 100 && $user->isUserLoggedIn() && $this->isUserAllowedToBuy()) {
  $this->redirectToBuyForm();
}

After refactoring:

$isUserAllowed = $user->isUserLoggedIn() && $this->isUserAllowedToBuy();
$isPriceAcceptable = $item->isPriceSet() && $item->getPrice() <= 100;

if ($isUserAllowed && $isPriceAcceptable) {
  $this->redirectToBuyForm();
}

Inline method

If a method is used only once, it’s small and its content says more than the method itself, we can consider transferring the content of the method to the place where it’s called.

Before refactoring:

public function getFoo() {
  return $this->bar() ? self::FOO : self::FOOBAR;
}

public function bar() {
  return $this->foo === ‘bar’;
}

After refactoring:

public function getFoo() {
  return $this->foo === ‘bar’ ? self::FOO : self::FOOBAR;
}

Moving features between objects

If there is a method in the refactored functionality that is used more often in another functionality, you should transfer the method to the class that uses it the most. If it’s a method that is used in many places - and the class that implements it also contains other responsibilities - you should separate the method into a distinct class. If the task of a given method is only to call another method, we call it Middle Man, its value is zero and we should delete it.

Data organization

This category includes all refactoring methods that focus on code organization. Using the methods contained in this section makes the code more readable and better organized.

Field encapsulation

All public fields of a class should be converted to private ones unless there is a good reason not to do so. Access to writing and reading its values should be done using getters and setters.

Before refactoring:

class Foo {
  public $bar;
}

After refactoring:

class Foo {
  private $bar;

  public function getFoo() {
    return $this->bar;
  }

  public function setFoo($value) {
    $this->bar = $value;
  }
}

Replacing magic numbers with constants

For developers writing the functionality, some part of it may be obvious, but it will cease to be so after a few months. This is important to remember when writing the code. Many people forget about it and leave strings and numbers in the code in a primitive form, which prevents new people from fully understanding the code. During the refactoring process, all the "magic numbers" should be replaced with constants, with concise but descriptive names.

Before refactoring:

class Foo {
  public function isUnderLimit() {
    return $this->bar <= 20; 
  }
}

After refactoring:

class Foo {
  const BAR_LIMIT = 20;

  public function isUnderLimit() {
    return $this->bar <= self::BAR_LIMIT; 
  }
}

Refactoring tools

There are a number of tools available to help you with the refactoring process. Familiarize yourself with the functionality available in your code editor. Many of the new IDEs have tools like this built-in or available as free plug-ins. Other helpful features that allow you to write better code are:

  • code sniffers - verify code compliance with standards,
  • static code analyzers - statically analyze the behavior of the code and allow you to pick up errors before running the code.

In the PHP programming language, the most common ones are php_codesniffer and phpstan.

Refactoring techniques - summary

The code refactoring process must be properly planned and preceded by a series of actions to optimize it. These tools and techniques, combined with an understanding of which parts of the application are problematic, will ensure that refactoring is done holistically and correctly. The tools and techniques we presented here are only an outline of solutions developed by the entire software development community. If you need help with selecting these types of solutions and carrying out the refactoring process, we can take care of this within PHP development.