Simplify your code
Tags: webdev, codequality, php
Published: 2024-03-08 12:00:38

Over the years, I have become very interested in clean code, [calisthenics objects](https://dev.to/klnjmm/9-rules-for-writing-better-code-3lb), etc. And over time, readings, videos, discussions and katas, my writing of code has changed: less superfluous, more meaningful code (at least for me 😇) and a desire to go to the 'essential. So here is what has evolved in my way of approaching code.

_The examples in this article are in PHP, but most of what I describe below is applicable to all languages._

---

## Comments

Commenting on your code can be useful, but it must be done for the right reasons. A comment should say why it was done like that and not what the code does.

```php
// If the user is at least 18 years old
if ($user->getAge() >= 18) {
    ...
}
```

This comment is completely useless, it is a literal copy of the `if` statement which can surely make you smile. But I used to write this kind of comment and I wasn't the only one (you just had to see the codebase of the project I'm working on some time ago). Look in your codebase, I'm sure you'll find some.

```php
// If the user is an adult
if ($user->getAge() > 18) {
    ...
}
```

This comment tells us a little more about what this instruction tests, but I think we can do even better and remove this comment. Many solutions :

* Put a constant in place of `18`
```php
if ($user->getAge() >= ADULT_AGE) {
    ...
}
```

* Extract the test into a function
```php
if (userIsAdult($user)) {
    ...
}
...
...
function userIsAdult(User $user) {
    return $user->getAge() >= ADULT_AGE;
}
```
This method is useful if you have **a fairly complicated test with a sequence of conditions**. Instead of putting a comment, **try naming your test and extracting it into a function.**

* Ensure that this test is done directly in the object code
```php
if ($user->isAdult()) {
    ...
}
...
...
class User
{
    private $age;
    
    const ADULT_AGE = 18;
    ...
    public function isAdult()
    {
        return $this->age >= self::ADULT_AGE;
    }
}
```

---

## PHPDoc

PHP is becoming more and more typed, and honestly I've never had to extract the PHPDoc from my projects. From now on for my personal projects, I no longer generate the PHPDoc of my functions. To return to my `User` class:

Before:
```php
class User
{
    private $name;
    private $firstName;
    private $age;
    
    /**
     * User constructor
     * @param string $name;
     * @param string $firstName;
     * @param int $age;
     */
    public function __construct($name, $firstName, $age)
    {
        $this->name = $name;
        $this->firstName = $firstName;
        $this->age = $age;
    }
    
    /**
     * Indique si l'utilisateur est adulte
     * @return bool
     */
    public function isAdult()
    {
         return $this->age >= self::ADULT_AGE;
    }
}
```

Now:
```php
class User
{
    public function __construct(
        private string $name,
        private string $firstName,
        private int $age)
    {
    }
    
    public function isAdult(): bool
    {
         return $this->age >= self::ADULT_AGE;
    }
}
```

* **The names of the methods are quite self-explanatory**, no need to describe them (especially when we see the comments generated by the IDE like `User constructor`!)
* **The constructor parameters are typed**, the IDE can very well indicate the type of each parameter
* The return type of the method is **directly in the code**
* And the advantage is that if one day a parameter or a return type has to change, **there is no risk of forgetting to update the PHPDoc**. (because yes, the problem with comments is that over time, they no longer correspond to the code below, due to forgetting to update 😕)

---

## Getter and setter

The IDE can be very convenient, but can also lead to bad habits. Automatic generation of a class's getter and setter is a good example. We don't know if we're going to need them, but we're going to generate them anyway.

![Generating automatically getter and setter](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/45h1zyy11ogmg3qj65pk.jpg)

I now try to create the minimum possible getter/setter (if not none if possible):

* Passing parameters directly into the constructor. Instead of :
```php
class User
{   // The constructor is empty for the example
    public function __construct() {}
    
    public function setName(string $name) {...} 
    public function setFirstName(string $firstName) {...}
    public function setAge(int $age) {...}
}
```
I do 
```php
class User
{
    public function __construct(
        private string $name,
        private string $firstName,
        private int $age)
    {
    }
}
```

* The object itself can have its own business rules. Taking the example from the beginning of the article on the age of the user:
Before
```php
if ($user->getAge() > 18) {
   ...
}
```
After
```php
class User
{
    ...
    
    public function isAdult(): bool
    {
        return $this->age >= self::ADULT_AGE;
    }
}
```

---

## Temporary variables

Like any developer, I learned to do `for`/`foreach`/`while` loops. And most often this included the creation of temporary variables. If I take the first example from my [Refactoring with Collection article](https://dev.to/klnjmm/never-write-another-loop-again-3np0), here is the kind of code I used to write before:
```php
public function doubleAllValue(array $numbers)
{
    $result = [];
    foreach ($numbers as $number) {
        $result[] = $number * 2;
    }

    return $result;
}
```

We have a temporary variable here. If I use the definition from Wikipedia:

> In computer programming, a temporary variable is a variable with short lifetime, usually to hold data that will soon be discarded, or before it can be placed at a more permanent memory location. Because it is short-lived, it is usually declared as a local variable, i.e., a variable with local scope.

And now here is what I usually write:
```php
public function doubleAllValue(array $numbers)
{
    return array_map(function($number) {
        return $number * 2;
    }, $numbers);
}
```

The use of temporary variables can be practical in certain debugging cases, on a case-by-case basis depending on the complexity of the code.

---

## Early return

During my studies, I was taught that a method must have only one output. But over the years, I realized that it was possible to use early returns to improve the readability of the code.

```php
function canDriveACar(User $user): bool
{
    $canDriveACar = null;
    if ($user->isAdult()) {
        $canDriveACar = true;
    } else {
        if ($user->learnInAccompaniedDriving) {
            $canDriveACar = true;
        } else {
            $canDriveACar = false;
        }
    }

    return $canDriveACar ;
}
```

The use of early return will allow:

* **Reduce code indentation**
* To **remove the `else`**
* To have **more readable code**

```php
function canDriveACar(User $user)
{
    if ($user->isAdult()) {
        return true;
    }
    
    if ($user->learnInAccompaniedDriving) {
        return true;
    }
    
    return false;
}
```

---

Our practice evolves over the years, sometimes with good ideas, sometimes not so good ones (but we realize it much later!). 

**What has changed in the way you code over the years? Let's discuss it in the comments.**


## Thank you for reading, and let's stay in touch !

If you liked this article, please share. Join me also on [Twitter/X](https://twitter.com/enjimmyklein) for more PHP tips.


_Header photo by [Artem Sapegin](https://unsplash.com/@sapegin?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash) on [Unsplash](https://unsplash.com/photos/turned-on-macbook-air-displaying-coding-application-b18TRXc8UPQ?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash)_