The Response Pattern

I don’t presume to place myself at the status of GoF or Martin Fowler, but I came up with a concept that was then improved upon by my twin brother, Tyler, which I feel could stand to be called a pattern. I may not be the first one to do this, but if I am, then it really shouldn’t be called a pattern since design patterns are observable patterns found in a lot of code that can be documented and generalized. I apologize in advance if it should not hold “pattern” status, but I think it is worth discussing, so please be kind. It’s pretty simple in concept, and has turned out to be quite useful in practice. I call it the Response pattern.

This pattern was developed for ActionScript 3, but might be applied to JavaScript or other languages where functions or methods can be passed by reference.

The Problem

Services (being used in the sense of web services being consumed) or other asynchronous operations must be responded to and handled correctly. Often the data returned will be formatted before it is passed on to the caller for consumption. Sometimes the data has been retrieved previously and cached by the system, requiring a check to the cache before calling the service.

Two existing solutions exist, the Callback and the Subscribe solution. Both of these have their drawbacks.

The Callback is a simple solution in which a method is passed in as a parameter of the service call. This method will then be called and passed in the results of the service call once the asynchronous operation is complete. While this is easy and simple, it only allows one method to respond to the call and additional complexity must be added to handle errors which might occur.

The Subscribe solution allows objects to subscribe to messages (or events) which may be broadcast by an object. This solution is the Flash player and Javascript’s event model with addEventListener etc. Some good things about this solution it it allows many methods to handle the results of a service call. It also allows you to “listen” to errors as well as results. While this solution works great for user interface events which may happen at any time, it has significant drawbacks for asynchronous service calls. The primary drawback is that when a service call is made the method handling the result cannot be sure which call it is handling. For example, you wouldn’t want a QUERY_RESULT event to be dispatched to handle queries because what if several objects in your system called a query? You’d have one method expecting a list of users but it might get a list of addresses first. In order to funnel results you have to become very specific in your events such as USER_QUERY_RESULT, and then you have a host of events you need to support. Though this solution does not promote formatting of data, it doesn’t prohibit it. If you add your listener first, you can modify the result data on the event object before other listeners get to it. This can be tricky however since you can’t always guarantee the order of the listeners.

There needs to be a way to handle the results of a service call that:

  1. allows you to deal with the results of a specific call (not any that match some event name)
  2. handles errors
  3. allows more than one method to respond to an operation
  4. allows methods to format the data in set order
  5. allows synchronous operations with the same method (e.g. a cached item in memory can be returned)

The Solution

Participants

  • Service: An object or objects which facilitate calling remote system asynchronously. This may be a webservice API but may also include loading resources such as images.
  • Handlers: A “handler” is a method or function which handles the results or errors of a call from the service.
  • Formatters: A handler which formats the data or converts it into a different data type for other methods handling the results or errors.
  • Response: An object that stores the handlers and formatters and calls them when the service results (or errors) are returned.

Interaction

When a call is made on a service, the service returns a Response object. The caller of the service may then add handlers to the response object. When the call is completed or receives an error, the response object is told to call the result handlers or the error handlers. Each result handler will have at least one parameter which the data from the result (if any) will be passed into. Each error handler will have at least one parameter which the error will be passed into. If a handler method returns a value, that value will become the new data/error. Thus a handler becomes a formatter taking the data it receives and converting it or changing it to a new type of value.

This solution allows for layers of services which abstract the lower level from the higher. The following is an example of how the response might be used.

Example

A system depends on a RESTful XML web service. A low-level service class has been created which loads HTTP data, we’ll call it WebLoader. This class uses the response pattern and is used to load images, documents, etc. from the web. Another service class called XMLLoader is layered on top of WebLoader, that is, it uses a WebLoader object to handle the low-level loading of an XML document from the web, but then converts that document into an XML object the system can use. Finally, a system specific service is layered on top of these other two utility services, called MyLoader. MyLoader takes XML objects and converts them into domain-specific objects, such as User, Product, or Contact.

The system needs to load all the contacts for the logged-in user and display them on-screen. It calls MyLoader.loadContacts(), which in turn, calls XMLLoader.load(“http://example.com/contacts.xml”) which in turn calls WebLoader.load(“http://example.com/contacts.xml”). The WebLoader.load call creates a new response object and stores it for when the result is loaded or an error occurs. Once created it returns the response object from the load method. The XMLLoader.load method receives the response object, adds a handler to it called stringToXML which takes a string, parses it, and returns and XML object, and then returns that response object from its load method. The MyLoader class receives the response object, adds its own handler, xmlToContacts, to format the XML into a list of Contact objects and returns the response. The system receives the response object and adds its own handler, displayContacts, to display the list of contacts on the screen.

When the load is completed, WebLoader calls complete(data) on the stored response object. The response object then loops through the handlers added to it, calling stringToXML first, receiving a value back from it, passing that value into xmlToContacts, receiving a value back from that, and passing a list of contacts into the displayContacts handler which doesn’t return anything, but displays the contacts.

Let’s add a cache to our MyLoader class. When the contact list is loaded, it stores the array of contacts in memory. Next time loadContacts is called, the MyLoader class creates a response object, calls complete(cachedContacts) on it, and returns it. Then, as soon as the caller adds displayContacts handler to the response, the response calls displayContacts and passes in the array of contacts which was cached. Thus, the caller doesn’t need to know whether the call has been cached or not, whether it is asynchronous or not.

While this may sound like a lot is going on, it is actually quite simple and allows service classes to be created and added to libraries for use in other systems. In the XMLLoader example, you don’t have to know or worry about how it gets the XML, the calling class can just know that it will receive XML in the response. The same goes for the MyLoader class. These services can be layered on top of each other like TCP and HTTP do, abstracting the higher levels from the lower levels.

Conclusion

The Response Pattern is something I made up. I created a Response class and as I’ve been using it more and more, it has turned out to be extremely useful and fun to use. I have found it much more preferable to using event listeners, Responder objects, and callbacks in Flash. I have wrapped the SQL classes in Adobe AIR with a service class that uses Reponse to make asynchronous database operations palatable. I have wrapped the File class for AIR. I have created a teeny tiny version of RemoteObject called RemoteService that uses Response. And I have created an ImageLibrary class which stores loaded images for me and resizes them to the size I need. Because it stores the images, sometimes calls are asynchronous and sometimes synchronous, but it is handled the same either way.

I plan to put together a library of often used services that are built around this concept for everyone to use. But until then, you can find a version of the Response class in the flight.net package of the Flight framework.

Update: I posted about the ActionScript implementation of the Response pattern. You can see how it is used and why it is different. It looks similar to other type of implementations, but if you ever use it you’ll see how different it is. It’s the littlest things in life that make the biggest differences.

4 Responses to “The Response Pattern”

  1. Not that Tyler Says:

    I’ve been following both your blogs for a while, and hadn’t thought that you two where related, let alone twins. :)

    This sounds like the flex mx.rpc.IRsponder and mx.rpc.AsyncToken from the flex framework.

    It is an variation of the callback method, using classes instead of functions. The AsyncToken can hold multiple IResponders, and calls them at the completion of the Async event.

    As I understand it, this is the recommended pratice for working with remote data in Cairngorm as well.

  2. Jacob Wright Says:

    Yes, it is similar to IResponder and AsyncToken but like callback it takes methods/functions (less coding). It also allows for sync/async operations. I will post some code soon that shows my implementation of Response in action.

  3. Si Robertson Says:

    Very good article. However, the use of Responder classes is not a new concept and you have more or less described the functionality of the mx.rpc.Responder class as Tyler^ mentioned. I have been using Responder classes myself for a couple of years now.

    //

    responder = new Responder( onResult, onError );
    service.doSomething( responder );

    function onResult( data )
    {}

    function onError( data )
    {}

    //

    Passing a responder to, or receiving a responder from, a service (or anything else) doesn’t make any difference to the functionality or end result.

  4. Jacob Wright Says:

    The way I’ve described it is different than the IResponder method. It allows you to chain and reformat data. If it was exactly the same I wouldn’t have posted about it at all.