Reducing technical debt in PHP project: EASY way

Reducing technical debt in PHP projects is crucial for ensuring long-term success. Technical debt can negatively impact project quality, leading to sneaky bugs and higher costs. Additionally, it limits flexibility and scalability, making it challenging to adapt to new requirements.

Dealing with technical debt

Developing IT projects can be tough, with plenty of problems that can pop up along the way. One big challenge is handling technical debt, which can cause lots of issues in a project.

In this blog post, we’ll look at how technical debt can influence the (PHP) project. By understanding these downsides, we can take steps to minimize technical debt and make sure our IT projects succeed in the long run.

Lower quality

Technical debt messes up project quality, leading to some bad consequences. It can cause sneaky bugs that are hard to find and fix, making the user experience pretty lousy. Nobody likes that!

Higher costs

Technical debt can make projects cost more in the long term. Fixing bugs and other problems caused by technical debt takes a lot of time and money. It’s a real drain on the project’s budget and resources.

Less flexibility

Technical debt also makes projects less flexible. When developers take shortcuts during development, it restricts their ability to make changes or add new features later on. This means the project can’t adapt well to new requirements or market demands.

Limited scalability

Technical debt messes with a project’s scalability, making it hard to handle a growing user base. When there’s technical debt, scaling up the project to meet the needs of more users becomes a real challenge. It can lead to a lot of performance issues and a not-so-smooth experience for users.

Conclusion? Build a solid foundation for IT project success

To make sure our IT projects succeed in the long run, we need to take action to minimize technical debt from the start. By focusing on smart development practices, doing regular code reviews, and setting aside time to improve our code, we can reduce technical debt and set our projects up for success.

🤔But what if it’s too late and we remained with a bunch of legacy code?

Reducing technical debt: Introducing Re(fa)ctor

The answer to the question posed earlier is to use the Rector tool.

Rector is a PHP tool designed to automate and simplify the process of code refactoring in PHP applications. It uses static code analysis techniques to identify patterns and code smells in PHP code. It provides a set of predefined rules and transformations that can be applied to automatically refactor the codebase. These rules cover a wide range of scenarios, such as:

  • renaming variables
  • updating deprecated functions
  • converting procedural code to object-oriented code
  • many more…

Installation

First, you have to install the package via composer:

composer require rector/rector --dev

Secondly, create a rector.php configuration file by command

vendor/bin/rector

Generated file:

// rector.php
return static function (RectorConfig $rectorConfig): void {
(...)
};

Configuration

In the configuration file rector.php you have access to RectorConfig class which exposes handy methods which we’ll discuss here.

Input data

To specify paths for files to check use paths(array $paths) method.

$rectorConfig->paths([
__DIR__ . '/src',
__DIR__ . '/tests',
__DIR__ . '/src/SingleFile.php',
]);

Apply rules

The list of 500+ rules is available in the Rector documentation here.

To apply the specific rule use rule(string $rectorClass) or rules(array $rectorClasses) methods.
If the rule needs specific configuration simply use ruleWithConfiguration(string $rectorClass, array $configuration).

use Rector\CodeQuality\Rector\Class_\InlineConstructorDefaultToPropertyRector;
use Rector\Privatization\Rector\Class_\FinalizeClassesWithoutChildrenRector;
use Rector\Renaming\Rector\Name\RenameClassRector;
// Apply many rules
$rectorConfig->rules([
InlineConstructorDefaultToPropertyRector::class,
]);
// Apply single rule
$rectorConfig->rule(FinalizeClassesWithoutChildrenRector::class);
// Configure single rule
$rectorConfig->ruleWithConfiguration(RenameClassRector::class, [
'App\SomeOldClass' => 'App\SomeNewClass',
]);

Choosing the right rules can be a tedious task. There are predefined sets of rules though, which are available in the \Rector\Set\ValueObject\SetList class. If you’re working with the Symfony framework, you can also use \Rector\Symfony\Set\SymfonySetList.

To apply specific sets, simply use the sets(array $sets) method!

use Rector\Set\ValueObject\SetList;
use Rector\Symfony\Set\SymfonySetList;
// Example sets
$rectorConfig->sets([
SetList::DEAD_CODE,
SetList::PHP_82,
SetList::NAMING,
SetList::PRIVATIZATION,
SymfonySetList::SYMFONY_62,
SymfonySetList::SYMFONY_CONSTRUCTOR_INJECTION,
SymfonySetList::SYMFONY_CODE_QUALITY,
(...)
]);

Skip rules

If for some reason you don’t want to use a particular rule that is available from the SetList, there is a possibility to skip it by using a skip(array $criteria) method.

use Rector\Php82\Rector\Class_\ReadOnlyClassRector;
$rectorConfig->sets([
SetList::PHP_82,
]);
// Skip rule applied by SetList::PHP_82
$rectorConfig->skip([
ReadOnlyClassRector::class,
]);

Dealing with FQCN imports

To increase code readability with importing classes by using shorter use syntax, the importNames() method comes with help!

// Simply use this method in rector.php
$rectorConfig->importNames();

// Before changes
$productRepository = new \App\Product\Repository\CustomProductRepository();
// Refactor results
use App\Product\Repository\CustomProductRepository;
$productRepository = new CustomProductRepository();

Execute

To make Rector work, use the process command:

vendor/bin/rector process [path] [--dry-run]
  • path – optional; if not specified, Rector will check files specified by the paths() method in the configuration
  • –dry-run – optional; if specified, Rector will display changes that it would apply without this flag and will not alter the files

The Three Musketeers of Continuous Integration

Continuous Integration (CI) is an essential part of software development that enables developers to identify and resolve issues early in the development process. By integrating tools such as EasyCodingStandard, PHPStan, and mentioned Rector into your CI pipelines, you can streamline your development process and improve code quality.

Summary

In this article, we explored the significance of reducing technical debt in PHP projects to ensure their long-term success. Technical debt can adversely affect project quality, increase costs, limit flexibility, and hinder scalability. To overcome these challenges, we introduced the Rector tool – a powerful PHP solution for automating code refactoring.
Remember that proactive management of technical debt is crucial for delivering seamless user experiences, staying within budget, and accommodating future growth.

NEED HELP?

Discover how our experts optimize PHP projects for success. Get tailored solutions and guidance to reduce technical debt and elevate outcomes.

Table of Contents