Chapter 5. Development Best Practices

In the previous chapters, we learned about various configuration best practices including caching best practices. Liferay Portal is a portal platform, and portal solutions are developed on top of it. Hence, it is very important to follow best practices during the development of custom features to build high performing portal solutions. In this chapter, we will focus on Liferay-Portal-specific development best practices. By the end of this chapter, we will learn the following topics:

  • UI best practices
    • Reducing the number of JavaScript files
    • Reducing the number of CSS files
    • Using CSS image sprites
    • Minifying JavaScript files
    • JavaScript tag positioning
    • Analyzing web page performance using tools
  • Java development best practices
    • Use of dynamic query and custom queries
    • Use of the Cache API to cache resources
    • Coding best practices

UI best practices

In any web-based applications, loading and rendering of the user interface in the browser contributes a lot in overall response time. It can even sometimes affect the processing on the server. In this section, we will talk about various UI best practices for improving the performance of the Portal.

Reducing the number of JavaScript files

JavaScript files are an integral part of web pages. There are two ways to include JavaScript in an HTML response:

  • One way is to embed JavaScript directly in the response using the <script> tag
  • The second is by referring to an independent JavaScript file using the <script> tag

It is recommended to include JavaScript using the second option. This allows the browser to cache JavaScript files separately in the browser cache. With the use of powerful JavaScript frameworks such as jQuery, YUI, Alloy UI, and so on, it is possible that one HTML page might be loading many different JavaScript files. This can slow down loading of the page in the browser because of network transfer. Transferring a number of small files over the network takes more time than transferring a single large file. Hence, it is recommended to reduce the number of JavaScript files by merging them together before transferring them over the network. This technique can improve the overall response time of the system.

Liferay Portal by default includes a lot of JavaScript files to implement various features. These files are required by either Portal's core features or by bundled portlets. If these JavaScript files are merged into a single JavaScript before transferring over the network, it can improve the overall performance of the Portal. This can be done by statically merging them but it will affect the maintenance of these files. For this reason, Liferay Portal has implemented a feature with which it dynamically combines these JavaScript files. Liferay Portal loads the combined JavaScript at once to improve the response time.

This feature can be enabled by adding the following property in the portal-ext.properties file:

javascript.fast.load=true

This property is by default configured to true, but sometimes developers set this property to false to debug JavaScript issues. The same configuration may be replicated in the production environment by mistake. Hence, it is very important to make sure this property is enabled in the production environment. When this property is enabled, Liferay Portal dynamically merges the list of JavaScript files. This list is known as the JavaScript bundle. Liferay Portal by default defines two bundles:

  • The barebone bundle
  • The everything bundle

When the Portal is accessed without authentication, every portal request loads the barebone bundle in the response. If the user accesses the Portal after authentication, every portal request loads the everything bundle in the response. Liferay Portal configures these JavaScript bundles using the configuration property. We can modify the list of files that are loaded by these bundles. The content of the barebone bundle can be modified by adding the following property in the portal-ext.properties file:

javascript.barebone.files=

In this property, we need to provide comma-separated JavaScript files. We can provide a relative path of the JavaScript files from the /html/js directory of the ROOT web application. For example, suppose we are using an AUI-based dialog box on most of our pages. It will require loading the aui-dialog.js file located in the liferay-portal-6.1.20-ee-ga2 omcat-7.0.27webappsROOThtmljsauiaui-dialog directory. Instead of making a separate request for this file from the browser, we can add this file in the barebone bundle. This can be done by appending auiaui-dialog aui-dialog.js to the existing values of the javascript.barebone.files property in portal-ext.properties.

To configure the list of JavaScript files of the everything bundle, we need to add the following property in portal-ext.properties:

javascript.everything.files=

By default, the everything bundle extends the barebone bundle. So, in the everything bundle, we need to provide only those JavaScript files that are not there in the barebone bundle. Liferay also provides a way to disable the barebone bundle. If we disable the barebone bundle, Liferay Portal loads the everything bundle for both authenticated and nonauthenticated requests. We can disable the barebone bundle by adding the following property in the portal-ext.properties file:

javascript.barebone.enabled=false

So far we talked about merging the JavaScript files of the Liferay Portal bundle. But we use Liferay Portal as a platform and develop portlets on top of it. Portlets also contain JavaScript files. It is recommended to merge the commonly-used JavaScript files of a portlet into one portlet to reduce the number of JavaScript requests.

Note

The JavaScript merging feature of Liferay is implemented using the minifier filter. Hence, it is very important to make sure the minifier filer is not disabled. The minifier filter is by default enabled but can be controlled by using the following property:

com.liferay.portal.servlet.filters.minifier.MinifierFilter

Reducing the number of CSS files

Similar to JavaScript files, CSS files are also an integral part of every web page, and a web page can have many CSS files loaded through the link tag. Again, inline styles through the <style> tag are not recommended. Similar to JavaScript merging, CSS files can also be merged to reduce network overhead. Liferay provides configuration to automatically merge CSS files of themes. This can be done by enabling the following property in portal-ext.properties:

theme.css.fast.load=true

If this property is enabled, it will always merge all the CSS files into one and load the merged CSS files on every page. By default this property is enabled by Liferay Portal. During development it may be required to disable this property to solve CSS-related issues. But in the production environment, this property should be set to true to get the best performance.

This feature only covers theme-related CSS files. We can also have CSS files in portlets. It is recommended to merge CSS files of the portlets into a single CSS file.

Using CSS image sprites

We looked at reducing the number of JavaScript and CSS file requests by merging them into a single file. Similar to that, every web page will have many network requests for images. Unlike CSS and JavaScript files, images are a different kind of resource and they need to be placed on the HTML page at a certain location. Hence, it is not possible to simply merge them, unlike CSS and JavaScript files, to reduce network overhead. To reduce the number of image requests, a technique called CSS image sprites is used. CSS image sprites are a pure HTML-and-CSS-based technique. Liferay provides built-in support for CSS image sprites through its tag libraries. Before we talk about Liferay Portal's CSS image sprites capability, let's understand how CSS image sprites work.

Suppose we have a simple HTML response with multiple static images as follows:

<html>
  <body>
    Arrow Up : <img src='arrow_up.png' />
    Arrow Down : <img src='arrow_down.png' />
    Arrow Right : <img src='arrow_right.png' />
    Arrow Left : <img src='arrow_left.png' />
  </body>
</html>

As shown in this code snippet, we are loading four images in the browser. To reduce the number of image requests, we need to combine all four images as shown:

Using CSS image sprites

Now the next step is to change the HTML code to render individual images from the preceding combined image:

<html>
  <body>
    Arrow Up : <img src='spacer.png' width='16px' height='16px' style='background:url(arrow_sprite.png) 0 48;' />
    Arrow Down : <img src='spacer.png' width='16px' height='16px' style='background:url(arrow_sprite.png) 0 0;' />
    Arrow Right : <img src='spacer.png' width='16px' height='16px' style='background:url(arrow_sprite.png) 0 32;'/>
    Arrow Left : <img src='spacer.png' width='16px' height='16px' style='background:url(arrow_sprite.png) 0 16;'/>
  </body>
</html>

This means we are now using one large image to load four different images. This concept is called CSS image sprites. The combined image is called a sprite image.

This technique is very good but it requires a lot of development effort. In the case of Portal, we need to create many image sprites for portlets, themes, and so on. We also need to add a lot of CSS styles to use sprite images. Fortunately, Liferay Portal provides built-in support for CSS image sprites. The Liferay plugin deployer automatically generates sprite images by combining all the images in one folder. Along with that it also generates a file called _sprites.properties. This file stores the size and coordinates of each image. Liferay tag libraries internally read this information and automatically generate the image tags to load the specific image from the sprite image.

Let's assume, in our custom theme, that we included the previous four images in the imagesarrows folder. Now when we deploy the theme on Liferay Portal, it generates the _sprite.png, _sprite.gif, and _sprite.properties files in the same folder. Both of the images will look similar to the image shown in this section. The content of the _sprite.properties file will look as follows:

/arrows/01_down.png=0,16,16
/arrows/01_left.png=16,16,16
/arrows/01_right.png=32,16,16
/arrows/01_up.png=48,16,16

As shown in the preceding snippet, the property file defines a key-value kind of structure. The key is the name of the individual image file. The value contains the width, height, and top y coordinate of the individual image in pixels. Liferay tag libraries take image names as an input. With the use of this property file, they can load individual images from _sprite.png. As mentioned earlier, Liferay Portal also generates _sprite.gif, which is used for old browsers.

This feature of Liferay Portal can be easily disabled or enabled. By default this feature is enabled. During the development phase, developers may want to disable this feature. It can be disabled by adding the following property in portal-ext.properties:

theme.images.fast.load=false

It is recommended to keep this property set to true in the production environment.

We looked at how CSS image sprites work for built-in features. We can also use Liferay tag libraries in custom portlets to load images from a theme. To load an image from an image sprite, we can simple use the icon tag of the liferay-ui tag library. Here is an example code snippet from a custom portlet that is loading an image from a theme:

<%@ taglib uri="http://liferay.com/tld/theme" prefix="liferay-theme" %>
<liferay-ui:icon src='<%= themeDisplay.getTheme().getContextPath()+"/"+ themeDisplay.getTheme().getImagesPath() + "/common/activate.png" %>' />

As shown in the preceding code snippet, we loaded an image from the theme. We just provided the path of the image. Internally, depending upon the value of the theme.images.fast.load property, Liferay loads the individual image or sprite image.

Minifying JavaScript files

Minification is a technique to reduce the number of characters from JavaScript files without affecting the functionality. With this technique, we can reduce the size of JavaScript files and improve the response time. It is recommended to use minified JavaScript files in the production environment.

Once JavaScript files are minified, it becomes difficult to read, debug, or modify them. Hence, it is a best practice to keep both minified and nonminified files in a version control system. In the production environment, only the minified version of JavaScript files should be deployed. In order to make sure all the JavaScript files are minified, it is recommended to automate the minification of the files through build scripts. This can be easily done by adding a target in an ANT build script.

Tip

To minify JavaScript files of a specific plugin of the Liferay plugin SDK automatically, we need to add an ANT task in the build.xml file of the plugin. From the ANT task, we need to call minifier to minify all JavaScript files of the plugin. YUI Compressor is one of the most popular open source JavaScript minifiers. It can be called from the ANT task. The following URL provides more details on how to call the YUI Compressor from an ANT task:

https://code.google.com/p/yui-compressor-ant-task/

JavaScript positioning

As per the HTTP/1.1 specification, the browser should not download more than two resources per host name. But with JavaScript files, this rule works differently. When the browser is downloading JavaScript, it blocks all other download requests irrespective of the host name. This affects the overall response time. The Yahoo! team found out that if JavaScript files are placed outside of the html tag, this problem can be avoided and pages load faster. Here is an example code from yahoo.com:

</html>
<!-- dnr= -->
<!-- bid=704 -->
<!-- sid=97684142 -->
<!-- myproperty:myservice-in:0:Success -->
<script language=javascript>
if(window.yzq_p==null)document.write("<scr"+"ipt language=javascript src=http://l.yimg.com/d/lib/bc/bcr_2.0.5.js></scr"+"ipt>");
</script>

As shown here, the <script> tag is placed after the end of the <html> tag. This is against the specification but all browsers support it. Hence, it is recommended to place JavaScript files outside the <html> tag in the footer. It is not possible to place all JavaScript files in the footer but whenever possible, we should place the files like this.

This is a good technique but in case of Portal, we develop portlets and they do not have <html> or <body> tags. They just render HTML fragments. Fortunately, Liferay provides a way to add JavaScript files in the page footer from any portlet. This can be done by providing the <footer-portal-javascript> tag in liferay-portlet.xml as shown:

<footer-portlet-javascript>/html/portlet/users_admin/js/main.js</footer-portlet-javascript>

Limiting the use of DOM operations

Document Object Model (DOM) is a convention for representing HTML objects. With the use of DOM operations, we can change the state of HTML objects displayed on the browser. With DOM, it will be very easy to programmatically manipulate HTML content rendered on the browsers. Frameworks such as jQuery, AUI, or YUI reduces the amount of code required to perform DOM operations. DOM operations are browser-dependent. Each browser provides its own implementation for DOM. Some of the browsers such as IE7 or IE8 are not optimized to perform DOM operations. DOM operations slow down the rendering of web pages in the browser. It is recommended to use fewer DOM operations in the code to make the system run faster.

Analyzing web page performance using tools

In this section, we talked about some of the key UI best practices. UI is a very vast field and there are many such best practices. These best practices can be applied to any web-based applications. It is very difficult to find out areas of the UI where we are not following such best practices. Fortunately, there are many tools available to find out improvement areas from the UI point of view. Here are some of the more popular tools, which we can use to find out areas of improvements:

  • YSlow: YSlow is an open source tool to point out issues that can affect the performance of the system. It checks the web page against around 23 rules. Based on the result it gives a performance grade. It can be installed as a browser plugin. It supports most of the popular browsers. For more information please refer to http://yslow.org/.
  • PageSpeed: This is another web page analysis tool to point out bad practices. It checks the pages against web page performance best practices. It is open source and can be used as a browser plugin. It can also be configured on Apache Web Server. For more information please refer to https://developers.google.com/speed/pagespeed/https://developers.google.com/speed/pagespeed/.
  • Compuware dynaTrace AJAX Edition: This tool installs an application agent in the browser. With that it can record all requests. Based on the analysis it points out areas of improvement. It also gives a performance grade to each page. This tool persists performance reports and so it makes it easy to compare the results after applying changes. For more information please refer to http://www.compuware.com/application-performance-management/ajax-performance-testing.html.

There are many other tools available in the market but I have listed out some of the key tools based on my experience.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.149.27.72