Performance Tuning - Chapter 2: Implementation

The second chapter introduces many useful skills to help you choose the correct Backbase widgets and technologies when tuning performance.

1. Combine model space island with view space island

Instead of using the full Backbase RIA implementation or traditional XHTML for a web application, combining these two model islands is a great approach. In this way, we can get the benefits from both sides: the speed from XTHML space and the functionality from the Backbase Client Framework.

In this section, the manual method is introduced first, followed by more advanced Backbase techniques.

In XHTML, a script tag can be added to wrap the Backbase Client Framework. On the other hand, in the Backbase space, b:xhtml can be used to wrap regular XHTML elements that do not need to be processed by the Backbase Client Runtime engine. Furthermore, b:xml is used for escaping back into an area that is processed by the Backbase Client Runtime engine, when used within the BTL xhtml tag. See the code snippet below:

<body>
        <script type="text/backbase+xml">
                //backbase code
                <b:slider/>
                <b:xhtml>
                        <p>This is outside the Backbase space</p>
                        <b:xml backgroundColor="yellow" style="display: block;">
                                <p>This is inside the Backbase space</p>
                                <b:calendar mode="inline" />
                        </b:xml>
                        <p>This is outside the Backbase space</p>
                </b:xhtml>
        </script>
        <div>
                //xhtml code
        </div>
</body>

2. Use Backbase progressive enhancement techniques - Import HTML

This is a Backbase built-in technique to combine different islands in an easy and organized fashion. The main idea behind it is to show all the HTML view nodes first, and then load the Backbase core to transform some of the HTML view nodes into model nodes and controllers.

In this way, the user will see the website first, just like a normal Multiple Page Interface (MPI) without any delay for loading the Backbase Client Framework and the interpretation of Backbase widgets. Later, the model nodes and controllers are created and all the functions are set up.

There is an online example and more explanation can be found in the Backbase Client Reference.

3. Use Backbase progressive enhancement techniques - view handlers/lightweight Ajax

View handlers is another Backbase built-in technique to easily handle logic between different islands. It helps people create fewer model nodes and controllers for simple implementations, and thus makes the application more lightweight.

The basic step is adding a match attribute to the normal event handler with CSS selectors. This technique makes it extremely easy to react to specific elements in the view space. Here is an example:

<d:template type="application/xml">
   …
   <tr class="classGrey"/>
</d:template>
<d:handler event="click" match=".classGrey" type="application/javascript">
   console.info('you clicked tr');
</d:handler>

View handlers only handle mouse and keyboard events. So other events like "onchange" event or "onfocus" event are not suitable to be used with view handlers.

4. Use deferred loading techniques (lazy loading/construction)

This technology allows people to have more control over the timing and processes within their pages. Lazy loading means to load certain data on demand. The BTL populator tag is designed for lazy loading. It listens to an event ("select" by default) on its parent, and loads a file when that event is triggered. In the example below, populatorOnce.xml will be loaded when the user selects the second tab. The third tab will always reload populatorAlways.xml when selected.

<b:tabBox>
    <b:tab label="intro" padding="5px 10px">
        <!--...text here...-->
    </b:tab>
    <b:tab label="populator once" padding="5px 10px">
        <b:populator url="data/populatorOnce.xml" />
    </b:tab>
    <b:tab label="populator always" padding="5px 10px">
        <b:populator url=" populatorAlways.xml" type="always" />
    </b:tab>
</b:tabBox>

Another lazy loading technique is to use the bb.command.load fuction.

<div>
    //Click here to load the contents of an external file.
    <e:handler event="click" type="text/javascript">
        bb.command.load('loadfiledata.xml','GET',null,null,bb.getProperty(this,'parentNode'));
    </e:handler>
</div>

Lazy Construction means to construct certain elements on demand (the content of the element has already loaded). It consists of two parts:

  1. Avoid the contained elements from being constructed on startup. We do this by overriding the built-in "children" method with an empty method:
    <d:method name="__children">
        <d:body type="application/javascript"/>
    </d:method>
  2. Provide an API through which contained elements can be constructed on demand.
    <!-- Construct contained elements on demand -->
    <d:method name="constructItem">
        <d:argument name="item" type="number" required="true"/>
         <d:body type="application/javascript">
            var oItem = this.selectSingleNode("*[position()='" + item + "']");
            // If the XPath expression didn't return a Controller, it still needs to be constructed
            if (!oItem.modelNode) {
                // construct the item (optionally provide callback)
                oItem = bb.construct(oItem);
            }
            return oItem;
        </d:body>
    </d:method>

Here is an example showing that a b:calendar will only be constructed when the user clicks the button:

<coca:lazyConstructor xmlns:coca="cola">
    <b:calendar/>
</coca:lazyConstructor>
<b:button>
    Lazy contruct
    <e:handler event="click" type="application/javascript">
        this.selectSingleNode('preceding-sibling::*:lazyConstructor'). constructItem(1);
    </e:handler>
</b:button>

5. Use smart pruning: Remove unused elements and behaviors

Pruning is the process of removing unnecessary elements from the model tree and memory. It is like a manual garbage collection process. Loaded data and model nodes/controllers should be removed when they are no longer needed. However, this pattern is only useful if the user does not need the data or model nodes often (for example, switching often used views is not a good candidate for pruning).

Here is an example that creates a window that will destruct itself when the user clicks the close button. The window could be recreated again by clicking the "Window1" button.

<d:element name="mywindow"  extends="b:window">
    <d:handler event="close" type="application/javascript">
        console.info('close');
        var oThis = this;
        setTimeout(function(){
                bb.controller.destructChildren(oThis);
                bb.destruct(oThis);
        },1000);
    </d:handler>
</d:element>

<b:button>
    Window1
    <e:handler event="click" type="application/javascript">
        bb.command.load('testcase.xml','get',null,null,this.getProperty('parentNode'));
    </e:handler>
</b:button>

6. Push static content into view space

This is the implementation of part 2 in stage 1. The usual approach is either to put static view nodes outside Backbase script tags, or to put as much static content as possible within d:resource tags. Another option is to put static content in a view template, where the CSS display property is set to none.

7. Make correct choice of widgets

There are over a hundred types of Backbase widgets. Some of them are more complex and require more time to initialize than others. For example, the Backbase comboBox has much more powerful functions (drop-down list and filtering) than the listBox. Also obvious HTML elements should not be forgotten. Simple HTML divs might be more effective than the Backbase panelSet, if the requirement is only to have a container to put content inside.

8. Create element behavior for repeated event handlers/methods

If more than one element uses the same event handler in the implementation, instead of rewriting this event handler inside those elements, programmers should create a Backbase behavior and put the event handler inside this behavior. Then all those elements can add an e:behavior attribute with the name of the behavior.

9. Choose proper programming model: JavaScript or Backbase declarative language

In terms of performance, using JavaScript is better than Backbase declarative language like XML Execution Language (XEL). This is because Backbase engine has to interpret the declarative language and change it into JavaScript that browser understand, which cost extra time.

10. Apply Backbase databinding technique for same data across among UI elements

Backbase data binding allows different elements to share the centralized data. This mechanism not only creates an effective way to communicate among elements, it also increases the performance as it make the client-side logic simpler and saves more memory. In addition, when the data needs to be synchronized with server-side, a single request is enough instead of sending many requests from each data-related elements. After receiving the data, data binding will in charge of notifying each observer and will update the value of each one.

11. Use appropriate skinning

Backbase Client Framework provides two skins for all renderable BTL elements: a system skin, which has the same look and feel as the Windows 95/98 operating system (or the Windows XP classic skin), and a modern, configurable chameleon skin. Backbase also allows you to customize the skin by applying the b:skinSettings element. The system skin is quicker as it has simpler CSS definition. On the other hand, the chameleon skin is relatively slow, because of its CSS definition and much more media files. It all depends on the requirements whether the project should use the system or chameleon skin.

See other chapters:

Performance Tuning - Checklist

Performance Tuning - Chapter 1: Architecture and Design

Performance Tuning - Chapter 2: Implementation

Performance Tuning - Chapter 3: Deployment

Performance Tuning - Chapter 4: Server-side Optimization

Performance Tuning - Chapter 5: Testing

Performance Tuning - Chapter 6: Conclusion