March 10th, 2008 · Posted by Nolan Wright ·

RIA + SOA: The Next Episode

The world of web development is moving away from MVC-based web architectures and towards a client/server model that is probably best described as RIA + SOA, where RIA represents the rich user interface and SOA represents the services that it consumes. There has been a lot of buzz around rich Web 2.0 applications, but they will not become mainstream until the next generation of web platforms emerge - fully integrated platforms that enable RIA + SOA.

State of the Union

Currently, in the standards-based world of HTML, CSS and Javascript, RIA developers have to assemble multiple third-party libraries and frameworks in order to build a rich user interface. This “a la carte” approach to building RIAs places an unnecessary burden on the developer. Instead of focusing on building applications, the developer must spend time finding, integrating, and versioning the various pieces of their RIA development platform. The same holds true on the SOA side; developers are left to figure out how to create services and how to integrate them with their RIA front-ends. Developers need a platform that addresses every aspect of building an application, so that they can focus on doing what they do best – build applications. The question is: what should a next-generation RIA + SOA platform look like? The best place to start is with the activities that are required to build an RIA + SOA-based application. At a high-level these activities include:

1. Design the “look” of the application

This is the general appearance of an application. It includes things like: color, fonts, graphics, and a general page layout.

Common toolsets: HTML, CSS and images

2. Integrate widgets

Widgets encapsulate a set of common capabilities within a single component. They typically contain both “look and feel” as well as a set of pre-defined dynamic behaviors. They are a fundamental building block of an RIA.

Common toolsets: ExtJS, Dojo, Yahoo YUI and several other small widget projects

3. Add dynamic behavior to the user interface

Creating dynamic behavior in the user interface involves two things:

  • Event handling
  • Document Object Model (DOM) Manipulation

Event handling is the ability to know when a particular event occurs (e.g., a user clicks a button or a service response is received). DOM Manipulation allows you to dynamically change the user interface based on the receipt of an event.

Common toolsets: Javascript libraries like JQuery, Prototype, and Scriptaculous

4. Consume services

Consuming backend services is a key capability of an RIA. It enables the creation of single page user interfaces that exchange application data with services. It also enables a clean separation between the user interface and the service tier. The most common method for interacting with services is Ajax.

Common toolsets: Javascript libraries like JQuery and Prototype

5. Create services

Services provide an interface to data and application business logic.

Common toolsets: There are several frameworks available for creating services in your programming language of choice

Now that we have a sense of what is required to build RIA + SOA-based applications, we can take a look at how these activities should be integrated in order to provide the most value to developers. The following sections outline the defining characteristics of a next-generation RIA + SOA platform.

Support for HTML and CSS

These two languages are perfectly suited for implementing the “look” of an application, plus they are familiar to most developers of web-based user interfaces. There is no reason to recreate the wheel.

Provide an Open Widget Framework

As stated earlier, widgets are a fundamental building block of RIAs. There are several widget toolkits available from the likes of Yahoo, Dojo, and ExtJS. There are also several standalone widgets that have been created by smaller projects and individuals. You can build RIAs using these widgets, but there are some catches:

  • It’s unlikely that one widget offering is going to meet all of your needs
  • Integrating different third-party widgets may require custom code as well as an in depth understanding of how each widget works
  • Writing new widgets is challenging because you either have to write to the low-level API of your preferred widget toolkit, or you have to write your own from scratch
  • Some widget frameworks require developers to write a significant amount of Javascript just to use their widgets, which is problematic for those with little to no Javascript experience.

In order to address the problems above, an RIA + SOA platform should provide an Open Widget Framework that has the following capabilities:

  • Support integration of existing third-party widgets
  • Provide a simple API for creating new widgets
  • Enable widgets to be used via simple markup (no Javascript required)
  • Support a distribution model that makes it easy to submit, find and use new widgets.

An Open Widget Framework will provide developers with one source for obtaining widgets and one simple way to integrate these widgets into their application. If a particular widget is not available, it can be easily created using the Open Widget Framework API.

Given the importance of widgets within RIA development and the fragmented nature of widgets today, an Open Widget Framework should be considered an essential part of any RIA + SOA platform.

Provide an Integrated RIA Programming Model

Developing RIAs requires significantly more user interface code than traditional web-based applications. As a result, a next generation platform needs to provide an integrated RIA programming model that facilitates and simplifies the key user interface programming tasks. These tasks include:

  • Event handling
  • DOM manipulation
  • Service consumption (Ajax).

Event handling, DOM manipulation and Ajax enable the “rich” in rich Internet application. It doesn’t take much investigation to see that they are closely related. To illustrate this point, let’s look at the typical steps involved with an RIA login form submission:

  • Login button is clicked (event handling)
  • Service request is sent (Ajax)
  • Some type of activity indicator is displayed (DOM Manipulation)
  • Service returns (Ajax)
  • Activity indicator is hidden (DOM Manipulation)
  • A Login “success” message is displayed (DOM Manipulation).

Despite their close relationship, most frameworks and libraries provide only light integration between the three, leaving the developer to bridge the gap. To illustrate this point, let’s look at some code. In the example below, we will set the contents of one combo box when the value of a second combo box changes. This example is written using JQuery:

1
2
3
4
5
6
7
8
9
10
11
$(function(){
  $("select#comboOne").change(function(){
    $.getJSON("/combo.php",{id: $(this).val(), ajax: 'true'}, function(j){
      var options = '';
      for (var i = 0; i < j.length; i++) {
        options += '<option value="' + j[i].optionValue + '">' + j[i].optionDisplay + '</option>';
      }
      $("select#comboTwo").html(options);
    })
  })
})

Now, let’s look at how this could be accomplished using a fully integrated approach to event handling, DOM manipulation and Ajax.

1
2
3
4
5
6
<select id=”comboOne” 
on=”change then r:load.combo2.request”>
</select>
<select id=”comboTwo” 
on=”r:load.combo2.response then value[property=rows,text=text,value=value]>
</select>

These two examples accomplish the same thing, but in very different ways. The first example requires more code and it’s all in Javascript. The second example uses a simple expression language to do the same thing. Let’s take a closer look at the syntax.

1
on=”change then r:load.combo2.request”

In this expression, the Ajax request message r:load.combo2.request will be sent when the <select> gets a “change” event – pretty simple. Now, let’s look at the second expression:

1
on=”r:load.combo2.response then value[property=rows,text=text,value=value]”

When the Ajax response message r:load.combo2.response is received, the contents of the second combo box are set based on data in the response message.

Let’s take this example one step further by adding a visual queue when the response message is received.

1
2
3
4
<select id=”comboTwo” 
on=”r:load.combo2.response then value[property=rows,text=text,value=value]
and effect[Highlight]>
</select>

By adding and effect[Highlight] to our expression, we are able to incorporate a subtle effect that lets the user know that the combo box values have changed.

These code examples demonstrate the power and simplicity of a fully integrated approach to event handling, DOM manipulation and Ajax. Developers that have little to no Javascript experience will find it easy to learn an expression language like the one above. It will enable them to get productive quickly, since they don’t have to climb a steep learning curve. Of course, there are developers that are comfortable with Javascript and would prefer to use it. As a result, an integrated RIA programming model should also support the use of Javascript, specifically in a way the supports the separation of behavior from markup. This is commonly referred to as unobtrusive Javascript. Let’s look at an example:

1
2
<img id=”progress_image” src=”images/indicator.gif”/>
$(“progress_images”).on(“r:login.request then show”).on(“r:login.response then hide”);

In this example, the <img> markup is separate from the Javascript code that defines its behavior – i.e., “show” when the login request message is received and “hide” when the login response is received. This type of programming model is good for developers that prefer to do their RIA programming in Javascript.

An Integrated RIA Programming model is a fundamental component of an RIA + SOA platform. It provides developers with a single integrated mechanism for handling the major RIA programming activities. The net result is that developers can build rich user interfaces faster and with significantly less code than is required today.

Provide an Integrated Services Platform

RIA only gets us halfway to our goal of building a rich application. We still need to provide an answer for the SOA piece of RIA + SOA. Unfortunately, the current crop of Web 2.0 toolkits and frameworks primarily focus on RIA; they provide little to no support for building services. This is problematic because developers are, once again, left to bridge the gap, which makes application development and maintenance unnecessarily more time consuming and difficult than it should be.

A next generation RIA + SOA platform must address this gap by providing an integrated services platform that provides the following:

  • Support for creating services in any programming language
  • Seamless interoperability between the RIA and SOA tiers
  • Ability to consume local mock services .

Historically, web-based frameworks have been built around a particular programming language, but in the world of RIA + SOA this practice seems outdated and unnecessary. RIAs only need to exchange application data with services, so they should be programming language agnostic. The only required link between an RIA and its SOA-based services should be a lightweight message-based contract. This loose coupling between the RIA and SOA tiers opens the door to a integrated services platform that enables developers to use any programming language for service creation without impacting the RIA tier of the application.

An integrated services platform should also provide seamless interoperability between the RIA and SOA tiers. Specifically, it should handle service routing and data marshalling on behalf of the developer. Here’s an example of a simple integrated approach to building a service. This particular example uses Java.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Service (request = ‘login.request’, response =’login.response)
protected void loginRequest (Message req, Message resp)
						throws Exception
{
	String username = req.getData().getString(“username”);
	String password = req.getData().getString(“password”);
	User user = UserDAO.login(username,password);
	if (user !=null)
	{
	          response.getData().put(“success”,true);
	          response.getData().put(“user”,user);
	          return;
        }
        response.getData().put(“success”,false);
 
}

In the example above, there are two things to notice. First, a plain Java object is turned into a service by simply adding a “Service” annotation to a Java method. This annotation contains both the service request and service response message that this method handles, which makes routing configuration easy. Second, working with service request and response data is simple and straightforward. In the example, the entire User object is placed into the response message. The service platform handles the data marshalling. The result is that developer can focus on writing service logic instead of writing glue code, which ultimately results in faster development with less code.

Finally, if the contract between the RIA and its services is message-based, then it becomes possible to create local mock services. Local mock services respond to remote requests but they exist locally within the RIA. This is a powerful capability because it opens the door to creating fully functional RIA prototypes without writing a single line of service code. These local mock services can be placed in a single file and removed once user interface development is complete. Let’s look at an example.

1
2
3
4
5
6
7
8
9
<!-- Progress indicator -->
<img src=”images/indicator.gif” style=”display:none
on=”r:login.request then show or r:login.response then hide”/>
 
<!-- Login form -->
Username: <input type=text” fieldset=”login” id=”username”/>
Password: <input type=”password” fieldset=”login” id=”password”/>
<input type=”button” value=”Login” 
on=”click then r:login.request”/>
Login Form
1
2
3
<app:script on=”r:login.request then execute after 1s”>
	$MQ(‘r:login.response’,{‘success’:true,’username’:’foo’});
</app:script>
Mock Service

In the example above, we have a login form that generates the service request r:login.request. We also have an image that will show when r:login.request is received and hide when r:login.response is received. The second part of the example is the mock service. The mock service listens for the r:login.request service request and responds with a r:login.response message after one second in order to simulate service latency. The login form has no knowledge of the service location; it simply responds to messages. This simple example demonstrates how an entire RIA prototype can be built without writing any service code. This prototype would be 100% reusable, and it has the added benefit of enabling developers to define the service contracts in advance of service creation. The result is that service creation is greatly simplified because service developers not only have a fully functional prototype as a reference; they have a complete set of service interfaces.

Conclusion

Developers are currently caught in the middle of a fundamental shift in web application development. We are moving away from the server-side MVC frameworks of Web 1.0 and towards a client/server architecture for the web, or more specifically RIA + SOA. As a result of this shift, developers have been left to piece together their web development platform for rich web applications. Of course, change creates opportunity. The opportunity in this case is to build a next generation web platform that provides end-to-end support for building Web 2.0 applications. At Appcelerator, we saw this shift coming well over a year ago. Our response was to build the Appcelerator Platform; a platform built from the ground up to support RIA + SOA. The examples used in this article are based on Appcelerator. Of course, many different approaches will be taken to create the next generation of web platforms, but while the specific implementations may differ the general characteristics should remain the same.

Popularity: 15% [?]

Tags: Opinion

4 Responses to “RIA + SOA: The Next Episode”

  1. Joe Says:

    How does the debugging end of things work out with those tight strings of text? Does it get “compiled” into Javascript that can be pretty cleanly stepped through on the client-side? Genuinely curious.

    I am a pretty big fan of the prototype/dwr combo. That would look like this on the client side (hopefully the code renders alright):

    function changeOne(){
    dwr.updateOne($(”comboOne”).value, {callback: newTwo});
    }

    function newTwo(newOptions){
    util.addOptions($(”comboTwo”), newOptions, “value”, “text”);
    }

    Its a few more characters (I could have packed it all in tight certainly) but super clear at a glance and really clean to debug on both ends.

    The server side then looks like this:

    @RemoteProxy(name = “dwr”)
    public class DwrController{

    @RemoteMethod
    public List updateOne(String value){
    return myManager.getNewOptions(value);
    }
    }

    It is indeed Java-only, but a nice combo if working in that environment. I think Prototype makes Javascript rather fun to work with.

  2. Joe Says:

    Well damn, I pasted in the pre-escaped stuff. On the client-side snippet pretend there is a tag wrapped around the JS functions, and then 2 comboboxes.

  3. Nolan Wright Says:

    HI Joe,

    There are a few options for debugging.

    1) we have a URL parameter: debug=1 that will print out everything that’s going on related to your application and our RIA framework.

    2) You can use Firebug (in Firefox) to see messages going back and forth between the UI and its services (including message contents). It’s also good for general client-side debugging.

    3) You can also add generic logging for your messages in the UI via our script widget. It would look something like this:

    This logs all messages that are sent to and received from remote listeners (services):

    <app:script on=”r:~.* then execute”>
    Logger.info(”Received remote message type: ” + this.type + ‘ data: ‘ + this.data);
    </app:script>

    This logs all messages that are sent to and received from local listeners :

    <app:script on=”l:~.* then execute”>
    Logger.info(”Received local message type: ” + this.type + ‘ data: ‘ + this.data);
    </app:script>

    The DWR/Prototype combo is certainly a viable option. We actually bundle Prototype with Appcelerator, so you can use it. We can also work with JQuery.

    We are trying to offer developers an alternative to the piecemeal approach to building RIA + SOA applications. Ultimately, I believe a fully integrated platform will win out; it’s just a question of which one.

    Thanks for your comment!

  4. Amro Mousa Says:

    One can also step through the code client side (in firebug for example) if one is clever about how they structure their code (that is setup listeners for debugging in standalone javascript files).

    Also, one can debug their Java service code by using the usual tools (that is remote debugging using eclipse and tomcat, for example).

Leave a Reply