DEV Community

Cover image for Simplify your code
Jimmy Klein
Jimmy Klein

Posted on

Simplify your code

Over the years, I have become very interested in clean code, calisthenics objects, 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.

// If the user is at least 18 years old
if ($user->getAge() >= 18) {
    ...
}
Enter fullscreen mode Exit fullscreen mode

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.

// If the user is an adult
if ($user->getAge() > 18) {
    ...
}
Enter fullscreen mode Exit fullscreen mode

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
if ($user->getAge() >= ADULT_AGE) {
    ...
}
Enter fullscreen mode Exit fullscreen mode
  • Extract the test into a function
if (userIsAdult($user)) {
    ...
}
...
...
function userIsAdult(User $user) {
    return $user->getAge() >= ADULT_AGE;
}
Enter fullscreen mode Exit fullscreen mode

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
if ($user->isAdult()) {
    ...
}
...
...
class User
{
    private $age;

    const ADULT_AGE = 18;
    ...
    public function isAdult()
    {
        return $this->age >= self::ADULT_AGE;
    }
}
Enter fullscreen mode Exit fullscreen mode

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:

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;
    }
}
Enter fullscreen mode Exit fullscreen mode

Now:

class User
{
    public function __construct(
        private string $name,
        private string $firstName,
        private int $age)
    {
    }

    public function isAdult(): bool
    {
         return $this->age >= self::ADULT_AGE;
    }
}
Enter fullscreen mode Exit fullscreen mode
  • 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

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

  • Passing parameters directly into the constructor. Instead of :
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) {...}
}
Enter fullscreen mode Exit fullscreen mode

I do

class User
{
    public function __construct(
        private string $name,
        private string $firstName,
        private int $age)
    {
    }
}
Enter fullscreen mode Exit fullscreen mode
  • 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
if ($user->getAge() > 18) {
   ...
}
Enter fullscreen mode Exit fullscreen mode

After

class User
{
    ...

    public function isAdult(): bool
    {
        return $this->age >= self::ADULT_AGE;
    }
}
Enter fullscreen mode Exit fullscreen mode

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, here is the kind of code I used to write before:

public function doubleAllValue(array $numbers)
{
    $result = [];
    foreach ($numbers as $number) {
        $result[] = $number * 2;
    }

    return $result;
}
Enter fullscreen mode Exit fullscreen mode

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:

public function doubleAllValue(array $numbers)
{
    return array_map(function($number) {
        return $number * 2;
    }, $numbers);
}
Enter fullscreen mode Exit fullscreen mode

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.

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

    return $canDriveACar ;
}
Enter fullscreen mode Exit fullscreen mode

The use of early return will allow:

  • Reduce code indentation
  • To remove the else
  • To have more readable code
function canDriveACar(User $user)
{
    if ($user->isAdult()) {
        return true;
    }

    if ($user->learnInAccompaniedDriving) {
        return true;
    }

    return false;
}
Enter fullscreen mode Exit fullscreen mode

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 for more PHP tips.

Header photo by Artem Sapegin on Unsplash

Top comments (9)

Collapse
 
pedrorfpacheco profile image
Pedro Pacheco

I like your approach to the comment section. Depending on the problems, I either use the constant with a name that I can clearly understand or I extract it into a function that I test.

Regarding the "early return" topic, it was one of the first things I learned in the professional world and it really makes sense and optimizes the process.

Collapse
 
klnjmm profile image
Jimmy Klein

Thanks for your comment !

About early return, I don’t know nowdays how the « one return only » is teached at school, but it’s a shame to learn early return in the profession l world…

Collapse
 
xwero profile image
david duymelinck • Edited

Great article!

side node: I would not let anyone that is an adult drive a car. There are already enough accidents with drivers that have a drivers license :)

Collapse
 
klnjmm profile image
Jimmy Klein

🤣

Collapse
 
sreno77 profile image
Scott Reno

This is good information!

Collapse
 
klnjmm profile image
Jimmy Klein

Thank you 🙏

Collapse
 
iwane021 profile image
iwanprs

thank you for sharing

Collapse
 
madalitsonyemba profile image
Madalitso Nyemba

Insightful 💯

Collapse
 
kriqn profile image
KriqN • Edited

Nice article!

About the "early return" - most of the time there are more things to check (fail) before reaching the "happy path" and that's why it is usually placed at the end of the method. Your example should looks like:

function canDriveACar(User $user): bool
{
    if (! $user->isAdult()) {
        return false;
    }

    if (! $user->learnInAccompaniedDriving) {
        return false;
    }

    return true;
}
Enter fullscreen mode Exit fullscreen mode