<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

	<title>Benjamin Thomas</title>
	<link href="http://benjaminthomas.org/atom.xml" rel="self"/>
	<link href="http://benjaminthomas.org/"/>
	<updated>2010-01-11T19:37:56+00:00</updated>
	<id>http://benjaminthomas.org/</id>
	<author>
		<name>Benjamin Thomas</name>
		<email>benjamin@benjaminthomas.org</email>
	</author>

	
	<entry>
    <title>On the Interwebs, number 20</title>
		<link href="http://benjaminthomas.org/2010-01-11/on-the-interwebs-20.html"/>
		<updated>2010-01-11T00:00:00+00:00</updated>
    <id>tag:benjaminthomas.org,2009-10-22:/2010-01-11/on-the-interwebs-20</id>
		<content type="html">&lt;p&gt;&lt;a href='http://blog.jozilla.net/2008/06/27/fun-with-python-opencv-and-face-detection/'&gt;Fun with Python, OpenCV and face detection&lt;/a&gt; &amp;#8212; I have been looking for an article on this for a while. This is so amazingly cool!&lt;/p&gt;

&lt;p&gt;&lt;a href='http://weblog.bocoup.com/reading-the-audio-stream-from-firefox-3-7'&gt;Reading the Audio Stream from Firefox 3.7&lt;/a&gt; &amp;#8212; I hope all the browsers get on this. This would be absolutely awesome.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://dailyjs.com/2010/01/07/ecmascript5-date/?utm_source=feedburner&amp;amp;utm_medium=feed&amp;amp;utm_campaign=Feed%3A+dailyjs+%28DailyJS%29'&gt;ECMAScript 5&amp;#8217;s Date Extensions&lt;/a&gt; &amp;#8212; Some long time coming changes to the date object in Javascript (aka ECMAScript). The most welcome of which are the new ways to instantiate a Date object.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://wiki.github.com/ry/node/ecma-5mozilla-features-implemented-in-v8'&gt;ECMA 5/Mozilla Features Implemented in V8&lt;/a&gt; &amp;#8212; Speaking of ECMAScript 5 features, a list of which ones are supported by V8, the javascript engine behind Google Chrome and Node.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://andialbrecht.wordpress.com/2009/05/09/when-merging-fails/'&gt;How Do You Look When Merging Fails ;-)&lt;/a&gt; &amp;#8212; A script that takes a picture with your webcam every time your merge fails. Pretty funny idea. Though, Mercurial only as far as I can tell.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://nichol.as/asynchronous-servers-in-python'&gt;Asynchronous Servers in Python&lt;/a&gt; &amp;#8212; A list of all the async web servers available in Python with example code. It is interesting to see the different approaches to one problem.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://github.com/rails/arel'&gt;arel&lt;/a&gt; &amp;#8212; A way to write SQL in Ruby without having to worry about different SQL engines. I was going to try and write something like this, so it saved me a lot of trouble!&lt;/p&gt;

&lt;p&gt;&lt;a href='http://www.engineyard.com/blog/2010/rails-and-merb-merge-plugin-api-part-3-of-6/'&gt;Rails and Merb Merge: Plugin API (Part 3 of 6)&lt;/a&gt; &amp;#8212; With this merge with Merb, Rails is taking the &amp;#8220;framework wars&amp;#8221; up a notch. The stuff they are doing is really cool. Also checkout &lt;a href='http://yehudakatz.com/2010/01/10/activemodel-make-any-ruby-object-feel-like-activerecord/'&gt;ActiveModel&lt;/a&gt; and &lt;a href='http://yehudakatz.com/2009/12/20/generic-actions-in-rails-3/'&gt;Generic Actions&lt;/a&gt;.&lt;/p&gt;</content>
	</entry>
	
	<entry>
    <title>On the Interwebs, number 19</title>
		<link href="http://benjaminthomas.org/2010-01-06/on-the-interwebs-19.html"/>
		<updated>2010-01-06T00:00:00+00:00</updated>
    <id>tag:benjaminthomas.org,2009-10-22:/2010-01-06/on-the-interwebs-19</id>
		<content type="html">&lt;p&gt;&lt;a href='http://rishida.net/tools/conversion/'&gt;Unicode Code Converter&lt;/a&gt; &amp;#8212; Displays the given text in many different escaped formats like HTML, URLs, Javascript, etc. Sounds odd at first, but just try the example and it will instantly make sense.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://blog.leetsoft.com/2009/12/6/clarity-in-log-files'&gt;Clarity&lt;/a&gt; &amp;#8212; Looks like a great tool for monitoring log files remotely.&lt;/p&gt;

&lt;p&gt;File APIs in Firefox 3.6 &amp;#8212; &lt;a href='http://hacks.mozilla.org/'&gt;hacks.mozilla.org&lt;/a&gt; has a &lt;a href='http://hacks.mozilla.org/2009/12/w3c-fileapi-in-firefox-3-6/'&gt;great&lt;/a&gt; &lt;a href='http://hacks.mozilla.org/2009/12/firefox-36-fileapi-demo-reading-exif-data-from-a-local-jpeg-file/'&gt;series&lt;/a&gt; &lt;a href='http://hacks.mozilla.org/2009/12/multiple-file-input-in-firefox-3-6/'&gt;of&lt;/a&gt; &lt;a href='http://hacks.mozilla.org/2009/12/uploading-files-with-xmlhttprequest/'&gt;articles&lt;/a&gt; on using the new File APIs in the upcoming Firefox 3.6.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://blog.new-bamboo.co.uk/2009/12/7/real-time-online-activity-monitor-example-with-node-js-and-websocket'&gt;Real time online activity monitor example with node.js and WebSocket&lt;/a&gt; &amp;#8212; Websockets look really powerful. And we already know I am obsessed with Node.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://antennasoft.net/robcee/2009/12/15/firebug-and-the-jit/'&gt;Firebug and the JIT&lt;/a&gt; &amp;#8212; Even if you don&amp;#8217;t have Firebug enabled it is probably slowing down your browsing experience.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://dailyjs.com/2009/12/16/node-irc/'&gt;Node.js on IRC&lt;/a&gt;: &amp;#8212; A post with a collection of links on using Node with IRC.&lt;/p&gt;</content>
	</entry>
	
	<entry>
    <title>On the Interwebs, number 18</title>
		<link href="http://benjaminthomas.org/2009-12-19/on-the-interwebs-18.html"/>
		<updated>2009-12-19T00:00:00+00:00</updated>
    <id>tag:benjaminthomas.org,2009-10-22:/2009-12-19/on-the-interwebs-18</id>
		<content type="html">&lt;p&gt;&lt;a href='http://www.theinvisibl.com/news/2009/12/08/a-piece-with-a-lot-of-screenshots-about-the-close-tab-behaviour-in-google-chrome/'&gt;A piece with a lot of screenshots about the close tab behaviour in Google Chrome&lt;/a&gt; &amp;#8212; Excellent write up about some excellent design. There has been &lt;a href='http://code.google.com/p/chromium/issues/detail?id=12035'&gt;a bug filed for Chrome&lt;/a&gt; to change this behavior on Mac OS X so that the close button goes on the left. I think this is lunacy, the Chrome guys did a great job here.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://hacks.mozilla.org/2009/12/css-backgrounds-firefox-36/'&gt;CSS Backgrounds in Firefox 3.6&lt;/a&gt; &amp;#8212; Finally we are getting the ability to manipulate CSS background images. Though we still don&amp;#8217;t have the one feature I want: the ability to specify positions relative to a given point, like &amp;#8220;put this image 6px to the right of center&amp;#8221;.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://www.wait-till-i.com/2009/12/08/using-yql-to-load-and-convert-rss-feeds-really-really-fast/'&gt;Using YQL to load and convert RSS feeds really, really fast&lt;/a&gt; &amp;#8212; I really need to get around to wrapping my head around &lt;a href='http://developer.yahoo.com/yql/'&gt;YQL&lt;/a&gt;. I just wish it was more distributed so you aren&amp;#8217;t relaying entirely on Yahoo.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://debuggable.com/posts/rightjs-1-5-6-8-times-faster-than-jquery:4b1fc009-1940-4d26-bdc6-0af2cbdd56cb'&gt;RightJS 1.5: 6-8 times faster than jQuery&lt;/a&gt; &amp;#8212; Some excellent analysis of performance claims. The moral? Don&amp;#8217;t trust everything you read without looking at the details!&lt;/p&gt;

&lt;p&gt;&lt;a href='http://www.stevesouders.com/blog/2009/11/16/cssembed-automatically-data-uri-ize/'&gt;CSSEmbed&lt;/a&gt; &amp;#8212; Convert images referenced in a CSS file into &lt;a href='http://en.wikipedia.org/wiki/Data_URI_scheme'&gt;data URIs&lt;/a&gt;. Pretty cool!&lt;/p&gt;

&lt;p&gt;&lt;a href='http://ahathereitis.blogspot.com/2009/12/how-it-works.html'&gt;Looking for tennis courts on aerial photos&lt;/a&gt; &amp;#8212; I wish I was better at Computer Vision techniques. But this is a nice explanation!&lt;/p&gt;</content>
	</entry>
	
	<entry>
    <title>On the Interwebs, number 17</title>
		<link href="http://benjaminthomas.org/2009-12-18/on-the-interwebs-17.html"/>
		<updated>2009-12-18T00:00:00+00:00</updated>
    <id>tag:benjaminthomas.org,2009-10-22:/2009-12-18/on-the-interwebs-17</id>
		<content type="html">&lt;p&gt;&lt;a href='http://www.bytestrom.eu/blog/2009/1120a_jpeg_encoder_for_javascript'&gt;A JPEG Encoder for JavaScript&lt;/a&gt; &amp;#8212; Just what it says. Pretty amazing feat actually. Javascript is really coming along these days!&lt;/p&gt;

&lt;p&gt;&lt;a href='http://blog.apparentsoft.com/business/124/is-paypal-good-for-your-microisv-business-a-short-paypal-horror-story/'&gt;A short PayPal horror story&lt;/a&gt; &amp;#8212; I have not had a good experience with using PayPal as a vendor either. From this day forth, when presented with an option on checking out I am not longer going to choose PayPal.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://24ways.org/'&gt;24 Ways&lt;/a&gt; &amp;#8212; 24 Ways is back this year, and has some good stuff. 24 Ways is a CSS advent calendar with 24 articles on CSS, one a day until Christmas.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://www.phpied.com/performance-advent-calendar-2009/'&gt;Performance Advent Calendar 2009&lt;/a&gt; &amp;#8212; Inspired by 24 Ways, but about performance.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://ditz.rubyforge.org/'&gt;Ditz&lt;/a&gt; &amp;#8212; Issue tracker intended to be embeded in your source. I love this idea.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://imageoptim.pornel.net/'&gt;ImageOptim&lt;/a&gt; &amp;#8212; Just what it says: &amp;#8220;ImageOptim optimizes images — so they take up less disk space and load faster.&amp;#8221; Dead simple and works well.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://dailyjs.com/2009/12/15/javascript-charts-roundup/'&gt;JavaScript Charts Roundup&lt;/a&gt; &amp;#8212; Summarizes different javascript libraries for graphing. I&amp;#8217;ll be looking at this for &lt;a href='http://github.com/bentomas/simple-analytics'&gt;a project I started a little while ago&lt;/a&gt;.&lt;/p&gt;</content>
	</entry>
	
	<entry>
    <title>&#8226; Bomber &ndash; a Node web framework &mdash; Actions</title>
		<link href="http://benjaminthomas.org/2009-11-29/bomber-actions.html"/>
		<updated>2009-11-29T00:00:00+00:00</updated>
    <id>tag:benjaminthomas.org,2009-10-22:/2009-11-29/bomber-actions</id>
		<content type="html">&lt;p&gt;This is another post in my series of posts about designing a web framework using &lt;a href='http://nodejs.org'&gt;Node&lt;/a&gt;. Catch the first two &lt;a href='/2009-11-20/designing-a-web-framework.html'&gt;here&lt;/a&gt; and &lt;a href='/2009-11-24/bomber-routing.html'&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id='a_new_website'&gt;A New Website&lt;/h2&gt;

&lt;p&gt;First a quick update: last night I decided Bomber needed its own place on the web, so I threw together a website for it. It is mostly based on the code for this site, so it was pretty quick. Anyway&amp;#8230;&lt;/p&gt;

&lt;p&gt;Announcing &lt;a href='http://bomber.obtdev.com/'&gt;bomber.obtdev.com&lt;/a&gt;! I&amp;#8217;m pretty proud of the icon, so make sure to check it out. Now I have a place to put documentation and more details then are appropriate for blog posts.&lt;/p&gt;

&lt;h2 id='actions'&gt;Actions&lt;/h2&gt;

&lt;p&gt;Today&amp;#8217;s installment is going to be about what I am calling &amp;#8220;actions&amp;#8221;, by which I mean, the code that is run for each request. The last post talked about routing, which was the business of figuring out from the URL which code should be run. So, this is the second half of that equation. For comparison, &lt;a href='http://rubyonrails.org/'&gt;Rails&lt;/a&gt; calls these &amp;#8220;actions&amp;#8221; and &lt;a href='http://www.djangoproject.com/'&gt;Django&lt;/a&gt; calls them &amp;#8220;views&amp;#8221;.&lt;/p&gt;

&lt;p&gt;Conceptually actions are pretty simple. Given a request, it is their role to generate a response. If you requested an HTML list of blog posts, it is the job of the action to generate that HTML document. In an &lt;a href='http://en.wikipedia.org/wiki/Model–view–controller'&gt;MVC&lt;/a&gt; framework, the action plays the role of the glue between all the different parts of application: the database, the templates, the cookie or session variables, etc. Here is an example of an action from Rails, generated by its &lt;code&gt;scaffold&lt;/code&gt; command:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;index&lt;/span&gt;
  &lt;span class='vi'&gt;@photos&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Photo&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;all&lt;/span&gt;

  &lt;span class='n'&gt;respond_to&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='nb'&gt;format&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
    &lt;span class='nb'&gt;format&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;html&lt;/span&gt; &lt;span class='c1'&gt;# index.html.erb&lt;/span&gt;
    &lt;span class='nb'&gt;format&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;xml&lt;/span&gt;  &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='n'&gt;render&lt;/span&gt; &lt;span class='ss'&gt;:xml&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='vi'&gt;@photos&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The code is pretty straightforward (even if you aren&amp;#8217;t familiar with Rails). It loads a list of photos from the database, and then depending on the requested format it either renders the &amp;#8216;index.html.erb&amp;#8217; template, or converts the list to an XML document.&lt;/p&gt;

&lt;p&gt;Actions have a lot of different needs. The two most basic are dealing with the request and the response:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An action needs to have access to the details of the request: What HTTP method was it? What headers were sent? What were the query parameters? What was the body of the request? What POST variables were sent? What cookies were sent? What session is it associated with? What session variables are set? Where is the request from? What browser is the request from? And so on.&lt;/li&gt;

&lt;li&gt;An action needs to be able to modify all the details of the response that it is creating. Primarily, that is setting headers, cookies, or session variables and generating the HTML.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id='giving_users_access_to_the_response_and_the_request_in_existing_frameworks'&gt;Giving users access to the Response and the Request in existing frameworks&lt;/h2&gt;

&lt;p&gt;Django is very explicit, here&amp;#8217;s an example of &lt;a href='http://docs.djangoproject.com/en/dev/topics/http/views/#a-simple-view'&gt;a simple view from the docs&lt;/a&gt;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='kn'&gt;from&lt;/span&gt; &lt;span class='nn'&gt;django.http&lt;/span&gt; &lt;span class='kn'&gt;import&lt;/span&gt; &lt;span class='n'&gt;HttpResponse&lt;/span&gt;
&lt;span class='kn'&gt;import&lt;/span&gt; &lt;span class='nn'&gt;datetime&lt;/span&gt;

&lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;current_datetime&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;request&lt;/span&gt;&lt;span class='p'&gt;):&lt;/span&gt;
    &lt;span class='n'&gt;now&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;datetime&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;datetime&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;now&lt;/span&gt;&lt;span class='p'&gt;()&lt;/span&gt;
    &lt;span class='n'&gt;html&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s'&gt;&amp;quot;&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;It is now &lt;/span&gt;&lt;span class='si'&gt;%s&lt;/span&gt;&lt;span class='s'&gt;.&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;&amp;quot;&lt;/span&gt; &lt;span class='o'&gt;%&lt;/span&gt; &lt;span class='n'&gt;now&lt;/span&gt;
    &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='n'&gt;HttpResponse&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;html&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;You are given a request, and you return a response. This is very intuitive, and powerful but can be a bit of a pain sometimes when you don&amp;#8217;t want to be writing all that boilerplate code over and over again. I wish I just didn&amp;#8217;t have to type quite so much. (This is a complaint I keep coming back to over and over again with Django, and it really isn&amp;#8217;t a strike against Django. Django is this way precisely because they don&amp;#8217;t want to pigeon hole you into writing your projects in a specific way. But sometimes I just wish they &lt;em&gt;would&lt;/em&gt; pick a way for me)&lt;/p&gt;

&lt;p&gt;Rails is a bit more &amp;#8220;magical&amp;#8221; in the sense that a lot of the code happens behind the scenes. With Rails, an &lt;code&gt;ActionController&lt;/code&gt; object is iniated for each request, and then the requested action method is called on that object. And because &lt;code&gt;self&lt;/code&gt; is optional in Rails it seems like things just come out of nowhere. Here&amp;#8217;s an example action:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='k'&gt;def&lt;/span&gt; &lt;span class='nf'&gt;show&lt;/span&gt;
  &lt;span class='vi'&gt;@photo&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='no'&gt;Photo&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;find&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;params&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:id&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;

  &lt;span class='c1'&gt;# just so you can see what it is like to set session and cookie vars&lt;/span&gt;
  &lt;span class='n'&gt;log&lt;/span&gt; &lt;span class='n'&gt;session&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:key&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='c1'&gt;# get the session variable from the response&lt;/span&gt;
  &lt;span class='n'&gt;session&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:key&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;value&amp;quot;&lt;/span&gt; &lt;span class='c1'&gt;# set the session variable for the response&lt;/span&gt;

  &lt;span class='n'&gt;cookies&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='ss'&gt;:key&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;value&amp;quot;&lt;/span&gt;

  &lt;span class='c1'&gt;# and setting headers&lt;/span&gt;
  &lt;span class='n'&gt;response&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;headers&lt;/span&gt;&lt;span class='o'&gt;[&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;Content-Type&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;]&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='s2'&gt;&amp;quot;application/pdf&amp;quot;&lt;/span&gt;

  &lt;span class='n'&gt;respond_to&lt;/span&gt; &lt;span class='k'&gt;do&lt;/span&gt; &lt;span class='o'&gt;|&lt;/span&gt;&lt;span class='nb'&gt;format&lt;/span&gt;&lt;span class='o'&gt;|&lt;/span&gt;
    &lt;span class='nb'&gt;format&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;html&lt;/span&gt; &lt;span class='c1'&gt;# show.html.erb&lt;/span&gt;
    &lt;span class='nb'&gt;format&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;xml&lt;/span&gt;  &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='n'&gt;render&lt;/span&gt; &lt;span class='ss'&gt;:xml&lt;/span&gt; &lt;span class='o'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='vi'&gt;@photo&lt;/span&gt; &lt;span class='p'&gt;}&lt;/span&gt;
  &lt;span class='k'&gt;end&lt;/span&gt;
&lt;span class='k'&gt;end&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;What is going on is &lt;code&gt;params&lt;/code&gt;, &lt;code&gt;session&lt;/code&gt;, &lt;code&gt;cookies&lt;/code&gt;, &lt;code&gt;response&lt;/code&gt; and &lt;code&gt;respond_to&lt;/code&gt; are all actually methods on the &lt;code&gt;ActionController&lt;/code&gt; object. To return a response you call a method like &lt;code&gt;render&lt;/code&gt;, or &lt;code&gt;redirect_to&lt;/code&gt;. I really do feel like writing applications in Rails is like writing in a-whole-nother language. Rails has request and response objects, but you generally don&amp;#8217;t use them in favor of the other simpler methods. With Rails there isn&amp;#8217;t a very clear distinction between requests and responses like there is in Django.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://www.sinatrarb.com/'&gt;Sinatra&lt;/a&gt; works in a very similar way to Rails. And of the Node frameworks, the majority of them are Sinatra like in spirit.&lt;/p&gt;

&lt;h2 id='evented_programming'&gt;Evented programming&lt;/h2&gt;

&lt;p&gt;If we already didn&amp;#8217;t have enough choices for how to design an API for a web framework, Node then adds an additional level of complexity due to its evented nature.&lt;/p&gt;

&lt;p&gt;What does that mean? Well, Node lives by the philosophy that a program should never just sit there and do nothing while it is waiting for input or output to finish. Here&amp;#8217;s an example of what not to do from &lt;a href='http://nodejs.org/jsconf.pdf'&gt;Ryan&amp;#8217;s presentation at JSConf this year&lt;/a&gt;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;result&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;db&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;query&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;SELECT..&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Ryan asks a simple question, &amp;#8220;What is the software doing while it queries the database?&amp;#8221; Well, with most libraries it is doing nothing, it is just sitting there waiting for the database to do its thing. This is inefficient. An evented library uses callbacks, so instead of waiting for the database to return, it does some other computation, and then when the database query is done, it calls the callback function. Here&amp;#8217;s Ryan&amp;#8217;s example:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='nx'&gt;db&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;query&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;SELECT..&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;result&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; 
  &lt;span class='c'&gt;// use result&lt;/span&gt;
&lt;span class='p'&gt;});&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This is pretty straight forward but what if you need to make a second database call depending on the result of the first one, and then use both those results? You&amp;#8217;d get something like this:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='nx'&gt;db&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;query&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;SELECT..&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;result1&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; 
  &lt;span class='nx'&gt;db&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;query&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;SELECT..&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;result2&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='c'&gt;// use both results here&lt;/span&gt;
  &lt;span class='p'&gt;});&lt;/span&gt;
&lt;span class='p'&gt;});&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;And what if you need to load in a template file (which would mean reading the file from disk) and use that template to format your results?&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='nx'&gt;db&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;query&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;SELECT..&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;result1&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; 
  &lt;span class='nx'&gt;db&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;query&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;SELECT..&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt; &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;result2&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='nx'&gt;templates&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;load&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;file-name&amp;quot;&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;template&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
      &lt;span class='c'&gt;// use both results and the template here&lt;/span&gt;
    &lt;span class='p'&gt;});&lt;/span&gt;
  &lt;span class='p'&gt;});&lt;/span&gt;
&lt;span class='p'&gt;});&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;There is an additional problem here. How do you keep track of state between all these different functions? In the previous example it is easy because a function is aware of all the local variables that exist at the time it is created, so the last function has access to &lt;code&gt;result1&lt;/code&gt; and &lt;code&gt;result2&lt;/code&gt; but this isn&amp;#8217;t always the case. Especially if you are trying to reuse functions in different parts of the app.&lt;/p&gt;

&lt;p&gt;This is very quickly getting unwieldy. And thus far none of the Node frameworks have addressed this issue head on. There have been some talks on the mailing list of adding &lt;a href='http://api.dojotoolkit.org/jsdoc/1.3.2/dojo.Deferred'&gt;deferred&lt;/a&gt; objects to Node and I think many people hope that this is going to solve the problem of writing evented web frameworks. While I think deferreds would be awesome, I think the solution needs to be a little more integrated then that.&lt;/p&gt;

&lt;h2 id='bomber_actions'&gt;Bomber Actions&lt;/h2&gt;

&lt;p&gt;(Note, this is the API I plan to implement in Bomber, but not all of it is completely written yet. Some of it though!)&lt;/p&gt;

&lt;p&gt;In Bomber, the solution is &lt;code&gt;Action&lt;/code&gt; objects, which have deferred functionality, but are a little more aware of the problem they are trying to address. Specifically, an &lt;code&gt;Action&lt;/code&gt; has a list of tasks that should be run to complete the action. And just like with deferreds, the result of a previous task is passed to the next task. This way it is easy chain functions to be run after one another. However, (and this is the real bread and butter of &lt;code&gt;Action&lt;/code&gt;s) unlike with deferreds (at least as far as I can tell) if the return result of a previous task is itself a deferred (or a Promise in Node-speak), the &lt;code&gt;Action&lt;/code&gt; will wait for that deferred to finish its task before calling the next task. Now you can chain up all your tasks, and not worry about the asynchronicity of the different parts.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Action&lt;/code&gt; objects have a couple other tricks up their sleeves.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They will make sure that all tasks are bound to the action object itself, so you can keep track of state between tasks by setting variables on &lt;code&gt;this&lt;/code&gt;.&lt;/li&gt;

&lt;li&gt;Every task will be called with the request and the response for that &lt;code&gt;Action&lt;/code&gt; as the first two arguments. This makes it easy to access those objects so you can get/set cookies, sessions or headers.&lt;/li&gt;

&lt;li&gt;If any task returns a certain kind of object (like a &amp;#8216;404 error&amp;#8217; object &amp;#8211; I haven&amp;#8217;t decided what to call it, yet) Node will stop running the tasks for that &lt;code&gt;Action&lt;/code&gt; and send that as the response for this request.&lt;/li&gt;

&lt;li&gt;If the result of the last task is a string or an object, Node assumes you want to use this value for the body of the request. If it is a string it assumes it is HTML and if it is any thing other than either a string or one of the objects in the previous bullet point, it converts it to JSON and sends that. This allows you to easily construct simple responses, but if you want more control you can just return &lt;code&gt;null&lt;/code&gt; and manage it yourself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is how the Server initializes an &lt;code&gt;Action&lt;/code&gt;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;action&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;new&lt;/span&gt; &lt;span class='nx'&gt;Action&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;request&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;response&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;view_function&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='nx'&gt;action&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;start&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Then a possible &lt;code&gt;view_function&lt;/code&gt; could look like this (to tackle the example from the section on evented programming):&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='kd'&gt;function&lt;/span&gt; &lt;span class='nx'&gt;view_function&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;request&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;response&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
  &lt;span class='c'&gt;// in this case the db.query function is assumed to return a deferred object&lt;/span&gt;
  &lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;addTask&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='kd'&gt;function&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;request&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;response&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nx'&gt;db&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;query&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;SELECT...&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;));&lt;/span&gt; 
  &lt;span class='p'&gt;});&lt;/span&gt;

  &lt;span class='c'&gt;// the next task is called with the result from the previous deferred object&lt;/span&gt;
  &lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;addTask&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='kd'&gt;function&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;request&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;response&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;result1&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;result1&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;result1&lt;/span&gt;&lt;span class='o'&gt;;&lt;/span&gt;
    &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nx'&gt;db&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;query&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s2'&gt;&amp;quot;SELECT...&amp;quot;&lt;/span&gt;&lt;span class='p'&gt;));&lt;/span&gt; 
  &lt;span class='p'&gt;});&lt;/span&gt;

  &lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;addTask&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='kd'&gt;function&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;request&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;response&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;result2&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;result2&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;result2&lt;/span&gt;&lt;span class='o'&gt;;&lt;/span&gt;
    &lt;span class='c'&gt;// I&amp;#39;m assuming templates.load is a deferred object as well...&lt;/span&gt;
    &lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='nx'&gt;templates&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;load&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;file-name&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
  &lt;span class='p'&gt;});&lt;/span&gt;

  &lt;span class='k'&gt;this&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;addTask&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='kd'&gt;function&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;request&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;response&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;template&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='c'&gt;// use both results and the template here&lt;/span&gt;
  &lt;span class='p'&gt;});&lt;/span&gt;
&lt;span class='p'&gt;}&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Now, I admit that at this point this looks like it might have been more work. But I guess I am going to have to try it out some to really see. I think this potentially could allow for better use of &lt;abbr title='Don&amp;apos;t Repeat Yourself'&gt;DRY&lt;/abbr&gt; programming because now it is trivial to use predeclared javascript functions as opposed to anonymous ones. That with the additional benefit of being able to return 404 errors or 3xx redirects at any point in that process will make this pretty handy.&lt;/p&gt;

&lt;p&gt;I have one more post planned about this Bomber design stuff but it might be a little while before I get to it. (I need to figure out how I want templating to work before I can write it! But I have some ideas&amp;#8230;)&lt;/p&gt;</content>
	</entry>
	
	<entry>
    <title>On the Interwebs, number 16</title>
		<link href="http://benjaminthomas.org/2009-11-28/on-the-interwebs-16.html"/>
		<updated>2009-11-28T00:00:00+00:00</updated>
    <id>tag:benjaminthomas.org,2009-10-22:/2009-11-28/on-the-interwebs-16</id>
		<content type="html">&lt;p&gt;Some websites I have found interesting recently (in no particular order):&lt;/p&gt;

&lt;p&gt;(Whew! This is a long one! Apparently I waited a little too long to post these!)&lt;/p&gt;

&lt;p&gt;&lt;a href='http://code.quirkey.com/sammy/index.html'&gt;Sammy&lt;/a&gt; &amp;#8212; A &lt;a href='http://www.sinatrarb.com/'&gt;Sinatra&lt;/a&gt; inspired framework for making browser based javascript applications. This is seriously cool. (Don&amp;#8217;t confuse this with server side javascript applications. This is for writing an application that lives entirely in a browser.)&lt;/p&gt;

&lt;p&gt;&lt;a href='http://github.com/mikel/mail'&gt;Mail&lt;/a&gt; &amp;#8212; What appears to be a spectacular Ruby library for checking/sending/generating/parsing emails.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://www.azarask.in/blog/post/identity-in-the-browser-firefox/'&gt;Identity in the Browser&lt;/a&gt; &amp;#8212; A very cool mockup of what it would look like if logging-in and managing accounts on websites was built into the browser. This feels like a hint of the future. And I can&amp;#8217;t wait! Putting the controls in the URL bar makes perfect sense.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://books.couchdb.org/relax/reference/views-for-sql-jockeys'&gt;View Cookbook for SQL Jockeys&lt;/a&gt; &amp;#8212; An explanation of &lt;a href='http://couchdb.apache.org/'&gt;CouchDB&lt;/a&gt; views for SQL people. Honestly, while this was helpful, I need a lot more examples before I am going to truely get this map/reduce stuff for CouchDB.&lt;/p&gt;

&lt;p&gt;&lt;a href='https://developer.mozilla.org/en/Using_files_from_web_applications'&gt;Using files from web applications&lt;/a&gt; &amp;#8212; Mozilla&amp;#8217;s documentation on a new javascript feature that allows you to access files without having to upload them to a server first. Bit by bit browsers are aquiring the tools to completely replace native apps. I can&amp;#8217;t wait!&lt;/p&gt;

&lt;p&gt;&lt;a href='http://blog.getify.com/2009/11/labjs-new-hotness-for-script-loading/'&gt;LABjs: new hotness for script loading&lt;/a&gt; &amp;#8212; A new library for getting your javascript files to download more quickly. I take a different approach (which is to make sure I am only using 1 javascript file) but this looks pretty useful for larger applications that have lots of dependencies.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://www.notonebit.com/s'&gt;An interesting 404 error&lt;/a&gt; &amp;#8212; Seems like it would only be interesting to people who are familiar with HTTP status codes, though.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;And now some &lt;a href='http://nodejs.org/'&gt;Node.js&lt;/a&gt; links (I&amp;#8217;m grouping them here in case you aren&amp;#8217;t interested in my latest obsession):&lt;/p&gt;

&lt;p&gt;&lt;a href='http://jsconf.eu/2009/video_nodejs_by_ryan_dahl.html'&gt;Video: Node.js by Ryan Dahl&lt;/a&gt;: Video of the talk whose &lt;a href='/2009-11-18/on-the-interwebs-15.html#p_nth_2'&gt;slides I linked to last week&lt;/a&gt;. The talk honestly doesn&amp;#8217;t add that much to the slides (he did some good work with those!) but it is really fun to put a face to the person.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://github.com/danwrong/restler'&gt;restler&lt;/a&gt; &amp;#8212; A super simple library for making HTTP requests from Node. I don&amp;#8217;t need this currently, but this looks like everything I would want.&lt;/p&gt;</content>
	</entry>
	
	<entry>
    <title>&#8226; Bomber &ndash; node.js web framework &mdash; URL Routing</title>
		<link href="http://benjaminthomas.org/2009-11-24/bomber-routing.html"/>
		<updated>2009-11-24T00:00:00+00:00</updated>
    <id>tag:benjaminthomas.org,2009-10-22:/2009-11-24/bomber-routing</id>
		<content type="html">&lt;p&gt;This weekend I finally got a chance to play around a little bit with some of the ideas I talked about in my last post on &lt;a href='/2009-11-20/designing-a-web-framework.html'&gt;writing a new web framework with node.js&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id='introducing_bomber'&gt;Introducing Bomber&lt;/h2&gt;

&lt;p&gt;I have decided to call the framework &amp;#8220;Bomber&amp;#8221;, which is a variant spelling of &amp;#8220;Bomer&amp;#8221;, which is a combination of &amp;#8220;Ben&amp;#8221; and &amp;#8220;Omer&amp;#8221;, which is because my friend Omer has been volunteering API/design thoughts and advice.&lt;/p&gt;

&lt;p&gt;You can checkout &lt;a href='http://github.com/obt/bomberjs'&gt;the source code for Bomber&lt;/a&gt; from GitHub if you want to see how it works or try it out. You must have &lt;a href='http://nodejs.org/#build'&gt;node.js&lt;/a&gt; installed&lt;sup id='fnref:1'&gt;&lt;a href='#fn:1' rel='footnote'&gt;1&lt;/a&gt;&lt;/sup&gt; first.&lt;/p&gt;

&lt;p&gt;Bomber is centered around the idea of &amp;#8220;apps&amp;#8221; (much like &lt;a href='http://www.djangoproject.com/'&gt;Django&lt;/a&gt; is), where an app is just a way to group code together in a folder so that it is more portable/reusable. Unlike with Django, Bomber expects certain code to live in certain places. For example, the URL routing has to be in a file called &lt;code&gt;routes.js&lt;/code&gt;. I have written up &lt;a href='http://github.com/obt/bomberjs/blob/c496b9f9de6001bb2ba47ced8edb21d625db7bf2/docs/apps.txt'&gt;a description of what files an app can have&lt;/a&gt; in the docs folder of the source.&lt;/p&gt;

&lt;p&gt;To actually run the Bomber server, &lt;code&gt;cd&lt;/code&gt; into the source code directory and run the command &lt;code&gt;./bomber.js ./exampleProject&lt;/code&gt;. This will start the server, using the &amp;#8216;exampleProject&amp;#8217; app.&lt;/p&gt;

&lt;p&gt;Right now Bomber doesn&amp;#8217;t do much. If you are looking for something more stable may I suggest &lt;a href='http://wiki.github.com/ry/node'&gt;one of the more established projects&lt;/a&gt;?&lt;/p&gt;

&lt;h2 id='bomber_routing'&gt;Bomber Routing&lt;/h2&gt;

&lt;p&gt;I&amp;#8217;ll show you how it works first, and then after, I&amp;#8217;ll talk about why I decided to have it work the way it does.&lt;/p&gt;

&lt;p&gt;The goal of the routing in Bomber is to determine which function should be run given a URL.&lt;/p&gt;

&lt;p&gt;Here is an example of what a &lt;code&gt;routes.js&lt;/code&gt; file could look like:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;Router&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;require&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;bomber/lib/router&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;).&lt;/span&gt;&lt;span class='nx'&gt;Router&lt;/span&gt;&lt;span class='o'&gt;;&lt;/span&gt;

&lt;span class='kd'&gt;var&lt;/span&gt; &lt;span class='nx'&gt;r&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='k'&gt;new&lt;/span&gt; &lt;span class='nx'&gt;Router&lt;/span&gt;&lt;span class='p'&gt;();&lt;/span&gt;

&lt;span class='nx'&gt;r&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;add&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='nx'&gt;view&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;simple&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;action&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;index&amp;#39;&lt;/span&gt; &lt;span class='p'&gt;});&lt;/span&gt;
&lt;span class='nx'&gt;r&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;add&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;/section&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='nx'&gt;view&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;simple&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;action&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;section&amp;#39;&lt;/span&gt; &lt;span class='p'&gt;});&lt;/span&gt;
&lt;span class='nx'&gt;r&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;add&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;/section/:id&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='nx'&gt;view&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;simple&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;action&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;show&amp;#39;&lt;/span&gt; &lt;span class='p'&gt;});&lt;/span&gt;
&lt;span class='nx'&gt;r&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;add&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;/:view/:action&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
&lt;span class='nx'&gt;r&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;add&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;/other_app/:action&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt; &lt;span class='nx'&gt;view&lt;/span&gt;&lt;span class='o'&gt;:&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;view_name&amp;#39;&lt;/span&gt; &lt;span class='p'&gt;});&lt;/span&gt;

&lt;span class='nx'&gt;exports&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;router&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='nx'&gt;r&lt;/span&gt;&lt;span class='o'&gt;;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;All this file needs to do, is create a &lt;code&gt;Router&lt;/code&gt; object, add routes to it, and then finally export that router object.&lt;/p&gt;

&lt;p&gt;If you have used &lt;a href='http://rubyonrails.org/'&gt;Rails&lt;/a&gt; this should look very familiar.&lt;/p&gt;

&lt;p&gt;How adding the routes works is you give the router the URL to match, and then an object with the set of parameters that should be used to decide which function to run.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;app&lt;/code&gt; parameter tell Bomber which app to use, &lt;code&gt;view&lt;/code&gt; tells it what view file to look in, and &lt;code&gt;action&lt;/code&gt; tells it the name of the function to run. Any other parameters (or those declared in the URL, like &lt;code&gt;:id&lt;/code&gt;) will find their way to the function (I&amp;#8217;m not sure how yet, wait for another post!). If you don&amp;#8217;t specify &lt;code&gt;app&lt;/code&gt;, Bomber will use the current app.&lt;/p&gt;

&lt;p&gt;Additionally, if you want complete control over the process, you can give it a regular expression instead of a string for the URL to match. Behind the scenes all routes are converted to regular expressions, anyway.&lt;/p&gt;

&lt;h2 id='the_thought_process'&gt;The Thought Process&lt;/h2&gt;

&lt;p&gt;There were 3 ways I considered using when designing this: the Sinatra way, the Django way, and the Rails Way.&lt;/p&gt;

&lt;p&gt;The Sinatra way is very popular with node.js frameworks (I have yet to find one that doesn&amp;#8217;t do it this way). The Sinatra way is to have the routing in the same file and even inline with the code that is to be run. It looks something like this (to take an example from &lt;a href='http://github.com/visionmedia/express'&gt;Express&lt;/a&gt;):&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='nx'&gt;get&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;user/:name/:operation&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt;&lt;span class='p'&gt;(){&lt;/span&gt;
  &lt;span class='nx'&gt;param&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;operation&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;ing &amp;#39;&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='nx'&gt;param&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='p'&gt;})&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Or like this (to take an example from &lt;a href='http://github.com/simonw/djangode'&gt;Djangode&lt;/a&gt;):&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='nx'&gt;dj&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;makeApp&lt;/span&gt;&lt;span class='p'&gt;([&lt;/span&gt;
  &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;^/$&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;req&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;res&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='nx'&gt;dj&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;respond&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;res&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;&amp;lt;h1&amp;gt;Homepage&amp;lt;/h1&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
  &lt;span class='p'&gt;}]&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt;
  &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;^/other$&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;req&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;res&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='nx'&gt;dj&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;respond&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;res&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;&amp;lt;h1&amp;gt;Other page&amp;lt;/h1&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
  &lt;span class='p'&gt;}]&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt;
  &lt;span class='p'&gt;[&lt;/span&gt;&lt;span class='s1'&gt;&amp;#39;^/page/(\\d+)$&amp;#39;&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='kd'&gt;function&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;req&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;res&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='nx'&gt;page&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt; &lt;span class='p'&gt;{&lt;/span&gt;
    &lt;span class='nx'&gt;dj&lt;/span&gt;&lt;span class='p'&gt;.&lt;/span&gt;&lt;span class='nx'&gt;respond&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='nx'&gt;res&lt;/span&gt;&lt;span class='o'&gt;,&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;&amp;lt;h1&amp;gt;Page &amp;#39;&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='nx'&gt;page&lt;/span&gt; &lt;span class='o'&gt;+&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;&amp;lt;/h1&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;);&lt;/span&gt;
  &lt;span class='p'&gt;}]&lt;/span&gt;
&lt;span class='p'&gt;]);&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This is a great system, as long as a) you don&amp;#8217;t have too many routes and b) your functions aren&amp;#8217;t too large. Otherwise I feel like it gets a bit unwieldy trying to keep track of what happens where. I&amp;#8217;m kind of envisioning Bomber being used for slightly larger projects. And in that case it is nice being able to see all your routes at one glance.&lt;/p&gt;

&lt;p&gt;This means I&amp;#8217;d like the routes to be in a separate file from the functions.&lt;/p&gt;

&lt;p&gt;The Django way works like this. You have a file in which you declare your routes, and each route maps to a specific function else where in the app. Here&amp;#8217;s an example from the docs:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='n'&gt;urlpatterns&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;patterns&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
    &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;r&amp;#39;^articles/2003/$&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;news.views.special_case_2003&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt;
    &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;r&amp;#39;^articles/(\d{4})/$&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;news.views.year_archive&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt;
    &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;r&amp;#39;^articles/(\d{4})/(\d{2})/$&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;news.views.month_archive&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt;
    &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;r&amp;#39;^articles/(\d{4})/(\d{2})/(\d+)/$&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='s'&gt;&amp;#39;news.views.article_detail&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;),&lt;/span&gt;
&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;I have two complaints about the way Django does routing.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I have to write out a route for every different function I want to use.&lt;/li&gt;

&lt;li&gt;&lt;a href='http://docs.djangoproject.com/en/dev/topics/http/urls/#named-groups'&gt;Named groups&lt;/a&gt; aren&amp;#8217;t very elegant (and this is Python&amp;#8217;s fault not Django&amp;#8217;s).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;But there are two things I really like about the way Python does routing.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It is great being able to just write a regular expression. I like that power.&lt;/li&gt;

&lt;li&gt;You can pass off the processing of a URL to other routing files. Here&amp;#8217;s the example from &lt;a href='http://docs.djangoproject.com/en/dev/topics/http/urls/#including-other-urlconfs'&gt;the documentation&lt;/a&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='n'&gt;urlpatterns&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;patterns&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;
    &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;r&amp;#39;^weblog/&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;        &lt;span class='n'&gt;include&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;django_website.apps.blog.urls.blog&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)),&lt;/span&gt;
    &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;r&amp;#39;^documentation/&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;include&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;django_website.apps.docs.urls.docs&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)),&lt;/span&gt;
    &lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;r&amp;#39;^comments/&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt;      &lt;span class='n'&gt;include&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='s'&gt;&amp;#39;django.contrib.comments.urls&amp;#39;&lt;/span&gt;&lt;span class='p'&gt;)),&lt;/span&gt;
&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This is really great. And is something I hope to add to the routing for Bomber soon.&lt;/p&gt;

&lt;p&gt;The Rails way works very similar to how I ended up doing routing in Bomber.&lt;/p&gt;

&lt;p&gt;It is also very similar to how Django does its routing. There is a subtle difference, however. With Rails, instead of having a route match to a function, a route just generates an object which has all the parameters needed to find the function. Then Rails uses this object to actually do that. The difference is that you can use parameters gathered from the URL to tell Rails which (to use Rails lingo) controller to use, or which action to run. This means you can set up defaults and not have to do anything else (if you want to). Even if you add controllers or actions later, your defaults still handle everything. Here&amp;#8217;s an example from the &lt;a href='http://guides.rubyonrails.org/routing.html#default-routes'&gt;Rails Guide on Routing&lt;/a&gt;:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;span class='n'&gt;map&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;connect&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;:controller/:action/:id&amp;#39;&lt;/span&gt;
&lt;span class='n'&gt;map&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;connect&lt;/span&gt; &lt;span class='s1'&gt;&amp;#39;:controller/:action/:id.:format&amp;#39;&lt;/span&gt;
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;This solves my first complain about Django.&lt;/p&gt;

&lt;p&gt;I also like it much better how you don&amp;#8217;t have to think about regular expressions if you don&amp;#8217;t want to. &amp;#8220;Give me everything between this slash and this one and call it X&amp;#8221; seems so intuitive to me. This solves my second complaint about Django.&lt;/p&gt;

&lt;p&gt;In the end I am hoping to have a system that takes the best parts from Django and Rails, and I think I am on my way.&lt;/p&gt;
&lt;div class='footnotes'&gt;&lt;hr /&gt;&lt;ol&gt;&lt;li id='fn:1'&gt;
&lt;p&gt;Simon Willison has &lt;a href='http://simonwillison.net/2009/Nov/23/node/'&gt;a great write up of how to get it installed&lt;/a&gt; (I can&amp;#8217;t link directly to that section, scroll down). And there is &lt;a href='http://wave.to/nodejs/install/nodejs_0_1_18_t1.dmg'&gt;a Mac OS X installer&lt;/a&gt; if that is easier for you. But the installer will soon become out of date. It will probably be easiest to stay current if you checkout and build from source. Node is changing quickly these days! &lt;a href='#fnref:1' rev='footnote'&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;</content>
	</entry>
	

</feed>
