Chapter 2: Architecture

Introduction | Structure - jQuery Templates | Modularity | Communication - Direct Communication, Loose Communication | Navigation | Data | Architectural Alternatives | Summary | Further Reading

Introduction

The Mileage Stats Reference Implementation (Mileage Stats) is a cross-browser, ASP.NET Model-View-Controller (MVC) application that takes advantage of the features of modern browsers. The application offers two types of user experiences:

  1. A traditional website experience. In this approach, a form post and page reload are executed each time a button or hyperlink is clicked.
  2. A rich website experience. In this approach, the initial page is loaded once, and server requests are only made when new data is required or updated. In addition to other user-friendly features, the lack of a full-page reload enables the animation of client-side state changes.

The rich website approach provides a superior experience for the user, as the application feels more responsive and more like a desktop application. However, because some users do not have scripting enabled or available on their user agent (web browser or accessibility tool, such as a screen reader), which is necessary for the partial-page reloads, we must also support the traditional website experience.

In the traditional approach, the ASP.NET MVC controllers are responsible for acquiring data and for returning a built-up view that consists of HTML structure and data. In the case of the rich website experience, we perform asynchronous data requests and the controller returns only data. The client then renders the data in the user interface (UI) without reloading the whole page.

Supporting both these experiences introduces complexity that requires careful planning on both the client and server sides to ensure that the application is responsive, maintainable, has a clean separation of concerns, and is testable.

You should determine early in the design phase which experience the user should expect in each browser and browser version the application will support. If you choose to support older browsers, you may limit your technology choices and affect the run-time experience of the application. Shims and polyfills, such as those that provide HTML5 support, are available for adding support for some technologies in older browsers, but these come at the cost of additional dependencies (see "Further Reading" at the end of the chapter to learn more about shims and polyfill solutions). Making decisions early on about which technologies you will need to support allows you to establish realistic expectations for users and project stakeholders.

This chapter provides a high-level map of the Mileage Stats client-side architecture, and is divided into five areas of discussion: structure, modularity, communication, navigation, and data.

  • Structure refers to client-side HTML structure and manipulation. It is represented below as the Template.
  • Modularity refers to how a clean separation of JavaScript objects helps create a more maintainable application. It is represented below as the Widget.
  • Communication defines how JavaScript objects communicate. It is represented below as Pub/Sub.
  • Navigation explains how to manage user gestures and coordinate animations. It is represented below as Navigation and the Layout Manager.
  • Data provides guidance for client-side data requests and data caching. It is represented below as the Data Manager.

Mileage Stats client architecture

Hh404097.931880a6-9e1b-4cc4-bd37-c4f92305eaec(en-us,PandP.10).png

In this chapter you will learn:

  • Options and strategies for getting the right HTML to the client.
  • The advantages of modular code, and techniques for using jQuery UI widgets.
  • How the Publish/Subscribe (pub/sub) pattern can be used for loosely coupled communication.
  • How to solve browser history and back-button problems when the site doesn't perform full-page reloads.
  • How a loosely coupled data layer can simplify caching for client-side data requests.
  • How the Mileage Stats team solved a number of challenges related to structure, modularity, communication, navigation, and data.

The technologies and libraries discussed in this chapter are JavaScript, jQuery, jQuery UI Widgets, and jQuery Back Button & Query Library (jQuery BBQ).

Structure

Websites like Mileage Stats provide an engaging user experience when viewed using modern browsers with JavaScript enabled. The site can also be viewed without JavaScript enabled and will function when viewed in an older browser.

To provide an engaging, responsive, and interactive experience, the application needs to manage client-side structure changes without performing full-page reloads. This requires client-side loading, creation, and replacement of HTML fragments or pages.

To support both rich and traditional user experiences, the Project Silk team chose to have the web server generate the initial HTML; then, after using JavaScript to detect the browser capabilities, we enhanced the user experience in capable browsers by replacing the server-generated HTML structure with a client-side version. Elements replaced include portions of HTML, button actions, and CSS classes. Enhancement can mean adding animation, page transitions, or Ajax functionality to client-side elements. Client-side enhancement of server-generated HTML is called progressive enhancement. Progressive enhancement adds features to the client-side experience based on browser capabilities.

After the initial enhancement of the server-generated HTML, the client-side JavaScript responds to user gestures, requests data, and initiates UI changes without posting back to the server.

Client-side UI structure can be generated with JavaScript, loaded on demand from the server, or rendered by a plug-in or a library. Initially, the team tried on-demand loading of granular HTML fragments from the server. This approach was motivated by the team's desire to limit the creation of HTML to a single location. However, this approach failed to provide the desired result, so the team changed tactics and used jQuery templates instead. See Chapter 7, "Manipulating Client-Side HTML" for a full explanation of this choice.

jQuery Templates

jQuery templates are HTML markup with inline JavaScript expressions that are used to populate values in the markup. The jQuery Template plug-in applies data to the template and renders the output into the document object model (DOM). Mileage Stats uses jQuery UI widgets to coordinate the data retrieval, applying of the data to the template using the plug-in, and overwriting the DOM element.

jQuery template rendering in Mileage Stats

Hh404097.ff053acf-6dc5-4ccd-8a10-45c415c07e61(en-us,PandP.10).png

The data can be a single object or an array of objects. jQuery templates separate structure and data, making the application easier to code, test, and maintain.

If you use ASP.NET MVC or ASP.NET Web Forms, you can use the rendering engine to dynamically create or modify the jQuery template while it's being rendered. Mileage Stats uses this capability to inject URLs and data- (pronounced "data dash") attributes into the templates at render time.

Mileage Stats loads all jQuery templates as part of the initial page load. Preloading templates simplifies the client-side application and provides much faster client-side rendering than on-demand loading of templates.

For more information on the jQuery Template plug-in and authoring templates, see "jQuery Templates" in the "Further Reading" section. For more information on jQuery templates in Mileage Stats, see Chapter 7, "Manipulating Client-Side HTML."

Modularity

Modularized code simplifies the overall application, establishes clear boundaries of responsibility, provides separation of concerns, increases testability, eases maintenance, and enables reuse. The modularization of code in Mileage Stats is achieved by composing client-side JavaScript into jQuery UI widgets and JavaScript objects.

jQuery widgets are objects attached to page elements that supply services for managing lifetime, state, inheritance, theming, and communication with other widgets or JavaScript objects. Objects in Mileage Stats belong to one of the following functional categories:

  • UI. Includes these jQuery UI widgets: vehicle, vehicle list, information pane, vehicle details, vehicle fill ups, vehicle reminders, registration, statistics, summary, status, header, and charts.
  • Behavior. Includes the tile and layout manager widgets, and JavaScript objects for pinned sites and validation.
  • Infrastructure. Includes JavaScript objects for data access, caching, and pub/sub messaging.

The jQuery widgets that compose the Mileage Stats Dashboard are pictured in the image below. The complexity of the application demonstrates the need for modularization. By breaking the implementation into discrete, loosely coupled objects, the client-side code is much easier to understand, author, maintain, test, and debug.

  1. Pinned sites. JavaScript object that provides the pinned sites implementation for Windows® Internet Explorer® 9.
  2. Status widget. Provides management and display of user notification messages.
  3. Summary widget. Acts as a container, managing its child registration, statistics, and reminders widgets.
  4. Statistics widget. Displays summary statistics for all vehicles.
  5. Reminders widget. Lists overdue and upcoming maintenance reminders. Manages the action of clicking on a reminder.
  6. Layout manager widget. Services navigation requests and coordinates UI layout changes.
  7. Vehicle list widget. Displays the vehicle tiles in a one-column or two-column listing. Invokes the child widget animation when required and controls when child widgets are displayed in expanded or contracted view.
  8. Tile widget. Provides drag-and-drop capability for the child vehicle widget.
  9. Vehicle widget. Displays vehicle information in expanded or contracted view. Manages the actions of each button.
  10. Header widget. Provides top-level navigation and user name display. Manages actions when a hyperlink in the header is clicked.

Modularization in Mileage Stats

Hh404097.4735b668-8b87-4a57-9b04-d8ed6eb368a8(en-us,PandP.10).png

For more information on modularity in Mileage Stats, see Chapter 5, "Modularity." For more information on jQuery UI widgets see Chapter 3, "jQuery UI Widgets" and Chapter 5, "Modularity." For more information on pinned sites, see Chapter 10, "Application Notifications."

Communication

jQuery widgets and JavaScript objects help you modularize your code, but these objects are not isolated islands; rather they are small objects that work together to form the complete application. Well-defined communication between objects is critical not only from a functional view, but from an architectural view as well.

If not carefully planned, communication between objects can lead to tight coupling and undesirable dependencies. Mileage Stats objects either communicate directly with one another, or loosely by using a publish and subscribe pattern (pub/sub).

Direct Communication

Direct widget communication is typically reserved for high-level widgets controlling lower-level widgets, such as when the layout manager tells a widget to hide or show itself.

Layout manager and pub/sub

Hh404097.f3fa1724-74ca-483a-af31-e9db292c3d24(en-us,PandP.10).png

Loose Communication

Pub/sub is a messaging pattern that enables loose communication between publishers and subscribers. When a message is published, zero or more subscribers will be notified. A pub/sub object manages communication, relieving the publishers and subscribers of needing direct knowledge of one another. Pub/sub messages are individually defined and can optionally contain a payload.

The pub/sub pattern provides clean separation between the object invoking the action and the object that handles the action. This separation allows the publisher and subscriber's internal implementations to evolve without affecting each other.

Mileage Stats has its own pub/sub implementation that provides for loose communication. For example, the Status widget subscribes to the status message. The status message has a payload that contains message, type, duration, and priority values. Publishers of the status message provide these values when publishing this message.

Mileage Stats widgets have publish and subscribe functions passed into their options object during construction to decouple them from the pub/sub implementation.

For more information about the pub/sub implementation in Mileage Stats, see Chapter 8, "Communication."

Navigation

Rich client-side web applications like Mileage Stats do not perform full-page reloads each time a button or hyperlink is clicked. Instead, client-side application code handles these events.

The jQuery BBQ plug-in is responsible for providing address bar URL changes. Changing the address bar URL performs two functions. First, it allows users to bookmark addresses so that they can return directly to a particular application state. This is known as deep linking. Second, it enables the browser history and back button to perform as the user expects.

The Mileage Stats layout manager is a widget that works in conjunction with the BBQ plug-in to service navigation requests. It subscribes to the BBQ plug-in hashchange event, and initiates layout changes based on address bar URL changes.

Navigation and layout manager

Hh404097.c92415c2-1f7a-40ae-a32b-04a88954c2c1(en-us,PandP.10).png

Along with hiding and showing UI elements, the layout manager is also responsible for initiating UI animations during navigation. The layout manager does not perform the animation, but sequentially calls methods on one or more lower-level widgets, resulting in an engaging UI transition.

As part of the layout manager's top-level widget responsibilities, it subscribes to several pub/sub messages and invokes lower-level widget data refresh methods when those messages are published. For more information about navigation and the layout manager, see Chapter 9, "Navigation."

Data

When designing your client-side data architecture, several key decisions will impact application performance, maintainability, and browser support. Will data requests flow through a central object or will objects make direct calls to the server? Will data be cached, and if so, how much? Will data be prefetched, and if so, how much? Answers to these questions will vary based on your application's specific requirements.

In Mileage Stats, all data requests are made via Ajax and are routed through the data manager. Having a single object handle data requests simplifies the client-side calling code, improves application testability, and facilitates cleaner application evolution when client-side libraries advance or change. The single data manager object also affords you the opportunity to implement client-side data caching in a central location. Data is cached in a JavaScript object, rather than using HTML5 local storage or similar APIs, in order to meet the cross-browser requirements of the application.

Mileage Stats prefetches chart data during the initial page load, enabling instant application response when the user navigates to the Charts page. Whenever data is returned from the server, it's cached. This can make the application more scalable because repeated requests to the server for the same data are no longer necessary, requiring less server processing per user.

Widgets and JavaScript objects request their data from the data manager. The data manager services the request, first checking if the request should be cached, and if so, checks the cache before making a call to the server. Upon successful completion of the request, the returned data will be added to the cache, and then passed to the calling widget. If an error occurs, the error will be returned to the calling widget.

Data request

Hh404097.e7412d75-e6d8-46e4-a381-cda03e529eb5(en-us,PandP.10).png

For in-depth coverage of data management and caching, see Chapter 6, "Client Data Management and Caching."

Architectural Alternatives

The Project Silk team built Mileage Stats using jQuery UI Widgets as a way to provide modularity in JavaScript while keeping external dependencies on other libraries to a minimum. This is an effective way to separate different client-side concerns and facilitates testability and readability of the code base. This approach worked well for Mileage Stats, but it isn't the only option.

A common UI design pattern separates the application's user content (the model) from the details that dictate how that information is displayed (the view). This separation necessitates logic that connects these two concepts (the controller). The MVC pattern has been implemented as described here and has also been adapted to specialized uses such as data binding that have resulted in similar patterns such as the Model View View-Model (MVVM) pattern. There are popular JavaScript libraries such as Backbone.js and Knockout.js that, for all intents and purposes, implement the MVC and MVVM patterns, respectively. There are also more comprehensive JavaScript frameworks such as SproutCore, YUI, and the Dojo Toolkit that aim to address more aspects of the client-side application in a single framework rather than using various libraries, each with a specific purpose.

The use of these libraries does create more dependencies, but this usually has a positive impact on the overall design of the application by making it easier to control the separation of concerns that is so important to complex user interfaces. If your UI has a number of screens made up of multiple regions and includes complex interaction patterns, and having additional dependencies is acceptable to you, you should consider applying these patterns and using these libraries. A design the Project Silk team is interested in investigating in the future involves the use of jQuery UI Widgets that can be data bound within an MVVM implementation such as Knockout.js.

Summary

Building a rich web application that reduces the number of full-page loads, includes animations, and is responsible for updating the UI dynamically requires a thoughtful approach to managing structure, modularity, communication, navigation, and data. This chapter provided a high-level view of the Mileage Stats client-side application architecture. The following image shows the client-side objects and their implementation mapped to libraries or frameworks.

Mileage Stats client architecture technology map

Hh404097.7d77b08a-90ca-4cb8-b0a0-15a75f425697(en-us,PandP.10).png

Further Reading

For more information on jQuery UI widgets see Chapter 3, "jQuery UI Widgets," and Chapter 5, "Modularity."

For more information on jQuery templates in Mileage Stats, see Chapter 7, "Manipulating Client-Side HTML."

For more information on pinned sites, see Chapter 10, "Application Notifications."

For more information on modularity in Mileage Stats, see Chapter 5, "Modularity."

For more information about the pub/sub implementation in Mileage Stats, see Chapter 8, "Communication."

For more information about navigation and the layout manager, see Chapter 9, "Navigation."

For more information about data management and caching, see Chapter 6, "Client Data Management and Caching."

For more information about the libraries and guidelines discussed in this chapter, see the following:

jQuery:
http://jquery.org

jQuery Templates:
http://api.jquery.com/category/plugins/templates/

Backbone.js:
https://documentcloud.github.com/backbone/

Knockout.js:
http://knockoutjs.com/

SproutCore:
http://www.sproutcore.com

YUI:
http://developer.yahoo.com/yui

Dojo Toolkit:
http://dojotoolkit.org

"jQuery BBQ: Back Button & Query Library" on Ben Alman's blog:
http://benalman.com/projects/jquery-bbq-plugin/

"Filling the HTML5 Gaps with Polyfills and Shims" from Rey Bango's MIX11 session:
https://channel9.msdn.com/Events/MIX/MIX11/HTM04

"Making HTML5 and CSS3 work with polyfills and shims" by Rey Bango on .net magazine:
http://www.netmagazine.com/features/making-html5-and-css3-work-polyfills-and-shims

Next | Previous | Home | Community