7 Laravel programming habits help you reduce bugs in your code

The article was forwarded from the professional Laravel developer community. Original link: https://learnku.com/laravel/t...

Every line of code we add to a project increases its complexity and the potential for bug s at any time. It could be a few minutes before the client's meeting, or it could be that we are not in front of our keyboard during the weekend in the cinema.

To prevent those terrible situations, let's write better code through the following seven techniques:
 

1. Specify descriptive names for variables, functions, parameters, and methods:

The code is written only once, but will be read and interpreted many times by other developers and you. Therefore, it's worth taking some extra time to name the new class or method, so its name shows its true intent or content.
Let's compare these two lines. Which one is easier to understand?

Let's compare the two lines. Which one is easier to understand?

$evnt->add($req->q);
$event->addTickets($request->quantity);

There is an input error in the first line. The add method is not clear about what has been added. The variable $req is not clear enough. It is difficult to understand that q refers to quantity.

On the other hand, the second example is easy to understand even for non developers.
 

2. Use PHP standard similar to PSR-2

Never underestimate the importance of writing code in an orderly and consistent way, because it allows you to find problems faster.

Consider two examples:

public function addTickets($quantity)
{
    foreach (range(1, $quantity) as $i)
    {
            $code = Code::generate(); }
            $this->tickets()->create(
                [
                'code' => $code,
            ]);
    }
public function addTickets($quantity)
{
    foreach (range(1, $quantity) as $i) {
        $code = Code::generate();
    }

    $this->tickets()->create([
        'code' => $code,
    ]);
}

Both code blocks have the same error: when they should create N, both code blocks create only one ticket. But in which code block did you find the problem faster? Now imagine the consequences of dealing with complex code that is malformed.
 

3. Reduce the number of temporary variables

Although we learn how to declare and use temporary variables in the first chapter of the algorithm, they still make it difficult to read and maintain the code.

Consider the following example:

$contact                           = array();
$contact['firstname']              = $user->first_name;
$contact['surname']                = $user->last_name;
$contact['id']                     = $user->id;
$contact_emails                    = array();
$contact_email                     = array();
$contact_email['email']            = $user->email;
$contact_emails[]                  = $contact_email;
$contact['emails']                 = $contact_emails;

$this->create('contact', $contact);
$contact = [
    'id' => $user->id,
    'firstname' => $user->first_name,
    'surname' => $user->last_name,
    'emails' => [
        [
            'email' => $user->email,
        ],
    ],
];

$this->create('contact', $contact);

Which example is easier to understand?

By the way, using the equal sign is a bad habit. This is not only a violation of PSR-2, but also makes the code difficult to maintain.

So, back to our second example, this example can be optimized by removing the code variable and writing in line:

public function addTickets($quantity)
{
    foreach (range(1, $quantity) as $i) {
        $this->tickets()->create([
            'code' => Code::generate(6),
        ]);
    }
}

However, in some cases, using local variables can improve code readability, such as:

function calculateCode($price, $quantity, $deliveryCost)
{
    $subtotal = $price * $quantity;

    if ($subtotal < 30) {
        $subtotal += $deliveryCost;
    }

    return $subtotal;
}

It may be clearer than:

<?php

function calculateTotal($price, $quantity, $deliveryCost)
{
    if ($price * $quantity < 30) {
        return $price * $quantity + $deliveryCost;
    }

    return $price * $quantity;
}

 

4. Don't use magic numbers

If an order is less than 30 yuan, then there will be no package and extra freight will be paid. At this time, we should use constant to identify. If the order price is less than 30 yuan, then freight will be paid. The configuration of constants is as follows:

    if ($subtotal < DELIVERY_COST_THRESHOLD) {
        $subtotal += $deliveryCost;
    }

The translation codes are as follows:

    if (order price < price without postage){
        $current order price + = freight price;
    }

In this method, we show the convenience of using constant, which can also be reused in other projects.

If we need to change the rule of non mailing, we only need to update one line of constant code, which not only reduces the repetition, but also reduces the uncertainty of using fixed numbers to judge in the code.
 

5. Divide and rule

In many scenarios, too long code can be separated into several small methods, so that each method has different responsibilities. For example:

The new method getContactInfo will return an array with user contact information:

$this->create('contact', $user->getContactInfo());

Object oriented programming requires us to concentrate data and functions in one place (class). We will assemble an array of contact information in a (User model) that contains all User information.

Another example

    $subtotal = $item->price * $quantity;
    $subtotal = $this->addDeliveryCost($subtotal);

Method addDeliveryCost will return the amount of a delivery cost, provided that the amount does not exceed the set threshold, otherwise the original amount will be returned.

Now let's remove the local variables and inline the code:

return $this->addDeliveryCost($price * $quantity);

Declaring and using many small methods is a good way to reduce the use of temporary variables in code.
 

6. Simple solution by default

Many tutorials that promise you'll write better code will end up making it too complex.

If you are using Laravel and Eloquent, these tutorials will tell you that it is wrong to put the following code on the controller:

// Somewhere in UserController.php

User::create([
    'name' => $request->name,
    'email' => $request->email,
    'password' => bcrypt($request->password),
]);

You should write as follows:

// Somewhere in UserController.php

$this->commandTransport->handleCommand(
    new UserCreationCommand(
        new UserNameField($request->name),
        new UserEmailField($request->email),
        new UserPasswordField(bcrypt($request->password)),
    )
);

In the UserCreationCommandHandler class, you can't create users either, because it violates the SOLID principle. You should use repository:

class UserCreationCommandHandler
{
    //...

    public function handle(UserCreationCommand $command)
    {
        $this->userRepository->create(
           $command->name,
           $command->email,
           $command->password,
        );
    }
}

Finally, in the UserEloquentRepository class, you will finally call User::create:.

class UserEloquentRepository implements UserRepository
{
    //...

    public function create(
        UserNameField $name,
        UserEmailField $email,
        UserPasswordField $password
    ) {
    return User::create([
        'name' => $name->getValue(),
        'email' => $email->getValue(),
        'password' => bcrypt($password->getValue()),
    ]);
}

}

After a while, the client asks you to add another field to the User model.

Which is simpler? Which is more bug gy (you may forget to pass a field from one method to another).

At the same time, do you notice that you call two times bcrypt in case 2? So the second example has bug s.

Unfortunately, some interfaces and classes don't stop you from making mistakes. Therefore, we need to test the code carefully. When it comes to test code:
 

7. Write automated tests

Accountants use a method called double entry bookkeeping. This method requires them to record all transactions twice. Writing unit tests requires us to write code twice, defining each test once:

function test_order_without_delivery_cost()
{
    $order = new Order;
    $order->addItem(new Item(['price' => 20]), 5);

    $expectedTotal = 20 * 5;
    $this->assertSame($expectedTotal, $order->getTotal());
}

function test_order_with_delivery_cost()
{
    $order = new Order;
    $order->addItem(new Item(['price' => 20]), 1);

    $expectedTotal = 20 + DELIVERY_COST;
    $this->assertSame($expectedTotal, $order->getTotal());
}

Write the code for the second time (this arduous task is up to you).

Many developers complain about this because it forces us to "double our work," but by writing code twice, we reduce the possibility of making the same mistake in the same way (if we make two different mistakes, the test may fail). That's why projects that implement some unit tests tend to have small bugs that take hours to debug.

Tags: PHP Laravel less Programming

Posted on Tue, 03 Dec 2019 12:21:59 -0500 by Bidibule