Fluid Architecture Overview
Table of Contents
- What's New?
- Technical Vision
- About Fluid Components
- Framework Libraries
- User Interface Transformation
- Component Design Principles
- How You Can Help
What's New (September 2007)
Unknown user: I've attempted to take a significant portion of the architecture as it was originally articulated at the beginning of the project, merge it with further material accumulated over the past several months, and refine it significantly based on current experience and discussions with other developers in the community.
The notion of shared libraries for common UI logic has been introduced to provide a simple set of tools with which developers can build new Fluid components with greater ease and consistency. These framework libraries consist of functionality such as keyboard handlers, AJAX connections, drag and drop features, and so on.
The intended effect of these revisions is to bring the Fluid architecture within reach of our immediate development goals, providing the community with a conceptual foundation and the beginnings of a code library on which to start building lots of components and identifying further framework functionality.
A note on terminology: While I've attempted to cut back on many of the heavier-weight features of the Fluid architecture because I felt that it was too early to define these well, I have continued to use the often overused term framework. Aside from the fact that much of the transformation functionality suggests the need for a bounded component model and lifecycle controlled from outside the component itself, I also think the term suggests a larger perspective or "worldview" within which we build our technologies. In the case of Fluid, our goal is to build a broad an inclusive framework for user interface development.
The goal of the Fluid framework is make it easier for developers to build better, more accessible user interfaces in collaboration with designers. Fluid will serve as a user interface layer across applications, encouraging developers to share their designs widely within the community.
Fluid's components provide richer and more direct interactions that are well-suited to being customized and embedded within a variety of tools and workflows. They are composable and highly configurable, providing greater flexibility to deliver a user interface that can best the meet the needs of both institutions and individual users.
The framework embraces the strengths and idioms of the Web, leveraging the server's ability to provide powerful services in a stateless manner along with the browser's dynamic environment for user interfaces. Our approach coexists well with current web presentation strategies while embracing newer Web 2.0-style interactions.
Fluid's architecture encourages server-side developers to expose web-addressable services that can be combined and directly queried by user interface components running on the client. This will enable a user experience that can break out of the typical tool and portlet silos of existing systems.
What is a Fluid Component?
Fluid components are self-contained, reusable chunks of user interface that can be easily adapted to suit different contexts within a Web application.
The Fluid conception of a component makes an attempt to correspond more closely with recurring interaction patterns and activities within a system. Components can thus be built in both the smaller and larger scales, from calendar pickers to file viewers on up to larger-scale multi-step wizards and flows. Thus, components aren't just widgets, but larger assemblages of UI behaviour built to be reused throughout an application.
Components are recurring interactions within a Web application. Some examples include:
- Wizards, multi-step indicators, tabs, menus
- Direct manipulation of objects:
- Ordering of objects, list builders, layout customizers
- Content management:
- File pickers and managers, content previewers, uploaders
On the client side, a Fluid component consists of:
- One or more HTML templates
- One or more layers of CSS
- Accessibility metadata:
- Roles, states, and properties (provided through ARIA)
- Control and presentation characteristics
Fluid components cooperate with infrastructure running on the server:
- Service logic exposed through a set of known web-addressable conventions
- Markup generation capabilities
- Component metadata and user preferences services
In order to ensure that Fluid components are highly flexible and configurable, they are specifically intended to be composable. Not only can you combine several smaller components into a larger one, but individual components themselves are composed of logical units that can be substituted or extended during development or at runtime based on user preferences.
For example, a typical component will provide a set of configurable properties that can be modified to change the behaviour of the component. Layout customizers, keyboard handlers, and connections to the server are parameterized so that alternative strategies can be plugged in. This compositional approach provides the underlying model for performing UI transformation based on user preferences.
As a concrete illustration of this, take the Reorderer as an example. The Reorderer is a very general component that can be used to order items directly on a page. When it is used within the Lightbox, the Reorderer allows the user to order items within a two-dimensional grid. However, the layout handling code is fully parameterizable, allowing alternative implementations to be substituted when needed; for example, when ordering lists instead of grids. This approach has the side effect of allowing very flexible rendering approaches: when a multi-column display isn't appropriate for a particular user — perhaps due to a small screen or the need to use magnification — the Reorder can be adapted to work with alternative types of markup by substituting other layout handlers.
Similarly, the Reorderer parameterizes its connection strategy for communicating changes in item order back to the server. The default implementation simply posts hidden input fields back to the server, but alternative approaches could be specified as needed. Keyboard bindings should also be adjustable, making it easy for designers and developers to customize the interaction and allowing users to avoid conflicts with assistive technologies.
Types of Components
Markup-driven components manipulate and work with markup generated on the server. They are able to handle arbitrary streams of markup, with an informal contract defined between client and server using meaningful ids, CSS classes, or ARIA metadata to denote elements of interest to the component.
Fluid's first example of a markup-driven component, the Reorderer, can accept any sort of markup in which the reorderable elements have been identified using a CSS class of
The markup-driven approach is sometimes referred to as AHAH or Asynchronous HTML and HTTP, emphasizing the use of the established markup generation and request handling capabilities on the server. This is in contrast to data-driven components, whose primary means for communication with the server is accomplished by sending data back and forth in JSON or XML format via AJAX.
The obvious advantage of markup-driven components is that they don't require any additional template processing logic running in the browser. They can easily interoperate with most any server-side toolkit that can deliver the appropriate markup to the widget and respond to typical HTTP requests.
Again using the Reorderer as an illustration, any server can use the Reorderer if it is able to satisfy three simple requirements:
2) It can deliver markup containing
reorderable classes wrapped in a named container element
3) Using the default connection strategy, can respond to a POST request containing the order indices as form values.
Data-driven components primarily communicate with the server using an AJAX approach, where requests are made to the server to satisfy a component's data needs, usually in XML or JSON formats. This approach offers richer semantics and structure for data that the component will manipulate and render into HTML itself. As a result, template-processing is often delegated to the component, rather than expecting the server to deliver fully-baked markup to the client side.
The data-driven approach will often involve a higher number of round-trips to the server to satisfy data requests, as well as more processing on the client side to parse XML data and render it. The primary advantage to data-driven components is greater autonomy for the component; fewer requirements are placed on the server to deliver markup, and the component can built up its own views by making calls into to the application's service layer.
One potential risk for data-driven components is the additional client-side markup rendering cycle may add visible flicker or unpredictability as the browser loads the page.
The markup-driven and data-driven approaches may well be combined within a single component where appropriate.
- Keyboard accessibility handlers
- Accessible drag and drop, including ordering
- Common communication strategies with the server (eg. for validation)
- ARIA support: a model for setting states and properties on DOM notes.
User Interface Transformation
The notion of user interface transformation is at the core of Fluid's goal to offer an experience that can be adapted to meet a user's personal needs. The Fluid framework will include a transformation service that allows an application to modify its appearance and behaviour by dynamically swapping or augmenting existing UI components with other components that have been designed for particular use cases or accessibility accommodations.
When the user requests a user interface, the transformation service inspects the default composition and cross-references the user's stated preferences with the library of alternative components, CSS, and markup. It then determines which of the available options are best suited to the user's needs and automatically delivers a new version of the user interface.
For example, a user who has a mobility impairment and relies on an on-screen keyboard for input and navigation may benefit from alternative or augmented navigation schemes. The transformation service is able to add additional components to the interface dynamically, such as a summary of essential page landmarks. Alternatively, complex navigational components such as nested menus may be swapped out dynamically for others that have been designed to allow easier access to frequently-used functions within the application. Web form components could be replaced with other components that provide Ajax-based word completion or other appropriate accommodations.
Illustrating the Transformation Process
This is a back of the envelope sequence diagram showing the relationship between the view renderer (or component framework in client-side scenario) and the transformation service and its collaborators.
Types of Transformation
At least initially, the types of transformations supported by the Fluid framework fall into a few discrete categories:
- Flexible Layouts and Linearization
- Expandable spacing, sizing, and layout for large print or small screens
- Flattening multi-column views for small devices or screen magnification (spatial linearization)
- Flattening multi-step views into a single composite, or sequencing large pages (temporal linearization)
- Enhanced Navigation
- Additional site maps, summaries, breadcrumbs, or other alternative views of navigation structure
- Additional graphic cues, structural markers, focus points
- Alternative Control Strategies
- Keyboard handler remapping to avoid conflicts with assistive technologies
- Modified tabbing or keyboard behaviour: for example, quick vs. comprehensive tabbing modes
- Components optimized for a particular control type (eg. mouse or keyboard)
At the same time, these types can be also be categorized based on how the transformation is achieved technically
- CSS & markup substitutions
- Flattening muli-column views
- Flexible layouts
- Addition of graphic cues, structural markers, focus points
- Flattening multi-column views
- Keyboard remapping
- Alternative tabbing behaviour
- Addition of new components
- Enhanced navigation (addition of summary view or breadcrumbs)
- Sequencing large pages into multiple steps (ie. addition of step indicators and so on)
- Substitution of one component for another
- Enhanced navigation
- Components optimized for control type
- Recomposition or reaggregation of components
- Flattening multi-step views
- Sequencing large pages into multiple steps
The key to making transformation viable is knowing enough about the characteristics of a user interface component to reliably interpret the user's preferences and find appropriate alternatives. Components need to be described by metadata that identifies a component's role, presentational characteristics, and control requirements. Specifically, we need to know things like:
- What types of layouts does this component support?
- Are graphics included in the component? Text? Other media?
- Does the component have any timing requirements?
- How can the component be controlled?
- Does it involve activating items such as links and buttons?
- Does it include text input?
- Does it require the mouse? Keyboard?
- Does this component provide an alternative to other components based any of the above characteristics?
Some of this metadata is already available in the ARIA specification. Much of it, however, will need to be worked out during development of new components. Additionally, a corresponding set of user preferences will
be required to allow users to assert a need for alternatives.
Where to Locate the Transformation Service?
One of the primary questions we still need to determine is where the transformation service should be located. On the client? On the server? Partitioned across both?
2) Who should render alternative markup and stylesheet links?
These questions suggest that a hybrid approach is in order, where the server delivers alternative markup as well as hints to the client on how to assemble an appropriate collection of UI behaviour for it.
Transformation on the Server
The primary rationale for placing the transformation service on the server-side is to leverage proximity to the server's markup generation abilities. This is particularly noteworthy since many of the transformation scenarios outlined above are fairly static in nature; users will rarely want the interface to transform itself in midst of doing something important. Hence it is simpler and more efficient to deliver an alternative interface when the component's markup is being first generated.
The downside to this scenario is largely one of closer coupling to the server-side presentation framework. While the service itself could be implemented in a relatively agnostic form, much code would still need to be built for specific frameworks. Another downside is the relatively inflexibility of many server-side frameworks in terms of their ability to dynamically deliver alternatives midway through the view rendering process.
Requirements for a server-side presentation framework
In order to enable runtime transformation of user interface component, a server-side framework needs to provide the ability to branch during template rendering into another, independent template powered by its own unit of rendering logic.
Server-side markup generation needs to be template-driven — as opposed to emitting HTML directly from code — so that components can be more easily reconfigured by making simple markup changes to the template. This suggests the need for enough symmetry between the structure of a main view or page and the components within a page, such that they both have a workable separation between logic and HTML presentation. In other words, the actual components need to be template-driven, not just the overall page. This is in contrast the the JSP taglib style, where only the page as a whole is rendered from a template, whereas the tags themselves generally emit chunks of markup directly from Java code.
Transformation requires the ability to substitute one component for another during the rendering phase, so a framework needs to support substitution of equivalent branches such that an alternative component can take the place of an originally-specified component. In non-component speak, the framework needs to be able to substitute one bundle of markup and its corresponding controller for another bundle at runtime.
Transformation on the Client
Moving transformation to the client largely decouples the most complex aspect of the Fluid framework from a dependency on specific server-side frameworks. The server would deliver the user interface to the client as it was originally designed, and then the client-side transformation service would perform any necessary modifications.
The upside of this, as mentioned earlier, is that it locates the transformation behaviour within the friendly dynamic environment of the client. The possible downfall of this approach is that it potentially delegates too much responsibility to the browser, causing slower page loads and unpredictable rendering behaviour while transformation occurs.
The Client-Side Framework Illustrated
Requirements for a server-side presentation framework
In this scenario, much less demand is placed on the server side presentation framework in terms of its need to support swappable components. Instead, the server is expected to produce markup with sufficient additional semantic cues to convey the capabilities of the default user interface.
Fluid Component Design Principles
- Build your components out of smaller units. Allow layout handling, keyboard controls, and so on to be configured by plugging in alternatives or setting properties to change modes.
- Favour HTML as a means of binding between client and server where possible. This opens up much greater possibility for graceful degradation and non-Fluidic alternatives to access the same underlying server-side behaviour.
- Describe everything you can about your components: add ARIA markup and help with the definition of more UI semantics
- Follow the DHTML Developer Checklist to ensure that your components provide a baseline of accessibility and portal-friendliness.
- Take advantage of the whole design lifecycle provided by the Fluid community. Work closely with designers, user testers, etc.
How You can Help
There are a lot more details that need to be worked out. Here's a shortlist of critical areas you can help out with:
- Determining the most suitable client/server partitioning for the transformation service
- Determining conventions for messaging between client and server. UVB?
- Building out framework libraries for common UI behaviour
- Helping to define the structure for user interface metadata and preferences
- Building new components