Fat Client - Ajax Patterns

Fat Client

From Ajax Patterns

Evidence: 1/3

Tags: Rich Decoupled DHTML Fast


Contents

In A Blink

TODO Diagram User and computer in close affinity, server distant with faded link.

Interesting, and sort of cool. In Display Morphing, you didn't have a diagram here, but I love the idea of having a visual representation of each pattern for the In a Blink section.

Goal Story

Bill is planning to purchase a home and needs to arrange a mortgage. He visits an Ajaxian financial planning site, where he can try various scenarios on the simulator. "try various scenarios" reads pretty formal. Really, he's trying out different mortgage programs, or interest rates, right? I'd say things as plainly as possible. The site provides rapid feedback, enabling Bill to quickly tweak settings and quickly explore the effects of different parameter values. Same thing here. Bill probably has no idea what a parameter is; but he would know what his down payment is, or his interest rate... Almost all of the interaction occurs between Bill and the browser (rather than the browser and a server); the browser's scripts taking care of the necessary financial modeling. Only occasionally are remote calls to the server made, usually to grab interest rate data appropriate for Bill.


Problem

How can you architect the system to provide instant interaction without the delay of remote requests? Most applications follow a Model-Viewer-Controller (MVC) pattern, however with a thin client web application the viewer (HTML pages) and controller (browser events) aspects of the MVC must communicate across remote connection to interact with the application logic, which is fundamental problem for providing responsiveness to users.Essay writing help

pre algebra help
Essay Writing Services


I wonder if we need to define these earlier on. For example, your description makes me think of this as an interactive application, but not necessarily a rich one. That said, if pressed, I'm not sure that I could give a clear concrete definition of "rich"; it's just a feeling.


Forces

  • The application should respond to user actions quickly, ideally instantaneously.
  • Responses from the server can be noticeably latent due to data transfer and server processing overheads.


Solution

Create a rich, browser-based, client by performing remote calls only when there is no way to achieve the same effect in the browser. Whereas the server is traditionally the realm of more complex processing, this pattern suggests harnessing the browser for all its worth, and implementing just about everything locally.

Most web applications have several concerns:

  • User Interface
  • Application logic
  • Business logic
  • Data access
  • External system communication

The user interface is what the user sees and interacts with. The application logic concerns the dialogue between the user and the computer. For example, given a certain user action, - regardless of the precise UI mechanism which allowed the user to - what should the computer do next? The business logic concerns knowledge about the domain and the website owner's practices and policies. The data access layer concerns reading and writing data to a persistent store. External system communication is also necessary in many enterprise systems, where other systems play the role of information sources or sinks.

TODO Diagram - Fat client vs Thin client (where each concern goes)

Conventional web applications concentrate the UI code in the browser, using a mix of HTML and CSS, with some Javascript used to perform a few basic UI tricks like placing keyboard focus or showing some animation or offering a dynamic menu. Everything else is usually managed on the server. This pattern reconsiders the balance by suggesting that some applications are better served pushing application logic and business logic into the browser.

With application logic in the browser, an inversion of control occurs in which the browser now controls the flow of activity. When the user performs some action, it is the browser that decides how to respond, and calls the server only if necessary, and for very specific services.

This pattern provides an opportunity for a more effective Model-Viewer-Controller (MVC) implementation. With application logic centered in the browser, the model aspect of MVC becomes the remotely linked aspect of the equation rather than the viewer and controller. The model can potentially be more automated for performance improvement than the viewer and controller, which require significant programmatic consideration for efficiency.

Traditional web applications have fallen very easily into the flaw of keeping transient application state on the server. Session variables/objects have lulled many programmers into this trap, which violates the REST principles of the HTTP protocol, and leads to significant memory loads on servers, and prevents caching opportunities. Fat clients on the otherhand naturally tend to store transient application state information on the browser, and can access server side data with idempotent requests very naturally.

Also, this pattern can potentially reduce server processing load. If the majority of processing occurs on the client, than less load is placed on the server, and it can scale to more users more effectively. Generally most client machines have plenty of unused computing capability to take advantage of (effectively distributing the load web applications).

The advice to hold business logic in the browser is anathema to most literature on serious website development, and should not be taken lightly. Business logic in the browser has numerous problems:

  • Programming in Javascript can be difficult because many features familiar to mainstream developers are unavailable. The standard API is minimal, object-oriented facilities are based on prototypes rather than classes. Indeed, the usage of dynamic typing is also uncomfortable for many developers in the Java and C# camps.
  • Portability is a major complication due to the number of platforms that must be supported, and their subtly inconsistent behaviours.
  • Development is also a challenge. Coding, refactoring, debugging, automated testing, monitoring, are standard in modern IDEs like IntelliJ Idea, but support at this level is minimal for Javascript.
  • Security is another constraint which forces logic server-side. Users can not only read code and data in the browser, but they can actively tamper what's sent back to the server. No amount of obfuscation will deter those people with the ability and motivation to do this.
  • Browser-based information is not persisted anywhere.

Are any of these showstoppers? Let's look at how we can cope with each of these problems:

  • Javascript may be different to server-side languages, but many programmers are discovering it's a lot more powerful than previously assumed. Until recently, the main resources on Javascript were "cut-and-paste this code" websites, but there are an increasing number of books and resources that take the language seriously. The language has undergone a renaissance in parallel with Ajax. New idioms and patterns are emerging, along with a pile of cross-browser frameworks to augment the relatively bare native API. The recent introduction of JSAN - a repository of Javascript libraries like Perl's CPAN - will only further reuse. Object-oriented concepts, including inheritance and aggregation, are indeed possible, if not in a manner familiar to all server-side developers. Dynamic versus static typing is a matter of taste which shouldn't affect a language's credibility; the dynamic approach of Javascript may not be everyone's preference, but Javascript is hardly an outsider here.
  • Portability does remains an issue, but imlpementations are more standard nowadays, and many of the new libraries abstract away those details. For example, over a dozen libraries offer a browser-independent factory method to retrieve XMLHttpRequest.
  • Development remains a challenge, but recent tools are making life easier, some discussed in Development Patterns.
  • Security remains an issue, but it's possible to deploy the application so that security-critical functionality can be exposed server-side in well-defined services, with the bulk of the application logic held locally and calling on those services as required.
  • Persistence cannot happen locally, but a background thread can be used to periodically synchronise with the server. In the 1990s, many desktop applications forced the user to explcitly save their work, whereas many of them now save periodically and save upon the user quitting. In the same way, it's now feasible for web applications to persist data transparently, without affecting workflow.

None of this says that programming in Javascript is more productive than programming in Java or C# or Ruby. In most cases, it isn't and never will be. What I'm saying here is that it Javascript programming is actually feasible. Professional software development involves choosing the language that fits the task at hand. Given the many benefits of browser-side coding, there are at least some circumstances which make Javascript the language of choice for implementation of business and application logic.


Decisions


How will business and application logic be implemented in the browser?

Conventional applications use Javascript for a little decoration. Even where a lot of Javascript is used, it's often packed into tightly-scoped library routines, to perform little tricks like validating a form's fields match regular expressions, or popping up a calendar. These are just little detours on the well-travelled road between browser and server. In contrast, a [[Fat Client]] responds to many events itself, delegating to the server only if and when it deems necessary.

All this implies a very different usage of Javascript, and there are some techniques which can help. It's beyond the scope of this pattern to cover them in detail, but following are some pointers.

  • First, if you're unfamiliar with Javascript, avoid "paving the cow paths". That is, approach Javascript as a unique language with its own properties and usage patterns, and be wary of mindlessly applying architectural concepts from your favourite server-side language if they don't fit in.
  • If you're one of the many Java and C# developer jumping aboard, take the time to understand dynamic typing, and how to embrace it.
  • Judicious use of object-oriented programming can help. Javascript uses a prototype-based paradigm, and you can achieve effects similar to class definitions and inheritance.
  • For complex functionality, consider a unit-testing framework like TODO JavascriptUnit.
  • Javascript runs slower than equivalent desktop applications, so optimisation is important. Also, consider issues memory usage and be aware of browser-specific bugs which might lead to memory leaks.
  • Break complex applications into multiple Javascript files, and consider managing them with On-Demand Javascript.
  • Reuse where possible. The new JSAN archive contains a growing collection of reusable, open-source, libraries and many others are available at SourceForge and individual project websites. Not that some useful libraries may not be explicitly labelled as Javascript because they are part of an overall project involving server-side code. A code-based search engine like koders.com, constrained to search for Javascript only, will help here.


How will the data be persisted?

It's possible to store some data locally using cookies. But important data must somehow be persisted server-side. The application might run entirely inside the browser, but there must be some mechanism to transfer the data. For a Fat Client, Submission Throttling is often the best choice because it is fairly transparent to the user. All you need is a function that periodically uploads all state. Then, another function can be used to pull it down when the user logs in again - a form of Multi-Stage Download. You might want to consider a general Object Persistence strategy too.


Real-World Examples

NumSum

NumSum provides the following basic spreadsheet functionality in Javascript:

  • Standard 2-dimensional spreadsheet with insertion and deletion of rows and columns.
  • User can enter values into any cell.
  • Text-formatting (bold, italic, underline a cell).
  • Text-justification.
  • Embedded links and images.

The basic spreadsheet is implemented as a table. Table cells aren't actually editable, so the script needs to simulate an editable table. An event handler ensures a cell becomes active when the user clicks on it, and that cell is then morphed to reflect subsequent user input.

GMail

GMail, like several of its competitors, presents a rich, Ajaxian, interface to a mail system. Conventional webmail offerings rely heavily on form submissions and page reloads - a new page must be opened each time the user wants to start composing an email, finish composing an email, open up an email message. With GMail, the list of emails is always present and regularly refreshed. All of these activities are handled within the browser using a combination of DOM Manipulation and Web Remoting.

Authenteo

Authenteo is an integrated JavaScript framework and web content management system. Authenteo is designed specifically for building fat JavaScript centric clients with built content management capabilities. Authenteo does Authenteo uses a persistent object model where the logic for applications is defined in the JavaScript within the persisted objects. The persisted objects as well as the JavaScript functions within are loaded on demand using the JSPON data format (an extension of JSON). Therefore Authenteo enables virtually all of the application logic to be carried out on the client including templating/rendering, data manipulation, and navigation with direct access to data structures for CSS, JavaScript, and HTML. Authenteo uses Narrative JavaScript for continuations, and by utilizing continuations, Authenteo can do true inline on-demand loading of JavaScript and data without making synchronous (locking) remote calls.

DHTML Lemmings

DHTML Lemmings shows how much can be achieved with some clever Javascript hacking. It's a full-featured implementation of the Lemmings PC game utilising a plugin only for sound - the entire game runs on DHTML, DOM, and CSS. The gameplay consists of a static image for the current level, with Sprites used to render the lemmings and other objects in the game. There is a periodic timer continuously checking the current state of each object, and DOM manipulation of the objects' properties is used to render their states at any time.

JS/Unix Shell

JS/Unix shell is a demonstration of an in-browser Unix shell. In its current form, it's a demo only. But it's capable of all the basic operating systems commands and even includes a vi editor! The approach stands in constrast to browser-side terminal emulators, which are thin applications that pass characters back and forth. With appropriate server-side integration, the application could be made into a functional multi-user application. Command-line remains the mode of choice for many power users, and this demo shows how an Ajaxian Fat Client can achieve it.

Ptable

Ptable is a complete periodic table with dozens of visualization options. However, requests to the server are extremely minimal. One request is made for all the properties data for all the elements (23KB) that is then rendered and inserted as needed by the browser. The temperature state slider calculates whether an element is solid, liquid, or gas on the client side using melting and boiling points. Colors and dynamic visualizations are computed from the stored values, and functions determine colors between min and max values and make logarithmic comparisons. Different layouts are swapped in and out by enabling and disabling a few short inline style sheets. Instant search is provided by looping over the DOM and checking for text inside certain nodes rather than going to the server. Elaborate orbital Hund diagrams (up and down arrows) and quantum numbers are computed entirely from a short electron strings (10 bytes) as needed.


Code Examples

The Wiki Demo is based on Fat Client principles, though its functionality is fairly limited. All of the interaction and rendering occurs locally. The only interaction with the server is a periodic synchronisation event, when the following occurs:

  • Pending messages are uploaded, an example of Submission Throttling.
  • All current messages are retrieved from the server, so that messages from other users are shown. This is an example of Periodic Refresh.

There is a timer to ensure synchronisation occurs after five seconds of inactivity.

 var syncTimer = null;
  
 function startPeriodicSync() {
   stopPeriodicSync();
   syncTimer = setInterval(synchronise, 5000);
 }
  
 function stopPeriodicSync() {
   clearInterval(syncTimer);
 }

The timer starts on page load, and is suspended each time the user begins to modify some text:

 window.onload = function() {
   synchronise();
   startPeriodicSync();
 }

 function onMessageFocus(event) {
   ...
   stopPeriodicSync();
 }

 function onMessageBlur(event) {
   ...
   startPeriodicSync();
 }


The script also contains a variable to accumulate pending messages whenever the user changes something:

 var pendingMessages = new Array();
 ...
 function onMessageBlur(event) {
   ...
   if (message.value != initialMessageContent) {
     pendingMessages[message.id] = true;
   ...
 }

The synchronisation event builds up some XML to post to the server, based on the pendingMessages array that has been accumulated. If no changes are pending, it simply requests the current server state. If there are changes pending, it posts those changes as an XML message. Either way, the server will respond with an XML specification of its current state.

 function synchronise() {

   var messageTags = "";
   for (messageId in pendingMessages) {
     var initialServerMessage = $(messageId).serverMessage;
     messageTags += "<message>";
     messageTags += "<id>" + messageId + "</id>";
     messageTags += "<lastAuthor>" + $("authorIdSpec").value + "</lastAuthor>";
     messageTags += "<ranking>" + initialServerMessage.ranking + "</ranking>";
     messageTags += "<content>" + escape($(messageId).value) + "</content>";
     messageTags += "</message>";

     $(messageId).style.backgroundColor = "#cccccc";
   }

   var changesOccurred = (messageTags!="");
   if (!changesOccurred) {
     ajaxCaller.getXML("content.php?messages", onMessagesLoaded);
     return;
   }

   var changeSpec = "<messages>" + messageTags + "</messages>";
   ajaxCaller.postBody
     ("content.php", null, onMessagesLoaded, true, null, "text/xml", changeSpec);
   pendingMessages = new Array();
 }

The main application logic is virtually orthogonal to server synchronisation. The only concession is the accumulation of pending messages, to save uploading the entire browser state each time. The timer and the synchronisation process know about the core wiki logic, but the core wiki knows nothing about them, and can therefore be developed indepdently. It's easy to imagine how the wiki could evolve into something with much richer browser-side features, like formatted text and draggable messages and so on.


Alternatives

Thin Client

A thin client contains only basic Javascript and frequently refers back to the server for user interaction. This is likely to remain the dominant style for Ajaxian applications, and is useful in the following circumstances:

  • Business logic requires sophisticated programming techniques and libraries that can only be implemented server-side.
  • Business logic involves substantial number-crunching or other processing which can only be performed server-side.
  • Due to bandwidth and memory constraints, the application cannot be held locally.
  • There is complex dialogue required with external services, and due to cross-domain secrity policies, those services cannot be accessed from the

browser.

Desktop Client

A desktop client runs as a standard application in the user's operating system, and connects to one or more servers using HTTP or any other protocol. Compared to a fat client, a desktop client can be richer and faster. However, the benefits of a web-enabled application are lost as a result. You can compensate for some of these benefits:

  • Portability can be achieved with a platform-neutral programming platform.
  • Centralised data can be achieved by ensuring all data is retained server-side.
  • Familiar user-interface can be achieved by tailoring to each individual platform's look-and-feel.

In some contexts, a desktop client represents the best of both worlds: rich client backed by a powerful server. In other situations, a Fat Client based on Ajax principles is a more appropriate sweet spot: powerful server, rich-enough client, and availability through a web browser.


Related Patterns

Periodic Refresh

Periodic Refresh is a relatively unobtrusive way for the client state to be enriched with any new server-side information.

Submission Throttling

Submission Throttling is a relatively unobtrusive way for the server to be notified of any significant changes that have occurred in the browser.

Rich CSS

Fat Clients often rely heavily on Rich CSS to provide a rich, desktop-like, appearance.

On-Demand Javascript

Since Fat Clients tend to contain bulkier scripts, On-Demand Javascript is useful for managing them.

Drag-And-Drop

Drag-And-Drop is familiar to many desktop users and helps to make a large application feel more natural. Whereas more conventional web clients rely on form-style interaction, Fat Clients can feel more rich if they support Drag-And-Drop.

Host-Proof Hosting

Where a Fat Client is seen as a replacement for a desktop equivalent, Host-Proof Hosting might be considered to avoid compromising on the superior security a localised solution sometimes offers. Engagement rings


Visual Metaphor

Agile development methodologies such as Scrum aim for an "inversion-of-control". Workers are empowered to plan their own activities, and management's role is to offer whatever services workers request in order to conduct those activities.


Want to Know More?