The New Client Side
What happens when you separate your client from your business logic?
I was thinking about Martin Fowler’s recent post about the Database Thaw, and was reminded of an article published by by Dave Thomas. He pointed out that we could build our clients independently from our web frameworks if we use RESTful back ends. Such an approach gives us a number of advantages in scalability, integration, and code separation.
Quite simply, when we work in terms of resources manipulated via HTTP, we introduce a new place where we can cache data easily. HTTP GETs are (or should be) side effect free, and can be cached, or run through a web proxy. Frameworks are also including increasing support for caching at the HTTP level, Rails for instance is introducing more support for ETags in its next release.
RESTFul back ends also create an excellent integration point for your applications. As Martin Fowler pointed out, they are quickly becoming a viable alternative to Integration Databases. They also make exposing functionality much simpler, and easier to pick up, for example the Twitter REST API follows similar conventions as Harvest’s REST API, and as a result, both are fairly easy to understand.
These are great reasons to look into a RESTful back end, and have been covered a lot. What I think has been largely ignored is the possibility of increasing code separation between the layers of your application. Right now, a common stack looks something like this:
| Database | Business Logic | Front End | |
|---|---|---|---|
| Product | MySQL, Postgres, SQL Server, etc. | Rails, Django, CakePHP, ASP.NET MVC, etc | HTML |
| Language | SQL | Ruby, Python, C#, etc. | Framework’s Custom View Language + HTML + Javascript |
Ignoring the fact that I probably left out your favorite language or framework, there’s something weird about this picture. While we typically have a clean distinction between our database layer and our business logic, the front end typically gets injected with a lot of support code from our framework. There is usually a template language, and often helpers which generate support JavaScript.
Over the next few posts I am going to explore building completely separated interfaces which are backed by a simple RESTful server. My premise is that we should be able to build simpler, cleaner interfaces, that play nicely with the web. I’m planning on creating a backend that is as bare bones as possible, and interfaces with examples using ExtJS, jQuery, SproutCore, and possibly Cappuccino. If everything goes well, we might just be able to add a Flex and Java client as well, who knows. Let me know if you’d like to see any other frameworks used, or if you would like to contribute one once things get going.
7 comments December 1, 2008
RubyDiff 0.2, now with Subversion support
I saw a post over on Polishing Ruby about using the proper version requirements, and figured that it was about time for me to push out a new version of RubyDiff. The major new feature is support for Subversion:
ruby_diff --svn http://project.svnserver.org/lib --svn BASE:lib
There are also some bugfixes dealing with classes referenced like: Module::SubModule::Class.
Add comment October 2, 2008
Playing with Ubiquity
Mozilla’s Ubiquity seems like a fairly neat idea. It has its rough edges and glitches, but the idea seems promising. I decided to give it a shot, and make a command to lookup bus routes here in Seattle.
CmdUtils.CreateCommand({
name: "bus-schedule",
takes: {"route": noun_arb_text},
icon: "http://transit.metrokc.gov/favicon.ico",
homepage: "http://endofline.wordpress.com",
author: {name: "Adam Sanderson", email: "netghost@gmail.com"},
license: "MPL",
description: "Look up King County Metro bus route",
help: "Select a bus route",
_url: function(directObject){
var url = "http://transit.metrokc.gov/cftemplates/show_schedule.cfm?BUS_ROUTE={QUERY}"
var urlString = url.replace("{QUERY}", directObject.text);
return urlString;
},
execute: function(directObject){
var urlString = this._url(directObject);
Utils.openUrlInBrowser(urlString);
},
preview: function(pblock, directObject){
searchText = jQuery.trim(directObject.text);
if(searchText.length <= 0) {
pblock.innerHTML = "Look up King County Metro bus route";
} else {
jQuery.get( this._url(directObject), function(res) {
var previewTemplate = "Look up route ${query} (${ok})";
var ok = !res.match("No Schedule") ? "<em>Found</em>" : "<em> Not Found</em>";
var previewData = {query: searchText, ok: ok};
pblock.innerHTML = CmdUtils.renderTemplate(previewTemplate, previewData);
});
}
}
});
One thing I really like about Ubiquity is that you can get a fairly rich preview. This command for instance lets you know if the bus route you’re looking for is listed, not rocket science, but handy all the same. For a nicely formatted version of this command, or to install it, check out the gist.
One thing left me a little puzzled about Ubiquity, why another text interface? We already have the url bar, couldn’t Ubiquity launch from there?
Add comment September 7, 2008
Introducing RubyDiff
You’re probably working too hard. Do any of these sound familiar?
- An entire file shows up in your diff, you think it’s because someone changed the tabbing from 4 spaces to 2 spaces, but you aren’t sure so now you’re pouring over all the code.
- Your co-worker decided to rearrange all of the methods in awesome.rb, but you didn’t notice they also changed the parameter order on one of the methods.
- There are a pile of small changes in large methods, and your diff didn’t show you what the method names were.
- You have no idea what you have been working on for the last 2 hours, and can’t remember what to put in your check in message.
If they don’t, then humor me and pretend that they do, because I’m trying to motivate this tool I just wrote and I want you to be interested. What you secretly have been wanting is not a textual diff, but a logical diff, and that’s exactly what RubyDiff does (neat!). So grab it now:
sudo gem install ruby_diff
RubyDiff scans over your code and builds a logical model which it can use to tell you the really important high level information you need. Lets take a look at two versions of my enterprise pancake code:
Sample Version 1
module Food
class Pancake
def is_yummy?
true
end
def << ingredient
puts "adding #{ingredient}"
end
def self.build(ingredients)
p = Pancake.new
ingredients.each{|i| p << i}
p
end
end
end
Sample Version 2
module Food
class Pancake
def << ingredient
(@ingredients ||= []) << ingredient
end
def self.about
puts "A delicious morning treat"
end
def is_yummy?
true
end
end
class PancakeFactory
class << self
def build(ingredients)
p = Pancake.new
ingredients.each{|i| p << i}
p
end
end
end
end
Now, the important thing here is not that waffles are better, but that a bunch of things have changed, and the question is… what was it?
ruby_diff test_a.rb test_b.rb c Food c Food::Pancake - Food::Pancake.build c Food::Pancake#<< + Food::Pancake.about + Food::PancakeFactory
RubyDiff shows us that the module Food has changed, within it the Pancake class changed. The class method Pancake.build was removed and a new PancakeFactory class was added. We also see that the append operator was modified and there is a new class method about. Great!
Best of all you can run ruby_diff over an entire repository of code, and it even supports git. For instance to see what changes you have made locally you can do something like:
ruby_diff --git HEAD --file ./ (your amazing changes here)
Or just to be meta, compare two revisions of RubyDiff:
ruby_diff --git HEAD~4 --git HEAD~3 c CodeChange c CodeChange#initialize c CodeChange#to_s c CodeComparison c CodeComparison#changed c CodeObject + CodeObject#child_signatures c StructureProcessor c StructureProcessor#diff
I’ll post more about RubyDiff shortly, but the source is available now on rubyforge and you can branch it on github. It’s still in it’s early stages, so I’d love to hear what you think.
2 comments June 4, 2008
Flourish – An action packed tree growing game in Ruby
Ok, I’ve taken the plunge, and opened myself up to the many eyes of the internet. The source for my wildly exciting tree growing game is now available at github. It may not be fun, it may not be polished, but it’s available for you to play with.
There are two main problems:
- Flourish is not fun
- Flourish is not polished
That being said, it’s still pretty cool. Go ahead and grab yourself a copy. You will also need Gosu, an excellent game library.
gem install gosu
Once you have gosu installed, just run it with:
ruby flourish.rb
To play, click and drag in from of the active branches and they will split, try to cover the green squares, while avoiding the red ones.
So, grab the source play around. If you think it could be fun to hack away at, go for it. If you think some day it could be a fun game, leave me suggestion or two.
Add comment May 5, 2008
Customizing the Ruby TestRunner
We all know we should write tests. That’s nothing new.
After those great tests get written, they have to be run. Lets figure out how this works so we can make running those tests as awesome as possible. We’re going to write a custom test runner to scratch an itch.
(more…)
Add comment February 11, 2008
