Tuesday, April 29, 2008

Ruby in the browser: a crazy idea whose time has come

This point of this blog post is first, to explain why I think the seemingly nutty idea having ruby execute in the web browser is actually a good one, and second, to show how you can actually do it. Today. It might be a little long, but bear with me.

I've been spending a lot of my free time over the past few months with various different approaches for getting ruby to work inside the web browser. The obvious question would be: Why? Let me start by stating this unequivocally: I do not hate Javascript. I've more than once argued that we as programmers have given not javascript nearly the respect that it deserves. In fact, it was only through treating javascript with respect that I arrived at the conclusions that brought me here.

A few months ago I was working on a project where we needed to move some reasonably complex business logic from the server to the client. The requirements were such that we just couldn't call the logic on the server and have the application behave as desired. I decided to try to use it as an excuse to improve my javascript skills. I used the object oriented features of Prototype, and some visual effects and the unit testing framework of Scriptaculous. To the best of my ability, I tried to approach it my javascript the same way I would any of my "main" development languages. I wrote the code using test driven development and attempted to make it as clearly communicative as possible. And you know what? I actually enjoyed it quite a bit. I was pleased with the code and the users seemed to like the result. I came away with a greatly improved opinion of javascript.

But something I observed bothered me: I ended up creating exactly the same classes in javascript as I had in server side language (in this case Java). This really shouldn't be surprising, since I used test driven design on the server side java code and the client side javascript code it only makes sense it would lead to a similar outcome. But duplicate code has always been (for me) the number one code smell that indicates a need to refactor. As far as I can tell, in order to get rid of this kind of duplicate code I need to develop my core business logic in a language which can execute on both the client (web browser) and the server. I mentioned earlier that I don't think javascript is a bad language, it's not very common for server side development right now and not my first choice. Currently my favorite language for server side code is ruby. If only ruby could execute in the browser. Pure fantasy, right? Believe it or not, there are actually at least 3 possible ways to do it.

JRuby

First up in my explorations was JRuby. Quite a while back there was an experiment by Dion Almaer to a JRuby applet to execute ruby code in the web page. While this was a nifty experiment when I tried to push this idea further I hit one brick wall after another. The first is that the current JRuby implementation does a lot of things that require additional privileges which means a signed applet. The second which proved more formidable is that javascript code can't call privileged java code at all. This meant that having javascript interact with my ruby code was out. Not good. Though JRuby is near and dear to my heart, this limitation, along with the potential barrier to entry of requiring the Java plugin seemed to make this not a promising solution for what I'm trying to do.

HotRuby

So I gave up on the idea for awhile, until I recently came across HotRuby. HotRuby is a Ruby VM written in javascript. It's a fascinating idea, and it actually works. Under the covers it's really a javascript interpreter for the YARV instruction set. It requires Ruby 1.9 since it depends on YARV. There is a script which dumps out the YARV instructions for a Ruby file in json format. In the browser you include the HotRuby javscript which creates a HotRuby javascript object which executes the jsonified YARV instructions. I installed 1.9 on my machine and checked out the HotRuby code from SVN. In a few hours of playing around, I was able to get it talking with prototype.js and had a simple example where i assigned a ruby block to an onclick event of a button. Although the project seems fairly experimental at this point, it shows great promise. In fact, I was getting ready to blog about it when I came across:

Rubyjs

Rubyjs is a ruby compiler that outputs javascript. It requires only Ruby 1.8.6 and installs as a gem which made it easy to get up and running with. Be aware, Ruby 1.8.5 will not work with it, which meant I had to upgrade. Rubyjs leverages another gem, ParseTree, which parses ruby code intos-expressions, which are kind of like a syntax tree. Rubyjs then emits javascript based on these. A bit more complex but seems to work well and can support more of Ruby than HotRuby can so far.

So far Rubyjs seems to be the most viable solution to me. And if you've made it this far into the post, you deserve to be rewarded with some code. To get running is easy, just gem install rubyjs. This will give you a rubyjs command which will take your ruby code and output javascript for it. Rubyjs comes with a few examples but none which really did what I was interested in doing. I wanted to show a simple block of ruby code listening to a button's onclick event. It took a bit of delving into the rubyjs code to figure out how to do it but I think the resulting code came out to be fairly understandable. Here it is:


class DOM
def self.find(element)
`return document.getElementById(#<element>);`
end
end

class Button
def initialize(js_element)
@js_element = js_element
end

def onclick(&block)
element = @js_element
`
if (#<element>.addEventListener) {
#<element>.addEventListener("click", #<block>, false);
} else {
#<element>.attachEvent("onclick", #<block>);
}
`
end
end

class Main
def self.main
button = Button.new(DOM.find("button"))
button.onclick { puts "clicked!"}
end
end


I create a simple DOM class to help me find an element by id. This shows how you talk to javascript code in rubyjs: by enclosing your javascript code in backticks. Rubyjs does automatically maps javascript objects to ruby and vice versa. I'm not going to delve into the nitty gritty of this too much, I'll do so in a later post.

The more interesting class here is Button. A Button instance gets pass in a DOM element in initialize and instances of button have a single method onclick which receives a block. As you would expect, this allows you to set the onclick handler of a button using a ruby block. The code in the onclick method of Button is also interesting: it shows how you can pass ruby objects into javascript (the javascript code I ripped of from Prototype to do cross browser event observing). Rubyjs will interpolate the javascript code in backticks and replace # type declarations with local variables converting the ruby objects to javascript as appropriate. What this means here is rubyjs is transforming our block into a javascript function for us. Pretty cool, eh?

To see this action, we'll need to compile this ruby code to javascript. The command to do it:


rubyjs button.rb -m Main -d -o button.js


The options tell rubyjs to compile button.rb to button.js. Rubyjs also needs an entry point, which is what -m Main is about. It expects Main to define a class method called Main. Very javaesque, but this is a minor gripe. You can see this code in action here.

There's a lot more to talk about with rubyjs, and I plan this to be the first in a series of posts about it. As part of the project there is also the beginning of a port of GWT to ruby. Altho the code is a bit to javaesque for my tastes so far (as you might expect for a direct port), the idea is very interesting. Let me also issue a giant thank you to Michael Neumann for writing rubyjs and for being incredibly helpful and responsive while I was experimenting. When I asked a question he posted a new version of the gem to address my concern within a few hours. Impressive.

Saturday, April 26, 2008

I'm presenting at RailsConf

Long overdue to blog about this, as I found out a few weeks ago now. Amazing but true: I'm speaking at Railsconf. I got invited to participate in a very non-conventional presentation with Joe O'Brien and Jim Weirich, two guys I respect enormously. We're presenting a dialogue between several developers on modeling. It's actually proving very challenging to write, as coming up with enough things for the characters to say in 50 minutes is a lot of text. But what an opportunity. All in all, the prospect of sharing the stage with Jim and Joe has me feeling a little like this.

Sunday, March 9, 2008

JRuby at TSSJS

Just a quick post to say I'll be presenting on JRuby at TSSJS. The JRuby core team is all at Scotland on Rails I presume, so I'll be doing my level best to represent. Drop me a line if you're going to be there.

Sunday, February 3, 2008

Rails "components": I do not think that word means what you think it means.

Right now I have 2 gigs. One is a java gig where I am working on an application I helped develop about two years ago using Tapestry. The other is a Rails gig. This has given me a good opportunity to compare and contrast the two. So far my experience is that I love the Ruby language and don't want to go back to doing Java except when/if I need to to pay the bills. But Rails I'm not as sold on. Mind you I'm not here to bash on Rails, there are some great things there and other people have done a fine job of praising them. But there are some things I definitely miss from Tapestry, and the most significant one is components.

Now when I say components I don't mean that abomination they stuck in Rails and then deprecated. I mean "real" components in the style of WebObjects, Tapestry, and other frameworks in that lineage. To qualify as "real" components in my mind means 3 things:

1. Reusable view and controller logic.
This is the easiest and this is I think what the deprecated Rails components thing was attempting to address. I've seen several other attempts to do this in Rails with varying degrees of success. I think the Presenter pattern being bandied about is essentially another attempt to have this same aspect of "componenty-ness".

2. Composability.
Components should be able to be composed out of other components. I haven's seen something in Rails that did this well yet. It could be out there, but if it is I haven't seen it. And this is also where it gets a little controversial. From what I've seen, DHH and rails core seems to believe that "high level" component reuse is either not possible or worthwhile. Having seen it absolutely work and work well in Tapestry I have to respectfully disagree. The Tapestry Palette and Table components are both "high-level" and reusable on multiple projects to great affect. However even the discussion around component reuse seemed to me to be framed incorrectly, as it seemed focused on components being reused between applications. This is certainly possible, but I find much greater levels of component reuse within an application.

3. Binding.
This to me seems to be the most neglected feature of components, but in my mind is perhaps the most important. This is simply the ability to say something like "the value property of this text field is bound to @person.name". This should result in me being able to access @person with the name already set. I shouldn't have to touch the params hash at all. This would get rid of what I see as an imporant non-dry part of Rails. For example, why should I have to say in my view:

text_field "person", "name"

And then in my controller:

@person = Person.new(params[:person])

With binding I wouldn't have to.

The other place binding comes into play in component frameworks is events. Not only properties support binding, but events do as well. For example, a Button component could have a block bound to the "onlick" property. The framework then manages and abstracts away all the details of HTTP, etc.

I guess that's really what I miss: with a good component framework (and not all of them are) I feel like I am working at a higher level of abstraction. When building reasonably sophisticated web applications, I really miss that. With simple web sites, I don't so much.

So where am I going with all this? Well, I've been thinking about these ideas a lot since I started doing Rails and talking about them with my pairmate. Recently the ruby-component-web-frameworks Google group has been getting active again so I thought I'd blog about my ideas. I've started doing a little code experiment to see how it might look to implement some of these ideas as a Rails plugin. It seems not too difficult so far; it never ceases to amaze me how much I can say in so little Ruby code. When we have an SVN repo setup I'll share what I have but it's just an architecture spike right now.

Saturday, November 24, 2007

Making our RESTful grid editable

In my last post, I showed you how to hook up the new dojo grid component to a RESTful resource in Rails. Now we're ready to make it editable. I promise this will be a shorter post than last time. The key piece is making a new model object to handle our edits. The dojo grid already provides the key pieces to make editing happen; we just need to provide a way to pass the edited values into our Jester-made object to send them along to our application. The way we do this is by creating our own model class which extends dojox.grid.data.Objects. Then we create an instance of this class. This is what the code looks like:

dojo.declare("MyModel", dojox.grid.data.Objects, {
beginModifyRow : function() {},
endModifyRow : function() {} ,
setDatum: function(inDatum, inRowIndex, inColIndex)
{
this.data[inRowIndex][this.fields.get(inColIndex).key] = inDatum;
this.data[inRowIndex].save();
this.datumChange(inDatum, inRowIndex, inColIndex);
}
});

var model = new MyModel([{key: "make"}, {key: "year"}], cars);



I'm definitely doing some hackery to make it simpler for myself here. The beginModifyRow and endModifyRow are dojo methods that get called at the beginning and end of editing a cell. In the normal dojo implementation these methods make a copy of the object being edited so it can be restored if a user cancels the edit. In a final version of this code we would want to clone our Car object when we start an edit, but we're just not worrying about it yet.

The code which actually handles the edit is in the setDatum method. It get's called with 3 arguments, the new value to set, the row index, and the column index. We have an array of cars to which makes it easy to lookup the right row, but how do we know which field is in which column? Well, dojo holds that information for us in the fields property of our model. The fields property provides a method to get a field object by index, and this field object has a key property which is the name of the property of car that lives in this column. This allows us to set the right property of car. Saving our changes back is a snap thanks to Jester. We call save on our car object and we are done.

Finally, we need to make some changes to our structure object to tell it which cells we want to be editable. We'll use dojo's simplest built in editor and make both cells editable. Here's how we do it:

var structure = [ {
rows: [[
{name: 'Make', editor: dojox.grid.editors.Input},
{name: 'Year', editor: dojox.grid.editors.Input}
]]
} ];
So this is it. We now have an editable dojo grid saving changes by making REST calls into our Rails app.

Using a JS component framework like Dojo (or ext, mootools, etc, etc) in combination with Jester seems like it opens up a new way to approach web application development. I might expound on this in another post.

Saturday, November 10, 2007

Dojo Grid + Jester + Rails = RESTful grid goodness



I've been experimenting with Javascript component frameworks lately, and that let me to look at Dojo. With their 1.0 release, they have added what looks to be a very powerful Grid component. I thought it would be fun to see how easy it is to get it talking with Rails. It proved to be not much code at all, and I think, kind of nifty. Here's how to do it.

Create a Rails app with a RESTful service


Not gonna go thru how to make a rails app, I'll assume you know that already. I created a little RESTful service with the scaffold generator something like this:

script/generate scaffold_resource Car make:string year:integer


Install Jester

When I found Jester it was one of those Open Source Moments for me. You know, the ones where you think: "Hey, wouldn't it be cool if you could..." and then Google and find out someone has already done it. Jester is basically ActiveResource in Javascript. The result makes so ridiculously easy to talk to RESTful services it's not even funny. I installed by unzipping the script and dropping jester.js in public/javascripts in my Rails app.

Install Dojo 1.0

Go get it, unzip it, drop it into public/javascripts. Nuff said

Write the code

And now for the fun part :) We'll start with a simple grid that pulls in data by making a RESTful call to our Rails app using Jester. Later on we'll enhance it to make it editable. First thing you need to know about Dojo is that it is CSS driven. This is definitely a good thing IMO, but it does mean you have to include the right CSS or it won't work at all, trust me ;) So make you sure you include the Dojo Grid CSS like so:


5 <style type="text/css">
6 @import "/javascripts/dojo-release-1.0.0/dijit/themes/tundra/tundra.css";
7 @import "/javascripts/dojo-release-1.0.0/dojox/grid/_grid/Grid.css";
8 @import "/javascripts/dojo-release-1.0.0/dojox/grid/_grid/tundraGrid.css";
9
10 </style>


Next, we'll need to include Jester and Dojo:


12 <%= javascript_include_tag :defaults %>
13 <%= javascript_include_tag "jester" %>
14 <script type="text/javascript"
15 src="/javascripts/dojo-release-1.0.0/dojo/dojo.js"
16 djConfig="parseOnLoad: true"></script>

Including Jester is just a matter of including using the standard javascript_include_tag helper, but dojo is a little wierd. You'll notice the djConfig attribute for starters. How does this even work? djConfig is not even a valid attribute for a script tag, right? As best I understand it, and someone please jump in if I'm wrong, dojo has a parser of it's own that comes along after your page load sand does things to it. This let's you add dojo components to your page "declaratively", or in html, instead of have to use so much javascript. Kind of interesting.

Now let's look at the script block that sets up the objects our grid will need:


18 <script type="text/javascript">
19 dojo.require("dojo.parser");
20 dojo.require("dojox.grid.Grid");
21 dojo.require("dojox.grid._data.model");
22
23 Resource.model("Car");
24 cars = Car.find("all");
25
26 var model = new dojox.grid.data.Objects([{key: "make"}, {key: "year"}], cars);
27
28 var structure = [ {
29 rows: [[
30 {name: 'Make'},
31 {name: 'Year'}
32 ]]
33 } ];
34
35
36 </script>
The first thing you'll notice is those dojo.require statements. These are how you tell dojo to go get all of the pieces it needs. Dojo is broken down into lots of individual javascript files, and while you could just include them all in script tags, that would be kind of a pain. dojo.require basically says "go get this piece and all of it's dependencies". It makes it easier to use some of dojo and not all of dojo as well.

Next we see Jester in action. Kind of puts dojo to shame from an ease of use standpoint, doesn't it? You tell Jester which model you want, and it makes a javascript class for you. We then call find all and it gives us back an array javascript proxy objects with the fields and methods you would expect. Like I said, ridiculously easy. There are options to have it do find (and save) asynchronously as well, which you would probably want to use for a real application.

Next we setup some objects our dojo grid needs. The first is a model, it tells dojo where to get it's data from. We're able to use of the built in types of models, dojo.grid.data.Objects. This kind of model will display an array of Javascript objects, which, conveniently enough, is exactly what we got back from the call to find. We have to give it a little more information, though, namely what properties to display in which columns of our grid. This is what we're doing in the first argument to the constructor. The second argument is our array of cars we got back from the call to Car.find("all").

Finally, we have an object that tells how we want our grid organized. I have to say this seems a lot more complicated than I'd like. It seems to me sometimes dojo is more focused on making the hard things possible than making the simple things simple. So I'm not even going to try to cover all the details of the structure object here, but briefly dojo grid structures consist of an array of views which have an array of rows which have an array of subrows. Phew. I think it would be possible to come up with a simpler structure object for simpler cases, but that would require more dojo-fu than I have yet.

At last, we're ready to put in the html for our grid. Here it is:


42 <div id="grid" dojoType="dojox.Grid"

43 model="model" structure="structure"
44 autoWidth="true" autoHeight="true">

45 </div>


Not much to it is there. Notice how we can set properties of our grid with html attributes. This is what the dojo parser does for us, as I understand it. Here we're passing in the model and structure we created in our script block.

So this is all that's required to use the dojo grid component and have it pull data from a REST service implemented in Rails. In my next post I'll show you how to have it be editable and save it's data using thru REST as well. It's easier than you might think.