Why Tagneto

Motivation

Tagneto was developed to aid using an MVC approach for building XML user interfaces (UI). HTML UI that uses JavaScript as the controller is the main target of the framework, but parts of it can be applied to any XML user interface. The framework is based on the following principles:
  1. There are two types of UI construction:
    • Layout UI. This type of UI construction is for general layout. It does not depend on user's data, or data that depends on the specific runtime request. This type can be considered part of the View in an MVC pattern.
    • Data UI. This type of UI can only be constructed during the runtime of the UI. This type of UI is generated by an interaction with the Controller and Model in an MVC pattern.
  2. Layout UI construction can be done before any runtime requests are received. It can be constructed during a build process or as part of deploying the UI files to the server.
  3. All Data UI should be generated on the client. The client in this case is normally a web browser.
  4. Server processing should be limited to providing data services and back-end business logic only.
Effects of the principles:
Approaching UI construction this way allows for the general UI Layout files to be served statically from a web server. This in turn allows for caching of the files by proxy servers and by clients. Some care needs to be taken with versioning, but there are simple approaches that solve the issue at the expense of longer term cacheability.

Since all data UI happens on the client, the state machine for the UI has to be centralized in the logic engine running on the client. This normally means a script language like JavaScript. This frees server application logic on the server to focus on data services and core business logic only.

Normally UI flow and state change more frequently than the core data services and business logic, so using partitioning specified by the principles allows for a clearer, more efficient separation of work between two teams. This allows the implementation of the server data services to be done in a separate technology than the UI. It even allows the possibility to be served from a different place than the server, even locally on a client machine (although there are browser security models to consider).

For rich web applications, there is better performance with this approach because:
  • UI is served as static files -- no application server/processing modules are needed to serve the UI.
  • The UI can be cached by proxy servers, or even in the client browser cache.
  • Since the UI is static and cacheable, it means there is a very low latency between user request and a response. This is particularly important in a broadband world where server response latencies become the speed bottleneck.
  • Perceived performance by the user. The sooner the client gets some UI, the sooner it can start to generate it for the user, and start retrieving additional assets for the UI (images, scripts, data).
  • There are techniques to allow data caching during user session in the browser, avoiding further server load.
The above runtime performance advantages could also be leveraged to actually scale back the amount of server power needed for the application, improving cost performance.

For development, prototyping is made easier, since the data services easily can be "canned", static XML/JavaScript responses.

MVC Challenges

There are particular Model, View and Controller challenges in using the MVC framework described above for web applications, and Tagneto provides tools and support to address the challenges.

Model

Getting the Model

In the strictest conformance of the above principles, the dynamic Model data for the page (user's data, request-dependent data) is not combined with the layout HTML on the server. It happens on the client. There are a few ways to retrieve the Model with this approach:
  • Dynamically created SCRIPT tags. A SCRIPT tag can be created in JavaScript to pull in model data. This has the advantage of working across site domains, but requires the Model to be in JavaScript form, and there are some issues with knowing when the Model has finished loading. Large requests will not work with this approach either -- only requests that are small enough to fit as an HTTP GET request (a safe size seems to be about 1KB).
  • Hidden FRAME or IFRAME. A hidden FRAME or IFRAME could be used to send requests to the server for the Model. This approach limits requests to specific site domains, but it allows the Model data to be either XML or JavaScript. It has a similar issue to the dynamic SCRIPT tag approach as far as knowing when the Model has finished loading. It could also trigger the "wait" cursor, and in MSIE, the user may here a "click" sound for each requests (the same sound MSIE uses whenever a new page is requested). HTTP GET/POST requests are allowed with this method, allowing for very large request sizes.
  • HTTPXMLRequest object. The HTTPXMLRequest object is supported by most modern browsers. However, the SCRIPT or FRAME/IFRAME approach may work in a larger set of browsers. Model data can be either XML or JavaScript encoded, but it can only come from specific site domains (normally the domain that the requesting HTML came from). It has an explicit callback when the Model has finished loading. HTTP GET/POST requests are also supported, and other HTTP commands may work too (but there may be issues with Safari).
Tagneto has specific JavaScript libraries that allow using these approaches to getting the Model.

Format of the Model

When the model data is retrieved from the server, it should either be encoded as XML or JavaScript. Once the browser receives the data in XML or JavaScript, the Tagneto approach favors holding the data as JavaScript structures, but XML could be used directly with an XSLT style sheet.

The decision on whether to fetch XML or JavaScript encoded Model data will probably be most dependent on the server providing the API calls. Using XML could allow re-using some existing data APIs that the server exposes. It would be more performant to retrieve the data as JavaScript, since the Tagneto approach prefers that format, and a conversion will have to be done on XML data. However, that might require custom adapters on the server to convert data to the correct format. Approaches like JSON may make this easier to do.

Tagneto has script libraries that convert XML to JavaScript, and convert JavaScript to an encoded type suitable for GET/POST requests.

View

View Assembly

An application server is not required to serve the View HTML files. However, for large projects, there are many pieces of HTML/CSS/script that are reused as part of many pages. Some sort of tool is needed to build the final View HTML pages from HTML fragments. This tool should be able to run offline, as part of a "compile" step for the application. 

If the complete View HTML page is built up from HTML fragments, the tool should have the ability to put the code in the right places in the final HTML file (<script>, <style>, <link> tags should go in the <head> area), and the HTML fragments should be able to specify an "API" for inclusion in the final HTML file.

Tagneto gives the developer a set of tags and tag handlers to do effective View assembly. It is easy for the developer to define new tags that use the built-in tag handlers.

HTML Sanitation

Using HTML fragments to build a larger page can lead to a final HTML file whose source is not easy to read. In addition, when the HTML is ready to be pushed to a production environment for end users, it may be desirable to strip out comments and excessive white space to cut down on size. Validating the HTML and JavaScript at "compile time" for the UI would also avoid unwanted bugs that may only surface when a user actually uses the application.

Post file filters are supported in Tagneto that allow processing the final HTML pages. Right now, only a file filter that supports stripping whitespace and comments is built. HTML pretty printing and validation is on the task list.

Controller

Grouping event handlers

Finding all the event handlers on a page in traditional HTML/JavaScript pages is hard to do. Event handlers can be embedded directly in HTML as an element's attribute, and reference functions in an external script file. Event handlers can be added during runtime via JavaScript. The ctrl:listen tag allows a developer to group all the event handlers on a page so it is easy to edit, but allow for the flexibility of binding the event handlers as element attributes or dynamically binding in script.

Using JavaScript to create HTML

Using JavaScript to create HTML for data UI can be messy. Using DOM methods (like appendChild()) is harder to do than "just writing HTML". Using innerHTML to inject HTML requires the HTML to be properly escaped in a JavaScript string -- something that is hard to read and maintain. Tagneto's ctrl tags allow the developer to just write HTML and allow the framework to escape the HTML properly.

Allowing browser caching of pages with dynamic URLs

It is normal for web pages to need dynamic information, usually in the form of GET (querystring) parameters, like "?name1=value1&name2=value2". However, asking for a page like that may not be cacheable, and the browser will unload the current page to navigate to the new URL. If these effects are not desired, Tagneto's Ctrl.js can be used to allow passing of dynamic parameters via the fragment identifier of the URL, like #name1-value1.

Why Not Something Else?

Tagneto was developed because of perceived shortcomings with the existing alternatives. The shortcomings may no longer exist in the alternatives (Tagneto was started in the summer of 2004), or Tagneto's author may have missed solutions or misunderstood the alternatives.

The main alternatives seemed to be Java Server Pages, Active Server Pages or PHP. They all have a similar design (from the perspective of a developer using them to build UI), so they will be referred to as SP (Server Pages) for the rest of this document. All of the SP variants are valuable and useful, and Tagneto can be used with them. Tagneto's motivational principles and the author's subjective preference gives rise to some differences between Tagneto and SP:
  • Tagneto is designed to not need an application server to render the HTML pages. For many types of web applications, a good deal of work can be done "offline", on a developer's box as part of a compile or transform step. If Tagneto's motivational principles are strictly followed, all of the View can be generated offline, and this allows for long cache times. For many web applications (including this web site), that is the only source processing that needs to be done.
  • It is very easy to mix the Model, View and Controller in SP. It is still possible to do that in Tagneto, but the offline compile step really forces the developer to consider the MVC boundaries.
  • SP's syntax. This is a highly subjective issue, so take it with a grain of salt. The syntax to demarcate SP parsing does not look at home in HTML, and the script languages used for server processing are different than the browser's JavaScript language for client processing. It would be nice to use just one language for both. 
  • XML syntax for demarcating SP parsing can be used, at least with JSPs, but it requires the entire document to be valid XML. Tagneto can be used in non-valid HTML/XML. However, the tags that Tagneto will handle do need to be either XML conformant, or conformant to a defined alternate syntax. Support for a XML syntax and a XML Entity-like syntax is built in, and new ones can be defined.
  • The SP include mechanism for including HTML fragments is weak on scoping the script variables and for enforcing required script variables needed for the include file. Tagneto allows for creating a child script scope for just the included file, and the view:inclueparam tag allows specifying required script variables needed for the included file.
  • Tagneto is non-invasive to the source. No special tags need to be defined in the HTML that is to be processed. The tagneticconfig file specifies the parsing and tag rules for the source. This ability coupled with overlays and the TagDefine functionality allow for interesting possibilities.
Jelly was considered early in the project, but the requirement that the source be valid XML was not compatible with the Tagneto design goals.

Why Java?

Java was Java used to build the View Assembly tool in Tagneto (The Java runtime is needed only by the web developer, not on the web server or on the end users computer). Java was used because that language is the most comfortable one for the author. It is also nice that it is cross-platform, and has internationalization and localization features built in. Being object-oriented makes it nice for other developers to extend Tagneto. Rhino, JavaScript engine that included E4X, was readily available for it too.


Copyright © 2005 tagnetic.org.