Clean Code PHP – Functions

Functions. It makes your life easier if you make correct use of it. There are some guidelines you should follow to create clean functions. This will help you in maintaining your code, but also makes it more readable. You need to remember that most of the time is spend reading code, not writing code. So better put some extra effort in writing good functions so its easier and faster to read them. In the long turn this saves you and your colleagues a lot of time.

Use descriptive function names

Your function names should explain what they do. You should not need to look into the function to find out what it does. Its better to use long descriptive function names.

A function name like processEmail() is not clear in its intent. What are we processing? We are making it ready to be send, or are we sending it? Or are we doing both? But if you change it to sendEmail(), then it makes more sense. Now we know it will send an email.  Everything your function does should be in the name. If that means you get a function name like setUserToActiveAndCreateGiftCardAndSendWelcomeBackEmail() then it means your function does to much. So when explaining what the function does in the name will also allow you to detect issues with it.

If you are unable to come up with a descriptive name. This might mean that you don’t know what the function does and that the function is not clear in its intent. This allows you to detect bad functions.

Every function should do one thing

Functions should do one thing. They should do it well. They should do it only.

Its the most important rule to follow. When your functions do more then one thing, they are harder to understand, to test and to maintain.

Its also easy to detect when a function does more then one thing. If you can extract another function from your function which is not a restatement of its implementation, then it does more then one thing. You can see this in the next example.

Bad

This code gets the the data from database and then creates the email. It does more then one thing. I can easily split this code in multiple functions which does not restate the implementation.

function sendNewsletterToSubscribedUsers(array $users) {
    foreach ($users as $user) {
        $userRecord = $db->query("SELECT * FROM users WHERE user_id = '".$user->getId()."' AND user_subscribed = 1 LIMIT 1");
        $mail = new PHPMailer;
        $mail->setFrom('noreply@thinktocode.com', 'Think To Code');
        $mail->addAddress($userRecord->email, $userRecord->name);
        $mail->Subject  = 'Newsletter';
        $mail->Body     = 'Hello, this is our  newsletter';
        $mail->send();
    }
}

Good

Here we extracted the code to new functions. Now it does only does one thing, and calls the other functions to do the other things.

function sendNewsletterToSubscribedUsers(array $users) {
    $subscribedUsers = getSubscribedUsers($users);
    foreach ($subscribedUsers as $subscribedUser) {
        sendNewsletter($subscribedUser);
    }
}

We have a separate function to get info from the database. And a function which will actually send the newsletter. In return this also made out functions smaller and easier to read and understand.

Also notice that the function name is a combination of the 2 new functions we created. We sendNewsletterToSubscribedUsers. So this means we need to getSubscribedUsers and sendNewsletter to them.

Functions should only have one level of abstraction

If we want to make sure a function does one thing. Then we need to make sure that all the code in our function is in the same level of abstraction.

A good way to find out is to read the code from top to bottom with TO paragraphs. Each describes the current level of abstraction.

  • To activate a user and send a gift card, we set the user to active, we create a gift card and we send the gift card.
    • To send the gift card we create a PHPmailer object if the user has a valid email
function activateUserAndSendGiftCard($user) 
{
    $user = setUserToActive($user);
    $giftCard = createGiftCard($user);
    sendGiftCardToUser($giftCard, $user);
}

function sendGiftCardToUser($giftCard, $user) 
{
    if (isValidEmail($user->email)) {
        $mail = new PHPMailer;
        // Send giftcard to user
    }
}

You can apply this to any code you write and you will see that you will make better, cleaner and more maintainable functions. Its always a good to idea to make your functions as small as possible.

Ideal number of function arguments

The ideal number of function arguments is zero, follower by one, followed closely by two. Then 3 arguments should be avoided. More then 3 should have a very good reason, but most of the time there is no good reason for this. Most of the time this means your functions do more then one thing.

So the more arguments you have, the harder it becomes to test and to understand the function. Also its hard to maintain a function which has a lot of arguments. The more arguments the more combinations you have to test and take into account. Its an explosion of unneeded complexity.

Bad

function createOrder($documentNumber, $title, $customer, $date, $status, $billingAddress, $deliveryAddress) 
{
    // ...
}

Good

class Order
{
    public $documentNumber;
    public $title;
    public $customer;
    public $date;
    public $status;
    public $billingAddress;
    public $deliveryAddress;
}

$order = new Order();
$order->documentNumber = '20170000001';
$order->title = 'New Smartphone';
$order->customer = $customer;
$order->date = '2017-10-22';
$order->status = 'On Hold';
$order->billingAddress = $billingAddress;
$order->deliveryAddress = $deliveryAddress;

Instead of a long function with countless parameters. We can use classes or arrays. This is also easier to maintain in case we need to add a new property.

Functions should not have side effects

A function should not have a side effect. Side effects are lies. You promise to do one thing, but your function does something else that’s hidden. So be cautious with this.

Sometimes you need side effects. Like writing data to a log file. In this cases makes sure that your side effects use other classes or functions. Your side effects should not have big altering effects which makes your function name a big lie.

Conclusion

You should use functions to write stories and just write code. Your functions should be a guide to describe how your program work. An application with perfectly crafted functions don’t need any documentation. In fact the the code is self documenting. It can be read as a book without a second thought. If you try to follow these rules as described here. Your functions will be short, good named and well organized.

I can only highly recommend reading “Clean Code” by “Robert C. Martin” to get a more deeper insight into this subject.