Performing an action progressively in increments is a generic design pattern that we can see in many contexts. The goals of the pattern vary depending on the context.
- Reduce perceived latency
- Improve the usability
- Avoid the information clutter
- Optimize resource usage (CPU, Memory etc)
- On-demand resource usage (CPU, Memory etc)
Here are few examples of this pattern
This is a UI design pattern. The goals typically here are to avoid the information clutter and improve the usability. General approach is to break up the content into smaller chunks/blocks, display one or two chunks to begin with and show the other blocks progressively as required. The techniques to hide/show content and the events that trigger progressive display are presentation technology dependent.
The pattern not only makes the digestion of content easy for novice users but also makes it possible for the advanced users to explore further – in a way helping the transition of novice user to advanced user. A popular avoid-the-clutter example that you may be familiar with is twitter.com site that displays controls (Reply, Retweet etc) when the mouse is hovered on the tweet.
Some relevant blog posts that talk about this technique in detail
This is another UI design pattern. The goal is to reduce the perceived latency. Like the previous technique, the general approach is to break up the information into smaller chunks (if not already broken in the original content), process each chunk and display before proceeding with another chunk.
Browser is a popular example where the various pieces of information in a web page (html, java script pages, CSS stylesheets, images etc) are processed in incremental and parallel fashion. The processing includes downloading the entity, parsing the entity, updating DOM. The processed entities are then displayed without waiting for other non-dependent entities. You would also see this pattern at work when a browser is rendering an image where the resolution of the image is improved progressively as the image data is getting downloaded.
maps.google.com is another example where the tiles comprising the map are separately downloaded, processed and displayed progressively. The end result is that you see parts of the map getting displayed instantly and the rest being filled in progressively.
Progressive Collection of Information
This is again a UI pattern where the goal is to ask the user for information incrementally as required based on the context. The traditional approach of displaying a form with dozens of fields and expecting the user to fill-in all in one shot runs the risk of user loosing interest and not providing the desired information.
A typical user registration form in many sites asks for the following information:
- Email address
- Mailing address
- Payment Details
- Areas of Interest
Instead, one can just ask for Email address to begin with. When the user navigates the site and purchases an item, then ask for Payment details. If the user buys an item that needs to be shipped, ask for mailing address at that point.
If you think about it, this is no different from how it works in real-life. When you got a brick-and-mortar shop, you are not disclosing any of these details up front. Only when you purchase an item, one is asked about payment details.
This is a software design pattern. Goal is to process a stream of information as the stream is downloaded as opposed to waiting to process until the end of the stream happens. In practice, with certain large or never ending streams, it mayn’t be possible to wait for the end of the stream and the only option left is this pattern. Use of this pattern not only helps in reducing the perceived latency, it would result in optimal use of resources (memory, CPU etc) in some cases.
A familiar example is XML Parsing. In a server environment where the server is handling multiple requests containing XML documents asynchronously in non-blocking manner, not all request data will be available in one shot due to the inherent nature of network delays and sharing across clients.
If the requirement is to build a DOM of this XML document, a progressive XML parser would fit the scenario better than a traditional non-progressive XML parser. A non-progressive parser either would block on the stream because the data is not available yet (most Java parsers fall into this category) or expect that entire document data be provided in one call. A progressive parser, on the other hand, would accept the input in chunks/increments, parse the chunk and then return the control back to the caller. When more chunks of data are available, a progressive parser would be able to continue parsing.
If the requirement is instead to use a SAX parser to search and extract certain data from the stream, a progressive XML parser would not only reduce the latency, it would also reduce the memory usage (one can discard intermittent data structures and previously received chunks of stream data).
In fact, the only publicly available commercial/open source C language XML Parser that I know is capable of doing progressive parsing is libXML. At apigee.com, my previous company, we have built couple of progressive XML parsers (one based on lex/yacc and the other based on hand-coded state machine) that not only could do wire-speed XML parsing but also could handle never-ending XML streams (used in financial world).
Use of this pattern influences the API contract of the component using the pattern. In the example of the XML parser above, the progressive parser would likely have appropriate methods to accept chunks of input and be called repeatedly until the last chunk.
Progressive building of data structures
This is a design pattern typically used in software design. Goal is to delay the resource usage to the point of actual requirement.
An example of this is again popular in XML parser world. A delayed DOM parser. Apache Xerces implements this pattern. In the delayed DOM building mode, When the Xerces parser is given an input XML document, it doesn’t materialize all the DOM nodes in the beginning itself. Instead, only the document and probably root node is materialized. As the methods are called on the root node, subsequent nodes are materialized.