The phrase customer-driven has become a mantra for many companies - asserting and embracing the central role played by customers in the daily life of today's corporations.
Notwithstanding the recent growth (and ebb) in IPOs and dot-coms, long-term business success still most often relies on the old basics, namely:
These two basics apply equally to software products, to tools and to services. In order to understand what your customers really want, it's often useful to actually solicit their input; accordingly, this article is about the fundamental importance of using your customers' feedback and suggestions to help prioritize your future development plans.
- Understanding what your customers really want and need
- Delivering a solution to them at a reasonable price
For many software companies, the simplest approach - that of having an e-mail "feedback" link on the company homepage - may be a perfectly adequate solution. Other companies may go a stage further and provide one or more newsgroups for soliciting and tracking customer suggestions. The third and most sophisticated approach is to use an application specifically designed to collect, track and prioritize customer feedback. Though a few commercial solutions exist, the main objective of this article is to show that, with a little effort, a fairly useful Web-based servlet solution can be implemented. More specifically (and to make this discussion a little more concrete), I'll be describing the "Feature Request Database" servlet used by IBMs VisualAge for Java development team to collect, track and prioritize customer input regarding future enhancements (see
The first screen that the customer will see (see Figure 1) contains the terms and conditions for the site and cannot be bypassed. (Should you decide to implement your own customer feedback servlet, your legal department will need to provide you with a precise wording for these terms and conditions.) The key message contained within these T's and C's is that by clicking on the "I Accept" button your customers are granting you the right to use their suggestions and incorporate them in a future release.
From a servlet point of view this is the start of the user's "session." That is, a unique session ID is generated and used as the index to user-state information that's accessed and updated by the screens that follow. If the user is entering a new feature request (see Figure 2), they are required to enter a one-line description and to select the relevant "component" (so that the correct VisualAge for Java development manager can also be notified).
Based on the one-line description, the servlet lists any similar feature requests. If a match is found, the user is encouraged to select an existing feature and add some additional comments; otherwise he or she can continue by selecting Open a New Feature.
This automatic and implicit search for any matching features helps to focus user input into fewer new feature requests, but with correspondingly more comments per request. This helps to simplify the subsequent analysis and prioritization. A more detailed description of the feature that can include links to other external Web pages or to other features must then be entered (see Figure 3). Finally (and after a confirmation screen) the feature is added to the feature database, and an e-mail is sent to the relevant component development manager.
The screens required to enter a new feature have by design been kept very simple (and hopefully intuitive). As befits this keep-it-simple design approach, browsing the feature database involves selecting one of several standard report options in a list box (see Figure 4). Each report returns a list of matching features, and clicking on the feature number will display the feature's full details.
From this detail screen (see Figure 5) users can either add some additional comments or "vote" for this feature as one of their list of top-10 required features. Each user is allowed a maximum of 10 votes, one per feature.
As with many servlet-based systems, authentication is an important issue. Many of the functions described above (adding features, comments or votes) require that the user be uniquely identified and authenticated. The simplest approach is to place the servlet in a subdirectory that requires a valid userID/password to be entered before it can be accessed. Within the servlet the http ServletRequest.getRemoteUser() method will return the current userID. The downside of this approach is that it's usually all or nothing. Without a valid userID/password the user can't even browse the database. For many applications it's therefore desirable to have a two-tier approach to authentication. That is, a userID/password isn't required for simple browsing, but any function that results in information being either entered or updated would prompt for authentication.
Fortunately this two-tier (candy-store) approach can be achieved with only a small degree of extra effort. The key lies in creating an alternative path to your servlet that doesn't require authentication.
The preferred way for users to initially launch the servlet is as follows:
In this mode the user is able to browse all information freely. It's only when users want to make a change (or view information and preferences that are specific to their userID) that they would be redirected to the original path to the servlet:
and hence be required to log in (i.e., authenticate). Most Web application servers support the aliasing of servlets, including the specification of any required userID/password lookup file. To make this transition (from unidentified user to authenticated user) as seamless as possible, the servlet should carry over as much session state information as possible (i.e., the small degree of extra effort).
Performance and scalability are two other key factors that had to be addressed early in the application design phase. Many of the performance issues are directly related to the need to select and sort from a large list of features as quickly (performance) and efficiently (scalability) as possible. For example:
A number of file and data storage solutions are possible, ranging from the use of a traditional database engine (for example, DB2) to using linked lists, hashtables and arrays. Rather than incur the overhead of administering a full-function database, we decided to store all feature information in a simple hashtable, with additional arrays to cache both frequently used data and feature lists, sorted in various sequences.
- Displaying all features sorted according to their total vote count
- Displaying all features that contain one or more search terms, ranked by their relevance
One such sequence represents the list of all feature numbers (implemented as a static array of integers sorted according to their total votes). At first glance, re-sorting this sequence as votes are added or removed would appear to require a significant amount of CPU time (and hence adversely affect servlet response time). For a list of n items the usual rough estimate of the time taken to sort is of the order n times logn (using the quick sort algorithm).
We found, however, that the sort time can be drastically reduced to only order n by using a simple trick, namely, the use of a bidirectional bubble sort that uses the results of the previous sort as input. Because relatively few features would have different vote counts since the last time a user had requested this sorted list, the bubble sort needs only a couple of passes over the list to resequence it based on the latest vote counts.
Persistent data storage is managed through a set of APIs that wrapper any additions or changes made to the hashtable. Effectively, any updates to the hashtable also result in a corresponding record being appended to the end of a sequential disk logfile (where each record consists of a feature number, field name, field value and some control/delimiter information). During servlet init(), this sequential data logfile is parsed into records and used to rebuild the hashtable (and all secondary caches). Periodically this sequential file is "compacted" - again during the servlet init() phase - so that any "old" records (i.e., records for which a newer version exists in the file) are deleted.
This ostensibly low-tech approach to persistence (versus, say, serializing objects to disk) was chosen in part for its simplicity, reliability and error-recovery characteristics. Even in the unlikely event of some system crash or hardware error corrupting one or more records in the logfile, the overall effect on the integrity of the data loaded into the hashtable would be very localized and minimal. Future plans for this data include a move to an XML-based storage format better suited for reuse by other applications.
This article has given a brief description of some of the design and implementation issues regarding building a simple servlet-based tool to capture and prioritize customer feedback. The feedback tool was developed using the WebSphere Test Environment in VisualAge for Java and was then moved to a production runtime environment provided by the WebSphere application server, Advanced Edition.
Given an opportunity, most customers are more than willing to provide you with their constructive suggestions and feedback regarding ways to improve your software tools and products. My hope is that this article may stimulate you to develop your own servlet-based e-business solution to further leverage your customers' input and incorporate it into your development plans for future releases.
I'd like to close by thanking both the Media Design and VisualAge Developer Domain teams at IBM for their many helpful suggestions and comments.
Dean Williams is a Java development manager at the IBM Toronto Laboratory in Canada and is currently focused on developing high-performance Java technology, including JIT compilers.