We all need a change

I’ve made a career change! I have been a consumer of “enabling technology” my entire career. I am now stepping behind that line as I want to be able to influence and shape the technology that enables designers and developers to deliver the best imaginable experience.

I have joined the product management team for Flash runtimes at Adobe, which allows me maintain my focus on the best imaginable, and uncompromising, experience for the user. Flash has enabled this mission more than any other technology on the web and has allowed me to build some tremendous experiences. When user experience was considered a unique differentiator, the Flash/Flex partnership was there to enable.

The landscape has evolved. Thankfully user experience is no longer a differentiator, it’s an essential. To succeed we must put the user first.

The tech community has responded admirably and the expressiveness associated with Flash is moving in to the open-standards that are being defined by HTML5, which will enable a new wave of uncompromising experiences across the web. Adobe gave meaning to expressiveness and continues to innovate through contributes to HTML5 standards, such as CSS regions and CSS shaders. I am sure there is even more goodness to come as we will undoubtedly see more innovation through ongoing contributions to standards and our active participation in open-source projects such as Webkit.

So what’s next for Flash? As outlined in the recent roadmap for Flash runtimes we will be focusing on gaming and premium video. This week Adobe launched a new site specifically around gaming. There are already some tremendous games that showcase the unique capabilities of Flash, which are built on Stage3D to leverage the hardware acceleration afforded by the GPU. The AIR 3.2 release candidate brings the power of Stage3D to mobile in conjunction with the Flash Player 11.2 release candidate. Already some of the top games on the Apple App Store, such as Machinarium, have been brought to you by Flash and Adobe AIR. The Flash runtimes are alive and kicking on iOS!

I also care a lot about the experience of the designer and developer and making our technology accessible. I want to make the experience of using our technology a good one. I want to make it easy to design-develop-deliver incredible experiences.

Your thoughts are welcome.

AIR + Heroku + Pusher

In this post I want to demonstrate an AIR client, that makes a remote call to a Node.js app running on Heroku, and receives a real-time update from Pusher.

Over the last 6 years I’ve built a number of enterprise RIAs using Flex/AIR and LiveCycle Data Services. I’m not alone in this, there are big investments out there in the Adobe technology stack and some incredible apps. While the HTML5 family offers comparable capabilities it’s not easy to turn your back on an investment. It takes time to pivot.

I’ve been thinking about how we can combine these technology stacks as they aren’t mutually exclusive. One strategy I’ve been looking at is using Node.js on the server-side. If I’m using  Node.js then I am using Heroku.

It gets a little more interesting as we starting looking at realtime data push. I’ve been interested in WebSocket, but support is spotty. Then I found Pusher, which is awesome. It’s simple, and it just works. Pusher provides a JavaScript library, but it has been ported to a bunch of other languages.

On the client-side I used AIR.

Before we jump in to the nuts-and-bolts I’ll make my disclaimer, this isn’t meant to showcase clean code or a clean user experience, it’s a spike to prove it all works.

So pulling it all together. The Node.js app is deployed to Heroku and uses the Pusher add-on to send realtime messages. The AIR client connects to Pusher and makes a JSON-RPC call to the Node.js app. The AIR client receives a response back from Node.js and a message from Pusher.

Deploying the app

  • Clone the server-side code from GitHub
git@github.com:p15martin/BlogPusherServer.git
  • If you don’t already have an account on Heroku then create one and install the command line client (CLI)
  • Move to your command prompt and change directory to where you cloned the server-side code
  • Create a new app on Heroku:
heroku create --stack cedar
  • Take a note of the app that was created (e.g. empty-night-2166) and the remote repository (e.g. git@heroku.com:empty-night-2166.git)
  • Add your Heroku app as a remote repository (remember to change it to your remote repository):
git remote add heroku git@heroku.com:empty-night-2166.git
heroku addons:add pusher:sandbox
  • In your browser, log on to Heroku and select your app (e.g. empty-night-2166)
  • From the add-ons menu select Pusher
  • Select the development app

  • Select API access

  • Take a note of the Pusher.app_id, the Pusher.key and the Pusher.secret
  • Now to change the code, in an editor open PusherServer/web.js
  • At the top of the file update the appId, the key, and the secret with what you got from Heroku, save the file
  • At the command prompt commit your changes:
git commit -a -m "updating pusher details"
  • Push your changes to Heroku:
git push heroku master

  • Now test your app (assuming you have curl installed), remember to change the url to your Heroku app:
curl -H "Content-Type: application/json" -d '{ "jsonrpc": "2.0", "method": "add", "params": [1,2], "id":2 }' http://empty-night-2166.herokuapp.com
  • If it worked then you should receive this response (if not jump down to the troubleshooting section): {“result”:3,”id”:2,”jsonrpc”:”2.0″}
  • Run the PusherClient by either installing the client, or by cloning the project from GitHub and importing it in to FlashBuilder
git@github.com:p15martin/BlogPusherClient.git
  • In the client enter your Pusher key and update the Heroku url to point to your app
  • Click Connect to Pusher and then click Send JSON-RPC message to Node
  • The first time may be a little slow, but you should see the JSON-RPC request and response, and a message from Pusher

The client code

The code is raw, but it should be simple enough to follow. In the client code (PusherClient.mxml) the key functions are connect() and sendMessage().

In the connect() function I am using the Pusher-ActionScript-Library from Shawn Makison. It’s kinda simple. You connect to Pusher:

var pusher : Pusher = new Pusher( pusherKey.text, "http://experiencecraftsmanship.com");

You then subscribe to the channel, which is “test_channel” in my example:

var channel : Channel = pusher.subscribe("test_channel");

Finally, you listen for events on your channel, in my example I am listening for “my_event“:

channel.bind( "my_event", eventCallback );

The AS3 library is semantically similar to the Pusher JavaScript library, so if you want to go further then take a look at the JavaScript quick start guide and the JavaScript client API guide. Generally speaking the Pusher docs are a good source of reference.

The sendMessage() function is a little more involved. We start by constructing our JSON-RPC request. I am using the native JSON support added in FlashPlayer 11. So I create an Object that represents my request and then call JSON.stringify(), which takes the Object and returns it in JSON format.

The final part is to send the request to the server, which is just a case of ensuring our HTTP request is set up correctly.

It’s not rocket science and the code could be easily refactored to separate out the different responsibilities and to create a clean API that abstracts the developer from the detail.

private function sendMessage() : void
{
   var object : Object = new Object();
   object.jsonrpc = "2.0";
   object.method = "add";
   object.params = [1, 2];
   object.id = 2;

   var message : String = JSON.stringify( object );

   jsonRequest.text = jsonRequest.text + message + "\n";

   var httpService:HTTPService = new HTTPService();
   httpService.method = "POST";
   httpService.url = herokuUrl.text;
   httpService.contentType = "application/json";
   httpService.headers = { Accept:"application/json" };
   httpService.resultFormat = HTTPService.RESULT_FORMAT_TEXT;

   var token : AsyncToken = httpService.send(message);
   token.addResponder( new mx.rpc.Responder( handleResult, handleFault ) );
}

The server code

I used a few packages, namely the node-jsonrpc package from Eric Florenzano, and node-pusher from Jaewoong Kim. In addition to these packages being referenced in the code (web.js), they are also specified to Heroku in package.json.

If you look at their respective examples you will see I have simply combined them in to my spike.

In the deployment section I called out the Pusher API details that you must update. I would also draw your attention to the channel and event, which need to match what are in the client code:

var channel = 'test_channel';
var event = 'my_event';

The final mention is to the add() function where I send the message to Pusher:

pusher.trigger(channel, event, message, null, function(err, req, res) {
   console.log("pushed");
});

In terms of gotchas the main thing to watch it the port. Make sure you bind the server to the port that Heroku sets in the environment:

var port = process.env.PORT || 3000;
express.createServer(
   require('connect-jsonrpc')(math, date)
).listen(port);

Although Heroku dynamically assigns the port number, you still connect using port 80 (I got caught out by that one).

Troubleshooting

If you run in to trouble then check the logs. You can configure the logging level from the command line as follows:

heroku config:add LOG_LEVEL=DEBUG

To check the logs use:

heroku logs

Other than getting tripped up by the port, which I mentioned above, I didn’t run in to any specific issues. It just worked.

Additional useful resources