Fleegix.org

Logan, client- and server-side JavaScript test runner

12 days ago / 0 Comments

Some of the work I'm doing at Yammer involves writing JavaScript code that runs in different environments. We're using geddy-model code in the browser, as well as with TheRubyRacer (which embeds the V8 JavaScript interpreter in a Ruby process).

This code is part of the Geddy web framework I have been building for Node.js -- so this means three different environments, and and four different JavaScript interpreters, that this code has to work within.

Multi-environment testing? Dual-sided? X-env?

I've been talking to people about ways to solve this -- in particular, Anders Conbere, who is working with similar issues at his job with Estately.

Testing multi-environment JavaScript code is an annoying problem. I looked around, I really didn't find any good solutions.

(I also didn't find anything nice and snappy to call JS code that has to run on both client and server. What's the "Ajax" of that? "Dual-sided"? "Multi-environment"? "JS-everywhere"?)

Meet Logan

I sat down to see what would be required to run the same tests in all these different environments, and it turned out to be pretty reasonable to build something that can run both brower- and server-side tests (thanks, Node.js!).

Despite having built Windmill's complex JavaScript API (or perhaps because of it), I've come around to Mikeal's way of thinking on testing: I want something minimal, without a lot of frameworky baggage -- something that just sets up some conditions and does some asserts.

What I've ended up with is Logan, a very small test runner that lets you run your tests in browsers, in Node.js, and in embedded V8 with TheRubyRacer.

The name is probably kind of obvious to anybody who's familiar with old sci-fi movies -- Logan is a runner), of course.

Logan uses a version of Node's assert module that Anders patched to remove the V8-specific code. I would love to see these changes pushed upstream to Node, so this fork doesn't have to persist (assuming there's a minimal performance impact).

Logan requires Node.js, and of course if you want to test out tests in TheRubyRacer, you need to have it installed.

Sharing code between sides

For Logan's testing purposes, "server-side" means in Node.js, which uses CommonJS modules. "Client-side" includes the browsers, and TheRubyRacer, where there is no facility for loading code modules from within the runtime. Logan uses plain requires for the server-side, and eval/script-append in the clients.

I should take a second here to call out very specifically one of the requirements is synchronous loading of dependencies. (This is why I went the route of source-code transformation.)

Once you get past some initial hackery, it's not that bad loading code in these different enviroments. (After you've done enough client-side JavaScript, I suspect your threshold for hackery gets a little higher.)

To make this stuff work, you do have to follow some specific rules in both app-code, and testing code. (The constraints for the app code are needed if you plan to run your code on both client and server at all, not specifically for running Logan tests.)

1. Use namespaces in your modules

Use a namespace object inside the module file -- you won't have module scope when you load it in the browser. Name it the same name as the variable you'll be setting it to when you load it via CommonJS require.

2. Check for the need to export

Only export your namespace in the CommonJS environment.

For example, in the module file, foo.js:

if (typeof foo != 'undefined') { foo = {}; }

foo.bar = new function () {
  this.a = 1;
  this.b = function () {}; 
}();

if (typeof module != 'undefined') { module.exports = foo.bar; }

Or, if you are exporting a constructor:

if (typeof foo != 'undefined') { foo = {}; }

foo.Baz = function () {
  this.a = 2;
  this.b = []; 
};  

if (typeof exports != 'undefined') { exports.Baz = foo.Baz; }

3. Set require result to namespace name

Use the same name as the namespace you created in the module for the variable name of the require result.

4. Create top-level namespaces non-destructively.

In your tests, if you're creating top-level namespaces to hang your required objects on, use something to create them that checks for their existence before creating.

Logan includes a utility function, logan.namespace, to help with this. In your own app's code, you'll either have to use a utility function for doing this, or simply check with a typeof check for undefined.

Here's how to load and use the previous two examples:

logan.namespace('foo');
foo.bar = require('./path/to/foo');
foo.Bar = require('./path/to/bar').Bar;

var fooTests = new function () {
  this.testFooBarAIsTruthy = function () {
    assert.ok(foo.bar.a);
  };

  this.testFooBazAIsNumber = function () {
    var barInstance = new foo.Bar();
    assert.equal(typeof barInstance.a, 'number');
  };

}();

logan.run(fooTests);

Details

The reason for these special requirements is the difference between the way that code loads on the client and the way it loads via CommonJS.

In the client environment (including TheRubyRacer), there is no module-level scope, and the mechanism for loading code doesn't return any value, so namespace creation has to happen inside the module file, and has to be careful not to rewrite anything other modules might have done.

Logan makes this work with CommonJS require syntax in your tests by doing source-code transformation -- it uses the require statements to know what code to load, and rewrites the statements so they don't stomp on the results of the previous eval operation.

If you're at all interested in the icky rewriting tricks necessary, have a look at the source for the browser runner.

The process for running tests in TheRubyRacer is pretty weird too -- Node shells out to a Ruby script that then turns right back around and embeds V8. It's a crazy world we're living in.

What's next

Logan is very new. I'm sure there are better ways to deal with the problems of X-env testing. (How about that? Yeah, "X-env"? It has the letter "X" in it like Ajax, right?) At least I hope there are better ways. I'm very interested in getting feedback on how to make improvements.

0 Comments

Geddy models/validations for Node.js

3 months ago / 1 Comment

The last couple of weeks have been a blast.

I've been settling into my new job at Yammer, getting to know the guys on the team, and enjoying the insanely delicious food. Yes, we have a chef that comes in; it's pretty ridiculous.

By happy accident, my team at Yammer is using the work I've done with Geddy on models and validations -- but in the browser.

It's kind of mind-bending to see code written for Node.js running in IE6, but that's a real-world example of the pure awesome we get with server-side JavaScript. No more writing the exact same input-validation in two different languages.

Geddy has an easy, intuitive way of defining models, with a full-featured set of data validations. The syntax is very similar to models in Ruby's ActiveRecord or DataMapper, or Python's SQLAlchemy.

As I mentioned, the model module works great both in Node, and in the browser, so it's very easy to share model and input validation code in your app between client and server.

Here is an example of a model with some validations:

var User = function () {
  this.property('login', 'String', {required: true});
  this.property('password', 'String', {required: true});
  this.property('lastName', 'String');
  this.property('firstName', 'String');

  this.validatesPresent('login');
  this.validatesFormat('login', /[a-z]+/,
      {message: 'Subdivisions!'});
  this.validatesLength('login', {min: 3});
  this.validatesConfirmed('password', 'confirmPassword');
  this.validatesWithFunction('password', function (s) { 
      // Something that returns true or false
      return s.length > 0;
  });
  // Can define methods for instances like this
    this.someMethod = function () {
      // Do some stuff
    };
};

// Can also define them on the prototype
User.prototype.someOtherMethod = function () {
  // Do some other stuff
};

// Server-side, commonjs
exports.User = User;
// Client-side
// model.registerModel('User');

Creating an instance of one of these models is easy:

var params = {
  login: 'alex',
  password: 'lerxst',
  lastName: 'Lifeson',
  firstName: 'Alex'
};
var user = User.create(params);

Data-validation happens on the call to create, and any validation errors show up inside an errors property on the instance, keyed by field name. Instances have a valid method that returns a Boolean indicating whether the instance is valid.

// Leaving out the required password field
var params = {
  login: 'alex',
};
var user = User.create(params);

// Prints 'false'
sys.puts(user.valid());
// Prints 'Field "password" is required'
sys.puts(user.errors.password);

I've been writing a bunch of tests so you can see some other examples.

Really cool seeing code that runs equally well on the server and in the browser. A credible server-side JavaScript plaform like Node really opens up a ton of new possibilities. Looking forward to seeing where it all goes.

1 Comments

What's next is Yammer

3 months ago / 8 Comments

I've just come back from a meeting at the offices of my new employer, Yammer, Inc. I've accepted a position there as Senior Front-End Engineer, doing development work primarily in JavaScript and Ruby.

I start next week, after enjoying a little family time this week -- coincidentally it's spring break for my boys.

For those who don't know, Yammer is a microblogging service for the enterprise. Think Twitter, or Facebook's News Feed, but for use in businesses.

Yammer is an excellent fit -- I've been a heavy user of microblogging and 'activity streams' since the fairly early days of Twitter.

It's easy to see the impact this new medium of communication has had on people's personal lives. I'm looking forward to helping invent how it impacts people in the the workplace.

The Yammer office is at Townsend and 5th in downtown San Franciso, very near South Park and the baseball stadium, so my commute remains a breezy 15-minutes up 280.

If you happen to find yourself in that part of town, hit me up -- I'd love to go have lunch.

8 Comments

REST easy with Geddy for Node.js

4 months ago / 2 Comments

Geddy is a small Web-app development framework for Node.js. It uses a router syntax similar to Rails or Merb, and now has tools for quickly creating RESTful, resource-based routes as well.

Building and installing Geddy

Prerequisites: An up-to-date version of Node.js. I'm developing Geddy on Linux (and I'm lazy), so I'm not sure yet what adjustments might be needed for it to work smoothly on OS X. I hope one of you Mac guys can tell me what's needed.

Get Geddy from GitHub and install:

git clone git://github.com/mde/geddy.git
cd geddy
make && sudo make install

There's currently no configure step, because the installation is really just packaging stuff up, and a little file-copying. The installation sticks Geddy into .node_libraries/ in your home directory.

Creating a Geddy app

Geddy comes with a utility called geddy-gen you can use to create an app:

mde@localhost:~/work$ geddy-gen app bytor
Created app bytor.
mde@localhost:~/work$ cd bytor
mde@localhost:~/work/bytor$ geddy
Server running at http://127.0.0.1:8000/

Go to http://localhost:8000/, and you should see:

Attention all planets of the Solar Federation

Pretty simple.

What's in a Geddy app? Well, geddy-gen starts you off with a simple app stub. The directory contents look like this:

mde@localhost:~/work$ find bytor
bytor
bytor/config
bytor/config/router.js
bytor/app
bytor/app/controllers
bytor/app/controllers/main.js
bytor/public

There's just a single, simple default route in router.js:

var Router = require('geddy/lib/router').Router;

router = new Router();
router.match('/').to({controller: 'Main', action: 'index'});

exports.router = router;

This has the the / path handled by the index action on the Main controller.

Adding resources

Change directories into your new app directory, and use geddy-gen resource to create one:

mde@localhost:~/work/bytor$ geddy-gen resource snow_dogs
[ADDED] ./app/controllers/snow_dogs.js
resources snow_dogs route added to ./config/router.js

Restart Geddy, and you'll see the new route working. Hit your new route -- for example, http://localhost:8000/snow_dogs.json, and you should see something like this:

{"method":"index","params":{"extension":"json"}}

Depending on how your browser is set up to deal with the JSON MIME type, it may want to open the response in a separate application.

Resource controllers

Take a look at the new file created, app/controllers/snow_dogs.js to see what actions a resource-based controller has. The actions are methods called on the controller, and get passed a copy of the parsed parameters from the URL and query string.

Okay, so REST isn't quite the same as CRUD, but Geddy's resource-based routes do take the expedient course of creating url/request-method mappings for easy CRUD operations like this:

GET /snow_dogs
(SnowDogs controller, index action)

GET /snow_dogs/add
(SnowDogs controller, add action, for any new-resource template -- "new" is not usable as a JavaScript action name)

POST /snow_dogs
(SnowDogs controller, create action)

GET /snow_dogs/:id
(SnowDogs controller, show action)

PUT /snow_dogs/:id
(SnowDogs controller, update action)

DELETE /snow_dogs/:id
(SnowDogs controller, remove action)

Content-negotiation

Geddy has some built-in ability to perform content-negotiation based on the abilities of the client, and the requested filename-extension. Right now, this feature is very bare-bones, supporting only JSON and plaintext, but can be easily extended to support XML, Atompub, or whatever.

If you have a JSON-serializable JavaScript object you want to return in JSON format, all you have to do is set up a resource with geddy-gen resource, and in the appropriate controller action, pass your JavaScript object to the respond method.

Something like this:

this.respondsWith = ['text', 'json'];

this.show = function (params) {
  // (Fetch some item by params.id)
  item = {foo: 'FOO', bar: 1, baz: false};
  this.respond(item);
};

Geddy will automatically serialize item to JSON, and set the content-type appropriately -- assuming the client can accept JSON.

Eventually it should be possible to register handlers for new content-types on a per-controller, or per-model basis. (Doing this by way of defining a 'to_[format]' method on the objects to be returned isn't a workable solution in JavaScript, when you're likely to be returning built-in types.)

If you want to use a specific format, you can pass it as the second argument to the respond call -- even if it's not one of the listed formats in respondsWith.

Perhaps something like this:

this.show = function (params) {
  // (Fetch some item by params.id)
  item = {foo: 'FOO', bar: 1, baz: false};

  // Serve up some html
  if (params.extension == 'html') {
    var html = '';
    html += '<html><body>';
    html += '<h3>' + item.foo + '</h3>';
    html += '</body></html>';
    this.respond(html, 'html');
  }
  // Otherwise return formatted data
  else {
    this.respond(item);
  }
};

Geddy uses simple strings for the identifiers of the formats, rather than an enumeration, because it's just cleaner-looking. I prefer simply 'json' to this.formats.JSON or something like that.

What's next?

Next is work on easy handling of templates. I'm not sure how far down the HAML/SASS road I want to go initially, but basic EJS, and Moustache seem like a good place to start.

2 Comments

Geddy: Web framework for Node.js

4 months ago / 0 Comments

So I've posted previously about the embarrassment of riches that we have with Node.js modules, specifically Web frameworks.

I count no less than 14 frameworks and micro-frameworks for building Web-apps with Node right now on the list of Node modules.

I had actually hoped to use one of these to build a small Node app, but as it turns out, many of these are either half-finished, or are broken with current versions of Node. Pretty understandable, given how quickly Node is changing.

Express looks good, but I'm a little more interested in something that will let me build complex apps -- and the Sinatra-style routing, with the verb and everything kind of inline there, seems a little verbose. I prefer the simpler DSL of Rails-/Merb-style routes. To me it's just more expressive, flexible, and powerful.

So I started building a basic router, looking at a lot of the ideas in Bomber.js, and remembering back on how simple and hackable the Merb framework was to use.

The result is Geddy. It's a small Web-app development framework that's still very embryonic -- but it does routing and invoking controller actions, and serves static files. I'm having a blast hacking on it. It's crazy fun doing all this server-side code in JavaScript.

Of course, it's named in honor of Geddy Lee, the bassist for Rush.

Routing

Routes in Geddy look like this:

r = new Router();
r.match('/').to({controller: 'Main', action: 'index'}).name('main');
r.match('/users/:userid/lerxstizer/:lerxstid').to(
  {controller: 'Users', action: 'lerxstizer'});

This should look pretty familiar to anybody who's used Merb or Rails. The controller here is really just an execution context for the action, which is really just a handler method.

The advantage of thinking of these as 'controller' and 'action' is that it allows the execution context of the handler method to inherit a bunch of helpful methods from a base Controller.

It also leverages people's understanding of MVC so the on-ramp to building something is minimal.

Controllers and actions

On startup, Geddy scans the app/controllers directory for JavaScript files, and loads them as available controllers.

A sample controller file looks like this (in file app/controllers/users.js):

var Users = function () {
  this.lerxstizer = function (params) {
    // params should have userid, lerxstid, and any query-string params
    this.render(JSON.stringify(params));
  };
};

exports.Users = Users;

The controllers are all required and instantiated based on convention, but I'm not going all meshugah with the Railsy pluralization rules.

The controller files should be all lowercase names, with underscores separating words. The constructor function in the file should be a camel-cased, initial-capital-letter version of the same name.

Some examples:

File Constructor
app/controllers/snow_dogs.js SnowDogs
app/controllers/priests_of_syrinx.js PriestsOfSyrinx

The action is a method then called on the controller instance, and passed a params object that contains any params pulled off by matching the pattern in the router -- and any query-string params.

So for example, in the case of the 'lerxstizer' example above, if you hit the following URL:

/users/alex/lerxstizer/2112?code=YYZ

The params object will look like this:

{
  userid: 'alex',
  lerxstid: '2112',
  code: 'YYZ'
}

Static files

It's impossible to develop a Web application without serving the static assets needed. I took a look at how Paperboy and other frameworks did it, and added static-file support for Geddy.

In development-mode, if an URL matches no routes, Geddy will serve up matching filenames in the public/ directory rather than responding with a 404. Obviously this directory path needs to be configurable at some point.

Stuff to do

There's a long list of stuff to hack in:

  • Resource-based routes
  • Content negotiation
  • Templating support
  • Better error handling
  • Controller-generator script
  • Kiwi package

I also need to separate out the framework code from what will eventually be generated app code. Lots of stuff to work on, and hopefully lots of opportunity to get to know Node better.

0 Comments

Node.js frameworks

4 months ago / 2 Comments

Quite a growing list of Node.js modules and projects on GitHub. It's like a Cambrian explosion of JavaScripty goodness.

If you're thinking of building a Webapp with Node, it's hard to know which of these embryonic frameworks to pick -- or if you should even pick one -- since the laws of competition dictate we'll end up with one or two large ones.

This is a problem I ran into working with Merb -- spending time working with a framework, submitting patches, fixing problems, only to see it subsumed into Rails.

I'll still probably pick one to work with, since it'll likely be as round as any wheel I could invent myself. I'll be following the trajectories of these frameworks with some real interest.

2 Comments

Reflections of a JS guy on AS3

11 months ago / 0 Comments

I've been doing a bunch of stuff with AS3 at Slide, and as a long-time JavaScript guy, thought it might be interesting to record my impressions of the language so far. I'll do the bad news first, so I can end on a positive note.

The bad news

Type annotations

Not a fan of the type annotations. I realize this was supposed to be one of the improvements to JS from ECMAScript 4, but so far there has not been a single instance where I've thought "wow, thank FSM I had that static typing to keep me safe."

I know this is jumping into the eternal static/dynamic typing debate, and I skew entirely toward the dynamic. But the reality is that I've met multiple people who've moved from using say, Java, to Ruby or JS, and they always talk about how painful it is to go back to Java. The awful verbosity is one of the reasons.

I see stuff like this in AS3:

var mySprite:Sprite = new Sprite();

This just seems silly.

It's also worth noting that with typed functions you can't have multiple return types from a function now, either -- for example, returning a string on success, and null on failure. (Okay, you could just type it as Object, but that seems pretty pointless.)

// Hello, pretty much everything is an Object
// Why am I typing this at all?
public function foo():Object {
  // I'd kinda like to return different stuff here
}

And now I have to think about two different types for unassigned variables -- one for typed ones (null) and one for untyped ones using the asterisk annotation (undefined, like old-fashioned JS).

// This has a value of null
var foo:Event;
// This has a value of undefined
var bar:*;

Now, there may be benefits to it that are a little bit invisible to me in day-to-day dev, like performance. But with the huge advancements in JS interpreters like the ones we're seeing in TraceMonkey, V8, and SquirrelFish, I'm a lot more dubious about the cost-benefit offered by the static typing and a compile step.

Access modifiers

Seeing all this public/prviate stuff everywhere makes me feel like I'm using Java. Maybe that's the whole idea; I don't know.

At one point I was reading documentation on the Adobe site, and it took me about 10 seconds to realize that a large chunk of code I was looking at actually was Java, not AS3.

Using enclosing scope seems mostly fine for private vars in JS. I guess the implicit binding of all the local vars to this in instances in AS3 makes that impossible, but I get the feeling that some guys really like all the delicious explicitness they get from having to pedantically declare all this stuff.

For me, it's mostly just more crap to have to type, and more noise to filter out when I'm trying to read code.

Closed classes

Again, this is supposed to be a feature. But overriding specific behavior in a class (in say, for example, testing, which is what I'm working on) requires endless subclassing, and having to think about inheritance-chain specificity way too much.

The most annoying example of this so far was some code that needed to accept various types of Events, but some of the containing code might call methods on a specific subclass. The compiler really doesn't like that.

The only way I can see to handle that is to use the "any type" asterisk for the annotation for that param, which kind of raises the question of "this static-typing stuff, it's good for exactly what again?"

Subclass 'super' invocation isn't really a function call

The correlary to this endless subclassing-annoyance is that I can't call a subclass's constructor method with Function.apply, and just pass it the same arguments as the constructor. There are couple of old mailing list threads from back in 2007, one here and the other here that talk about this.

Even after reading these I'm still don't get the rationale for this is -- but as a mere workaday developer, I do know that forcing me to type long lists of parameters mechanically on top of the endless subclassing is horribly tedious and error-prone.

Compile step

Hate it.

I guess I'm way too ADD, or spoiled by JS Web-dev work, but I need my instant gratification. Sitting and waiting for five or six seconds for multiple interdependent SWFs to compile totally breaks my workflow.

I feel like I'm spending a disproportionate amount of time making the compiler happy, and less time thinking about what my program actually does.

Object keys don't iterate in insertion order, WTF?

Okay, so I get that this isn't in the ECMA-262 Edition 3 spec (and don't know if it was supposed to be in ECMAScript 4), but every major ECMA implementation iterates over an Object's keys in the insertion order.

I'm not sure if it's a huge perf-killer, or if they just didn't get around to making it work right, but it seems pointless to position AS3 as "JavaScript with improvements," and then screw up something so fundamental. Before you implement all the improvements, how about getting the basics right?

(And by 'right,' I don't mean "bare minimum correctness according to the spec," I mean "at least as good as the other implementations.")

The good news

A real 'for each'

It's really nice to iterate over items in an array without the tedious array-index incrementation. This is so much nicer, so much more readable:

for each (item in someArray) { // Do stuff to item }

Yes, I know this already exists in newer JavaScript implementations -- but we can't use it until old Internet Explorer albatross goes away.

Checking for the existence of an attribute

So nice to stop using the janky test for whether a property's typeof is undefined. Now I can do:

if ('foo' in bar) { // Do stuff }

I really like this syntax -- way more much readable.

If these kinds of syntactic niceties are in the more-modest ECMAScript 5, I'll definitely continue to be a happy JS programmer.

In Short

I guess it's pretty clear -- what I like about AS3 is its similarities to the JavaScript I know and love, and the small syntactic fixes to what have always been obvious JS warts.

What I don't like is all the Java-like verbosity which, thankfully seems to have died in the main JS evolutionary branch with the ill-advised ECMAScript 4 adventure.

0 Comments

New gig at Slide, new digs in SF, new ... Python?

about 1 year ago / 0 Comments

Okay, yeah, so I've left the blog pretty quiet the last couple of months -- it's been a busy time with lots of changes.

After being without a full-time gig, doing a bunch of contract work, and looking around a lot, I accepted a job offer from the nice folks at Slide. The position is in their office in San Francisco, so in the last month I've moved myself and my family (and our whole houseful of crap) out to the Bay Area.

We're ensconced in a lovely rental in Pacifica, and loving the amazing views of the mountains, ocean ... and of course, the fog.

It's an interesting change going from years of working remotely from home, to working day-to-day in an office. With actual human beings in it. It's quite a change, and actually nice in a lot of ways seeing people other than my family on a regular basis, but there are downsides to the whole deal -- like, you know, having to wear pants.

The other big change, of course, is using Python for my server-side language of choice. I've been pretty much a Ruby guy up to this point, but Slide is a Python shop. The switch has been pretty interesting so far: I'm learning fun idioms like how to fake the ternary operator, and (of course) basic stuff like how not to screw up my indentation. I like it pretty well. Of course we're building Web apps, so there's also piles and piles of tasty JavaScript to work on.

Now that we're set up in our new digs (and the endless piles of boxes are mostly disposed of), and I'm managing to make major changes to code without blowing shit up, I think I'm settled in enough to begin updating here a bit more regularly.

Either that, or microblogging has killed my ability to post -- we'll see I guess.

0 Comments

Fleegix on Sinatra

about 1 year ago / 0 Comments

The Sinatra Web dev framework has been around for a while, but I've recently been seeing it popping up a lot more.

Simon Willison, the co-creator of the Django Python Web-dev framework, even mentioned it to me at SXSW Interactive when I buttonholed him after his panel on the Changing Face of News, to ask him what the Guardian is using for their API service.

(Sadly, he said, it's still all enterprise Java. NPR is using a mix of PHP and Java, and the New York Times runs their API service on Ruby on Rails.)

I suggested to Simon that Sinatra's higher profile comes from its status as the new anti-Rails, and Ezra Zygmuntowicz said the same thing today on Twitter:

@wycats sinatra is filling the gap now that merb is an organ donor ;)

He is of course referring to the fact that Merb, the Ruby Web-dev framework which has proven to be a credible competitor to Rails, is now being merged into Rails -- the result being Rails 3.

But Sinatra is more than that -- Adam Keys put it well in that same back-and-forth on Twitter:

@wycats I see some people taking to Sinatra now that Merb isn't the angsty choice. But mostly, its people looking to do more with less code.

Unless you have a case of man-with-hammer syndrome, you see that no single tool is right for every job -- and Sinatra's lightweight approach (it doesn't even bill itself as a framework, just a 'DSL') looks great for simple uses where you don't need all the overhead of Rails (or even Merb).

I recently converted the Fleegix.js project site from a Merb flat app to a gorgeously minimalist Sinatra app, and found Sinatra's simple aesthetic to be just about perfect. I could also see using it for throwing up simple Web services as well (although it's hard to beat Merb's resource routes and braindead-easy display/provides content-negotiation for that).

My next Sinatra project will be the EpiphanyRadio site, which is definitely due for a little love. It's another simple site (currently a bunch of raw mod_ruby/eruby) which would be a lot nicer as a simple Sinatra app.

0 Comments

Leaving Seesmic

about 1 year ago / 3 Comments

I started at Seesmic a little over a year ago, and it's been great helping the platform grow from a full-page Flash app prototype to an Ajaxy Web app backed by a solid REST API.

There is a time for every purpose under the sun, and now it's time for me to be moving on to other projects better aligned with my personal career goals.

I'm really proud of the work I did at Seesmic, and some of the early technology choices we made (particularly Merb) have proven to be excellent bets.

I also feel extremely fortunate in the great people I've gotten to work with there, and owe Loic a huge debt of gratitude for that opportunity. I remain a Seesmic shareholder, and a big believer in what they're trying to do with the platform. I look forward to seeing where they take it.

Not sure what's ahead for me yet -- I have just started my job search, but I will be blogging (and microblogging) about the process as it unfolds.

3 Comments

Subscribe

About

This is the Weblog of Matthew Eernisse. I'm a Web developer, and work primarily with JavaScript and Ruby.

Yep, It's My Book

Recent Articles