A technique to efficiently manage client-side code when bandwidth is limited

Using a cooperative client-side and server-side technique enables code to be automatically generated based on the data entered by the end users.

On a recent project we had a very complex Web application to deliver in an environment where many of the end users had slow connections to the server on which the application was to be deployed. As such, conservation of bandwidth was one of the priorities. We decided to design for bandwidth constraints from the beginning of the project. This focus led to a key decision to develop the application primarily using client-side scripted code—in this case written in JavaScript—which could be cached locally and by the proxy servers, etc. upstream of the end user, resulting in a significantly smaller package needing to be retrieved from the main servers.

As this was an internal application for this organization, we only had to consider our install base being Internet Explorer 5.5 or higher and all users had JavaScript enabled, in a different situation this may not be the most suitable development choice.

Printable PDF

This article and the corresponding example code are available in a printable PDF download version.

Not all clear sailing

On the whole, this approach worked very well and allowed us to have the application function faster than expected by the end users, who were used to a heavily biased client/server approach even with their Web applications. As most of the functionality was concerned with validation of data entered by the users into a HTML form—for which JavaScript is very suited—the JavaScript was quite simple, but of significant volume—almost 10,000 lines in total.

However, it was not all clear sailing, there were some functions that were very complex to create in JavaScript and several that contained actual data rather than logic or functionality. It was these parts of the data model which concerned us most as any change to the content would require developer, rather than user, intervention. Some of the pseudo code for the functions was similar to the following:

if ProductType=A then add items 1,2 & 3 to dropdown DD1
else if ProductType=B then add items 1, 4, 7 and 20 to dropdown DD1
else if Product Type=C then add null, 34, 78 to dropdown DD1

As you can see, while this is very simple to code up in a client side scripting language such as JavaScript (see Listing A), it would not be in a format that an end user, or even a power user could be left to update on his own. In any other design, we would have stored this information in a database lookup table—such as the one shown in Listing B—and then interacted with it when we needed to.

We then asked the users about frequency of change of the data concerned. If it did not change on a regular basis, then we could consider leaving it in as shown in Listing A and take the hit of the development team maintaining it. However, as this data was likely to change on a regular basis and the client required immediate updates—rather than logging a support ticket and waiting a few days—we decided to store it server side in a database table with a maintenance screen for the key user to manage the data. We began to discuss how we would pass this information from the server side to the client to be processed; we considered several options including:

  • A hidden IFrame on the page.
  • An XML file.
  • A new popup window.

We decided to use the hidden IFrame approach so that we could hide the call from the users, but could also make the IFrame visible for debugging if required.

Our next problem was how to convert the tabular database table into a format that could be used by the rest of our application on the client side. We very quickly decided to simply dump the table into two Arrays—one for each column—and then cycle though them when required to populate the drop-down box.

Just as we were on the verge of resigning ourselves to this and preparing to brief the key users and management on this change and performance hit, one of the consultants from SolarFish—one of our consultancy firms—came up with an intriguing potential solution. He realized that the information needed to be updated using server-side code, but used on the client side. His suggestion was to amend the server-side script that updated the database to recreate a client-side script file on the server, which could then be loaded and cached like the rest. This file would then be as static for its lifetime as any of the static files, rather than being created dynamically every time it was called.

After some experimentation, we were able to get a working prototype using classic ASP's File Scripting Object to create the file on the server as part of the update process of the database table. The relevant fragment of code is shown in Listing C, and the result and output in Listing D. As this file would only ever by updated when the data was changed, we could treat it in the same way as the rest of our client-side script code and it would also be cached.

Having proved that this approach would work, we re-examined the rest of our Requirements Specification, and spotted several other situations in which the same approach could be reused, either to ease maintenance or to improve the offering we provided to our users. For example, we were able to create a database table of the field labels on the screen and then have any changes to the labels immediately populated to the end users' screens in the same manner.

Code factory

Using this approach, we were able to meet our internal goal of delivering a system primarily using client-side code to minimize network traffic for our customer. In addition, we were able to add several items of functionality that could be managed by the customer rather than by a developer, allowing a quicker response time to most simple change requests, such as label changes.

Also, as the code was automatically generated and the data directly entered by the end users themselves, we were able to remove the developers—and any typos, errors, delays, etc. that they could be blamed for—entirely from the equation. This freed up the developers to work on other projects rather than making minor changes to existing code every time these bits of information changed.

Having created "code that wrote code" as we described it to our Project Manager, we had found a method that could be reused in other projects that we were working on. We had not come up with a name for this approach, but it seemed to be some kind of code factory, although most of the developers prefer to call these components "SkyNet" after the computer AI in the Terminator films, or "Hal" after the AI in the film 2001: A Space Odyssey; The latter seemed appropriate primarily because bugs were hard to find and fix and usually resulted in some really strange output.