Skip to main content

From assumptions to assertions

In your journey as a developer you not only develop applications, you also develop yourself. You and I both know there's more to developing than writing code that works, it's writing good code that works well. If you're like me then you probably started developing websites from scratch, later decided you wanted to build your own CMS and so on. In that stage as a developer you are usually very focused on getting stuff to work and not really on the unhappy paths.
As you continue to write code and continue to develop yourself you will eventually find yourself writing code like this, keep an eye on the is not null checks:
$lastOrder = null;

if ($user->getOrders()->count() > 0) {
    $orders = $this->filterByCompleted($user->getOrders());
    $lastOrder = $orders->last();
}

if ($lastOrder !== null) {
    if ($order->getBillingAddress() === null) {
        $order->setBillingAddress($lastOrder->getBillingAddress());
    }

    if ($order->getShippingAddress() === null) {
        $order->setShippingAddress($lastOrder->getShippingAddress());
    }
}
In the code above we retrieve the last order and use some information from there if it's missing in our current order (prefilling). Code like this is quite common and is sprinkled through most codebases I've worked with and contributed to. The problem with this code is that we're still making assumptions instead of assertions, just like we did back when we didn't check for unhappy paths at all and assumed all was good. The big cause of this are the is not null checks, they're a habit some of us have and it's not doing us as much good as we think it's doing.
Just to give you some insight, the $orders variable is of type Doctrine\Common\Collections\ArrayCollection and the last() functionactually uses PHP's end() function, if we check the documentation on that we can see that end() returns false when the array is empty. This may be something you already knew but this is not necessarily something you think about everytime you write code. With this in mind we can see that our code is flawed, it will run the if $lastOrder is not null check, pass and it will try to run $lastOrder->getBillingAddress() while $lastOrder is set to false. Our assumption was: "if $lastOrder is not null, it must be an object of type Order", just like we're assuming that $order->getBillingAddress()'s default value is null.
This brings me to the point of blacklisting vs whitelisting, I strongly believe we should be whitelisting in this case to turn assumptions into proper assertions. The above code could be rewritten as:
if ($lastOrder instanceof OrderInterface) {
    if (!$order->getBillingAddress() instanceof AddressInterface) {
        $order->setBillingAddress($lastOrder->getBillingAddress());
    }

    if (!$order->getShippingAddress() instanceof AddressInterface) {
        $order->setShippingAddress($lastOrder->getShippingAddress());
    }
}

Comments

Popular posts from this blog

Memory leak in 7.x json_decode()? Best Php Training Trivandrum

Memory leak in 7.x json_decode()? There appears to be a memory leak in 7.x json_decode(). I've uploaded a huge JSON file to demonstrate the problem. Here is the sample code: <?php echo memory_get_usage(false) . ' : ' .memory_get_usage(true) . PHP_EOL; $json = json_decode(file_get_contents('http://zaremedia.com/big.json')); echo memory_get_usage(false) . ' : ' .memory_get_usage(true) . PHP_EOL; unset($json); echo memory_get_usage(false) . ' : ' .memory_get_usage(true) . PHP_EOL; Below is output from 7.x and then 5.6: // Running on 7.0 and 7.1 349608 : 2097152 27245512 : 29360128 375552 : 29360128 The process starts with 0.3mb used / 2.0mb allocated. After json_decode(), it's 27.2 / 29.4mb, after unset, it's 3.7mb / 29.4mb -- The second value (memory allocated by php via emalloc()) has not been freed, though PHP's gc has correctly freed up the object usage. // Running on 5.6 221136 : 262144 31577064 : 35913728 420104 : 86507...

PHP-FPM tuning: Using ‘pm static’ for max performance best php training trivandrum

PHP-FPM tuning: Using ‘pm static’ for max performance Lets take a very quick look at how best to setup PHP-FPM for high throughput, low latency and a more stable use of CPU and memory. By default, most setups have PHP-FPM’s PM (process manager) string set to  dynamic  and there’s also the common advice to use  ondemand  if you suffer from available memory issues. However, lets compare the two management options based on php.net’s documentation and also compare my favorite for high traffic setups…  static  pm: pm = dynamic  – the number of child processes is set dynamically based on the following directives:  pm.max_children, pm.start_servers,pm.min_spare_servers, pm.max_spare_servers . pm = ondemand  – the processes spawn on demand (when requested, as opposed to dynamic, where pm.start_servers are started when the service is started. pm = static  – the number of child processes is fixed by...

PHP Realtime Libraries |Best php Training Triavndrum

PHP Realtime Libraries PushRadar’s official PHP library, wrapping the PushRadar API   – PushRadar is a realtime notifications API service for the web. The service uses a simple publish-subscribe model, allowing you to broadcast “notifications” on “channels” that are subscribed to by one or more clients. Notifications are pushed in realtime to those clients. Real-time log debugger  – Simple and Lightweight real-time log debugger via Websocket with Nodejs, SocketIO and Restful API to feed log (PHP, Python…) This project turnkey is distributed as a middleware to expose RATP realtime data as REST resources – This project turnkey is distributed as a middleware to expose RATP data as REST resources. You can retrieve real time schedules for any given RER (train), Metro, Tramway, Bus or Noctilien stop in real time. A PHP API wrapper for ORTC    – It’s an unofficial client for  ORTC  (Open Real-Time Connectivity, realtime & cl...