Live Command-Line






Live Command-Line

Assistive, CLI, Command-Line, Grammar, Supportive

Live Command-Line


Goal Story

Frank is using an advanced query tool to run a report on current output. He begins entering an SQL-like query: "list all." At this point, a suggestion list appears with all the things that can be listed, and he chooses "products." Continuing on, the query now reads "list all products where" and a new list appears: "creationTime," "quality," and so on. He chooses "creationTime," and. then enters the rest manually, preferring to ignore further suggestions. The query ends up as "list all products where creationTime is today and quality is faulty." There's a tick mark next to the query to indicate that it's valid.

Problem

How can a command-line interface be supported?

Forces

  • Users can only say so much with point-and-click interfaces. The command line is more expressive and remains the tool of choice for expert users.

  • URLs and search fields are becoming general-purpose command-lines (http://www.codinghorror.com/blog/archives/000296.html).

Solution

In command-line interfaces, monitor the command being composed and dynamically modify the interface to support the interaction. The interface changes according to data, business logic, and application logic. When the command line is to be executed on the server, as is often the case, the browser usually delegates to the server the task of evaluating the partial command.

The command line is the quintessential expert interface and it's worth bearing in mind that most users are "perpetual intermediates" (http://www.codinghorror.com/blog/archives/000098.html). That is, they learn enough to get by and generally learn new things only as and when required. So, while a powerful command line may be a superior choice in the long run, most users simply don't have the time to spend learning it in advance.

Traditional command lines present a problem because they offer the user a blank slate. Everything the user types must be based on prior, upfront, learning, and the only feedback occurs after the command line has been executed. That's not only inefficient for learning, but downright dangerous for sufficiently powerful commands. The model is: human enters command, computer executes command.

The solution is to be more interactive: with a smarter, more proactive command line, the construction of a commandits quick evolution from nothingness to an executable stringbecomes something of a human/computer collaboration. For example, you can:

  • Indicate whether the command is valid before submitting it. If it's not valid, prevent it from executing and inform the user what's wrong and how it can be rectified.

  • Offer to fix invalid commands.

  • Offer Suggestions to help complete part of the command.

  • Help the user predict what will happen when the command is executed. For a query, this means hinting at the resulte.g., estimating number of matches (see Guesstimate [Chapter 13]).

  • Provide graphical widgets to help the user construct the command. For example, build up a mathematical expression using a calculator-like interface to introduce numbers and functions. The query is still represented as plain-text, but the text doesn't need to be entered by hand.

  • Provide graphical widgets to help the user refactor the command. For example, you could provide a "delete this" button next to each condition in a query.

  • Provide visualization tools to render the query in other formats. For example, certain numerical queries might be visualized graphically.

The benefits apply to novices and experts alike. In supporting novices, the technique has sometimes been referred to as a "training wheels" approach. Like training wheels on a bike, you get a feel for the more powerful interface while still being productive.

Often, the command goes to the server, so it usually makes sense for the server to advise the use regarding partial commands. Basically, the procedure goes like this:

  1. Submission Throttling (Chapter 10) periodically uploads the partial command string as an XMLHttpRequest Call.

  2. The server then processes the command and returns supporting information.

  3. The browser updates the user interface accordingly.

As an Ajax feature, this pattern is largely speculative: I'm not aware of any production-level Ajax Apps, but the command-line interface is growing at the same time as Ajax; it's inevitable that these things will collide, and as the discussion here suggests, there are plenty of synergies. One source of inspiration here is the evolution of IDEs over the past five years, particularly in the Java space. Environments like Eclipse (http://eclipse.org) and IntelliJ Idea (http://www.jetbrains.com/idea/) internally represent source files as data structures, leading to features such as ongoing error detection, offers to fix errors, suggestions, powerful refactorings, and alternative displays. All of this happens without the user ever having to compile the source code. As another source of inspiration, there was a recent experiment on training wheels for the command line (http://www.cs.utep.edu/nigel/papers/HCII2005.pdf). Students learned about the Unix command line from either a book or a GUI "training wheels" interface, similar to a Live Command-Line. The training wheels interface was found to be more productive and a more pleasant experience, too.

Decisions

Where will the partial command be analyzedbrowser or server?

It's possible to perform some kinds of analysis in the browserfor example, the browser can check the query against a constant regular expression. So should you try to support analysis in the browser or delegate it to the server?

There are several advantages to analyzing the command server side:

  • The analysis can take into account server-side data, external services, and server-side hardware resources.

  • In most cases, the command will ultimately be processed by the server, so this allows related logic to be kept in the same place.

  • Since the command is just a text string, it's in a convenient form for uploading and server-side processing. Also, it's easier to keep earlier results in a Browser-Side Cache because the command constitutes a key for the cache.

The downsides are:

  • There is an extra load on the server.

  • Extra bandwidth is required to download richer responses.

  • There is extra lag time between the user's input typing and the browser's response.

How much information will the server provide?

Producing more information for partial commands will consume more server resources. The information will also take a bit longer to download. You'll need to trade off resources in favor of supportive information. For example:

  • In supporting validation, you can often rule out many errors with a simple regular expression. But more complex errors relating to the existence of business objects, for example, will get past that filter. Should you try to catch those too? Doing so would improve usability at the expense of resources.

  • In hinting at the command's result, there's a spectrum of precision. For a query, you can say "there might be results," "there are results," or "there are 4123 results." In an extreme case, you can offer a Live Search (earlier in this chapter) and actually show the results.

Real-World Examples

I'm not aware of an all-encompassing Live Command-Line demo. However, the examples in Live Search and Suggestion (earlier in this chapter) are special cases of Live Command-Lines. There are also some JavaScript terminal emulators around, though they don't provide Live Command-Linessee Web Shell (http://a-i-studio.com/cmd/) and JS/UNIX Unix Shell (http://www.masswerk.at/jsuix/jsuix_support/). Also, see the Try Ruby! tutorial (http://tryruby.hobix.com/) for an impressive web interface to the interactive Ruby programming environment.

YubNub

YubNub (http://yubnub.org) isn't Ajaxian, but it is noteworthy as the first explicit exploration of the "search as command line" meme. Yubnub lets users submit commands, which are then mapped into external queries. For example, if you type in "sum 10 20" (http://yubnub.org/parser/parse?command=sum+10+20), you get the sum of 10 and 20; if you type in "ajax form" (http://yubnub.org/parser/parse?command=ajax+form, you get search results from ajaxpatterns.org for "form."

Code Example: AjaxPatterns Assistive Search Demo

The Assistive Search Demo (http://ajaxify.com/run/assistiveSearch) was inspired by services such as Google Search, which are trending toward a general-purpose command line. It aims to illustrate the "training wheels" style of command-line support.

The Assitive Search Demo has a typical search engine forma free-range text input with a Submit buttonin addition to several images, one for each category that can be searched. Thus, the user is alerted to the capabilities of the search. As the user types, the categories highlight and unhighlight to help predict what kind of results will be returned (Figure). All of this information comes from the server side; the browser application doesn't know anything about the categories. It calls the server and startup to discover the categories and corresponding images. A timer monitors the command line, continually asking the server which categories it matches. The browser then highlights those categories.

Assistive Search Demo


The startup sequence loads the categories and kicks off the command-line monitoring loop. The server is required to have an image for each category. If it says that there's a "phone" category, then there will be a corresponding image at Images/phone.gif. The images are all downloaded and placed alongside each other:

  window.onload = function( ) {
    initializeCategories( );
    requestValidCategoriesLoop( );
    ...
    }
  }
  function initializeCategories( ) {
    ajaxCaller.getPlainText("categories.php?queryType=getAllCategoriesCSV",
                            onAllCategoriesResponse);
  }
  function onAllCategoriesResponse(text, callingContext) {
      allCategoryNames = text.split(",");
      var categoriesFragment = document.createDocumentFragment( );
      for (i=0; i<allCategoryNames.length; i++) {
        var categoryName = allCategoryNames[i];
        var categoryImage = document.createElement("img");
        categoryImage.id = categoryName;
        categoryImage.src = "Images/"+categoryName+".gif";
        categoriesFragment.appendChild(categoryImage);
      }
      document.getElementById("categories").appendChild(categoriesFragment);
  }

The key to the Live Command-Line is the monitoring loop. Whenever a change occurs, it asks the server to return a list of all matching categories:

  function requestValidCategoriesLoop( ) {
      if (query( )!=latestServerQuery) {
        var vars = {
          queryType: "getValidCategories",
          queryText: escape(query( ))
        }
        ajaxCaller.get("categories.php", vars, onValidCategoriesResponse,
                        false, null);
        latestServerQuery = query( );
      }
      setTimeout('requestValidCategoriesLoop( );', THROTTLE_PERIOD);
  }

The server uses a bunch of heuristics to calculate the valid categories for this query. For instance, it decides if something belongs to the "people" category by looking up a collection of pronouns in the dictionary. A controller will ultimately return the categories as a comma-separated list generated with the following PHP logic:

  function getValidCategories($queryText) {
    logInfo("Queried for '$queryText'\n");
    $cats = array( );
    eregi(".+", $queryText) && array_push($cats, 'web');
    eregi("^[0-9\+][A-Z0-9 \-]*$", $queryText) &&
array_push($cats, 'phone');
    eregi("^[0-9\.\+\/\* -]+$",$queryText) &&
array_push($cats, 'calculator');
    isInTheNews($queryText) && array_push($cats, 'news');
    isInWordList($queryText, "./pronouns") && array_push($cats, 'people');
    isInWordList($queryText, "./words") && array_push($cats, 'dictionary');
    return $cats;
  }

The browser dynamically updates the category images using a CSS class indicating whether they are valid, which it determines by checking whether they were in the list. There's also an event handler to perform searches on specific categories, as long as those categories are valid:

  function onValidCategoriesResponse(text) {
      var validCategoryNames = text.split(",");
      // Create a data structure to make it faster to determine if a named
      // category is valid. For each valid category, we add an associative array
      // key into the array, with the key being the category name itself.
      validCategoryHash = new Array( );
      for (i=0; i<validCategoryNames.length; i++) {
          validCategoryHash[validCategoryNames[i]] = "exists";
      }
      // For all categories, show the category if it's in the valid category map
      for (i=0; i<allCategoryNames.length; i++) {
          var categoryName = allCategoryNames[i];
          var categoryImage = $(categoryName);
          if (validCategoryHash[categoryName]) {
            categoryImage.onclick = onCategoryClicked;
            categoryImage.className="valid";
            categoryImage.title =
              "Category '" + categoryName + "'" +" probably has results";
          } else {
            categoryImage.onclick = null;
            categoryImage.className="invalid";
            categoryImage.title =
              "Category '" + categoryName + "'" + " has no results";
          }
      }
  }

Alternatives

Point-and-click

The command line involves typing, while point-and-click is a simpler interface style that shows available options and lets the user click on one of them.

Drag-And-Drop

Another means of issuing commands is with Drag-And-Drop (Chapter 15)dragging an item into a trash can to delete it.

Related Patterns

Submission Throttling

Instead of processing the command upon each keystroke, use Submission Throttling (Chapter 10) to analyze it at frequent intervals.

Status Area

Feedback such as input validation and result prediction is usually shown in a Status Area (Chapter 15).

Highlight

Some parts of the command can be highlighted to point out errors, incomplete text, and so on. Also, aspects of the Status Area can be highlighted to help with prediction.

Progress Indicator

If it takes more than one second to process the command line, consider showing a Progress Indicator (see earlier).

Browser-Side Cache

Introduce a Browser-Side Cache (Chapter 13) to retain the server's analysis of partial commands.

Fat Client

Consider creating a Fat Client (Chapter 13) that tries to handle as much of the analysis as possible, thus reducing server calls.

Live Search

Live Search (see earlier) is an extreme version of Live Command-Line applied to search, where the command is effectively executed while the user types.

Suggestion

Providing Suggestions (see earlier) is one characteristic of Live Command-Lines.

Want To Know More?



 Python   SQL   Java   php   Perl 
 game development   web development   internet   *nix   graphics   hardware 
 telecommunications   C++ 
 Flash   Active Directory   Windows