Optimize before you go live (Part 1).

Created on
Updated on
Written By
Optimize before you go live (Part 1).

Part 1: Backend developer

Here are two reasons why you should take it seriously when it comes to your website speed. First of all a faster website means a better user experience. People can easily get bored waiting for your pages to load and could quickly drop off your site. On the other hand page speed is now one of the factors Google uses to determine the search ranking. Slow-performing sites could be penalized specially when it comes to mobile. In this article, we’ll discuss some common performance problems and shared some guidelines for backend developers. This is the first instalment of an 4-part blog series focus on performance.

Performance

Clean up your watchdog table

Every time a watchdog error gets logged, it consumes CPU resources on the web and database server. Even if you turn off the database logging (db_log) every single PHP error will still slow down the speed of PHP execution. Furthermore, too many warnings or notices will hide critical issues as your logs will be more difficult to read and monitor. Having too many PHP errors is often a sign of poor development and you don't want to be in that position. So the only acceptable rule should be to fix all your errors, warnings and notices. No exception to this.

Don't abuse the variable API

The variable API is probably one of the most misused API and people tend to store in it something and everything. It’s not a surprise the API has been dropped in Drupal 8. When a variable is set the cache variable (located under the cache_bootstrap table) is cleared. Next time a page is requested the whole cache variable will need to be rebuilt which can become a big task if you are dealing with a lot of variables.

Make Fewer HTTP Requests

Calling external services through the http_request() function can bring your website to a standstill. The best approach is to try to move the logic behind the HTTP request into a queue or a cron job. Another solution would be to cache the results so you don’t need to call the same service twice if you are expecting the same results for a define period. If you really need to call http_request() then don't forget to specify a reasonable timeout knowing that the default value is 30 seconds. It will prevent your website to fall apart if one of the external services you are consuming is down.

Keep your "dot module" short

On every page request, every single "dot module" file is loaded for every single module that's currently enabled. Keeping the code shorter in those module files will improve your performance and decrease the PHP memory footprint. Drupal provide different techniques to split the "dot module" into several dedicated files.

First of all you can implement your page callbacks in separate files. Most likely those callbacks are not needed all the time so there is no reason to load them on every single page request. If you provide a file parameter in your hook_menu() declaration, Drupal will make sure to include the file when needed.

function modulename_menu() {
  $items['admin/config/modulename/page'] = array(
    title= 'Your Module',
    page callback= 'drupal_get_form',
    file = 'modulename.admin.inc',
  )
  return $items;
}

Secondly you can move all your theming methods into a separated file. Your theming functions are cached by Drupal so there is absolutely no need to fetch that code on every page load.

function modulename_theme() {
  $path = drupal_get_path('module', 'modulename') . '/theme';
  return array(
    'modulename_button' => array(
    'variables' => array('button_content' => NULL),
    'path' => $path,
    'file' => 'modulename.theme.inc',
  )
}

Another way to reduce the amount of code in your "dot module" file is to use the auto load mechanism provided by some well know core and contrib modules (rules, drush, token, view). You just need to follow some conventions and move the code specific to those contrib modules into dedicated files. Those files will be included upon need leaving you with a better performing web application. For example the drush module will get commands defined in the modulename.drush.inc. The Rules module has a more flexible inclusion mechanism but also allow you to reduce your main "dot module" file.

Keeping your "dot module" short will not only improve the performance of your code but it will make it easier to hand over to another developer. It's obliviously easier to find your way when you implement short, clean and consistently named files like this:

  • modulename
    • modulename.rules.inc
    • modulename.module
    • modulename.views.inc
    • modulename.drush.inc
    • modulename.token.inc
    • modulename.admin.inc
    • modulename.theme.inc

Know the Drupal API

When loading multiple entities like nodes, comments, users or taxonomy terms Drupal, since Drupal 7, provide efficient API functions. So feel free to abuse node_load_multiple(), comment_load_multiple, user_load_multiple() or taxonomy_term_load_multiple().

# Wrong implementation
foreach ($nids as $nid) {
  // Load each node one at a time.
  $node = node_load($nid);
  do_something_function($node);
}
# Correct and more efficient implementation
$nodes = node_load_multiple($nids);
foreach ($nodes as $node) { 
  do_something_function($node); 
}

The db_select() method is slower than db_query() but that does not mean you should always use db_query(). db_select has many advantages over db_query(). It is easier to read, more flexible - through Tags, Extender and node access control -  and support cross database compatibility. But if performance is critical for your project, you should benchmark (xhprof) your methods and replace them accordingly.

The hook_form_alter() has another more specific variant, which takes the form of hook_form_FORM_ID_alter(). Using the dedicated hook will only affect a specific form. Therefore it will not only increase your website performance, but improve the readability and quality of your code.

Expensive functions

The hook_init() is invoked by Drupal on each page requested for authenticated users. The hook_boot() and hook_exit() will run every time even if your content is cached and serve to anonymous users. So it's something to keep in mind when you are building your module. You don't want to do crazy and time consuming tasks in those hooks as it will just kill your site.

Voilà! We are now done with the back-end improvements. Those enhancements will not only speed up your website but most importantly will increase the maintainability and the quality of your code. Next time we will discuss how site builder, font-end engineers or operational teams can improve your pages’s load time.