Sails 0.8.9: A Rails-Inspired Real-Time Node MVC Framework
Version 0.8.9 of Sails, a real-time MVC framework built atop node.js, was released on April 9th by Austin, TX-based Balderdash in an ongoing effort to bring a Rails-like development platform to modern web apps.
With over 8 years since the advent of Rails, the Balderdash team envisions the MIT-licensed Sails as an evolutionary step forward: weaving together the rich developer experience of the Rails tradition with the modern capabilities of the real-time web.
InfoQ caught up with Sails creator Mike McNeil for a deeper analysis of the burgeoning framework.
Mike: From the beginning, Sails.js has been about making me more effective at creating awesome, stable Node.js applications for our enterprise and startup customers. In general, our approach has been to take the trusted tools we're already using and crystallizing our best-practices in a reusable way. For instance, we're heavily dependent on two excellent frameworks from the guys at LearnBoost: Socket.io for server push, and Express for our web routing and templating. Express is the most popular framework for Node.js (by about 13,000%, but who's counting?) At every turn, we aim to avoid reinventing the wheel.
Which isn't to say we haven't rolled our own components-- I ended up building an ORM, which is probably the largest piece of original code in Sails, and where we have the most tests. We also have a completely different approach to handling WebSocket code: rather than maintaining a separate code base to handle realtime messaging, you use the same code that handles your regular API. This means that, whether you're building for WebSockets or HTTP, your project is full of the good ole Express code you're used to writing.
It wasn't until I started Balderdash that it occurred to me how important that decision was going to be. We were able to build an API-driven, realtime backend designed to support over 300,000 users in less than month. It mirrors the Box.net API, but also enables all updates to files to be broadcasted in realtime.
INFOQ: Because Meteor leads in popularity in this space, could you highlight some of the similarities and differences specifically?
Mike: Well for starters, we don't have 12 million bucks! But seriously, we're solving different problems: Meteor is focused on creating a completely new kind of real-time web application framework. Sails.js is a solution-focused tool for creating real-time APIs for any kind of application, using the MVC paradigm developers are familiar with.
I learned early on, when swinging our first enterprise deals, that it would be a hard fight to get any full stack framework, let alone Meteor adopted. Node.js is a proven technology, but it's hard enough to convince customers to make the jump to doing full-stack Node.js, much less trying to get them to adopt a new web framework on the front-end.
In the end, people are going to pick the framework that's right for them, based on their needs for the project they're working on--this is open-source, after all!
INFOQ: How does Sails.js handle load balancing / scaling?
Mike: Whether you're deploying behind the Great Corporate Firewall in your data center, virtualizing, working directly with a cloud provider like Joyent, or getting help through PaaS like Modulus or Nodejitsu, the deployment strategy for Sails is just like what you would do with any other sort of Node.js application. I know a few developers in the IRC raved about Nodejitsu's support getting their Sails apps set up, so that might be a good way to go. You'll want to follow the same standard, tested best-practices you'd follow with an Express or Socket.io app. We do bake in support for Redis as both a session and pubsub/socket store. This means you can create as many copies of your Sails server as you need, and everything will still work.
Sails makes it easier to store your session and socket store in Redis. As far as your data models, you'll want to scale the database accordingly. You'll have the same scaling considerations you'd have with any other app.
INFOQ: Are angular.js / ember.js and other client-side enterprise frameworks meant to play nicely with Sails.js, or does Sails.js enforce a application structure of its own? Is Sails.js meant to work with mobile devices?
Mike: One of the fundamental design philosophies behind sails is device agnosticism. We don’t want to to predict or restrict how you build your front-end. That means we want to be flexible enough to deliver data the way you need it whether it’s to the browser, to the native mobile app, to the wrist-watch or refrigerator.
This is a widely-accepted approach, especially in enterprise, where you'll hear it called an SOA (or service-oriented architecture). Most companies are interested in building SOAs because, well, let's put it this way-- the number of different types of devices accessing the internet is not going to decrease any time soon.
Sails places zero control over how you build your front-end, other than offering some optional tools you can use for things like compiling LESS and CoffeeScript-- if you're working on something like that. We've used Sails for native PhoneGap apps and Chrome extensions, and other developers are using Sails to power the backend of their Backbone, Ember, Angular, ExtJS, native iOS and native Android applications. A couple of our contributors are using Sails in even cooler ways: Dennis Bartlett is building a bicycle helmet with a HUD, and Thom Simmons is using Sails to serve the API to his smart frisbee.
INFOQ: What's the advantages of using the JSON api that comes "for free" with every collection?
Mike: The Sails blueprints are a feature we originally added for prototyping, but ended up actually adding tons of value for us in production. If you've got a tested, searchable, sortable, queryable, sexy-looking API, why not use it? You can do some really interesting things by mixing policies with the blueprint API, especially if you switch up the model adapter. It's pretty neat to be able to create a queryable API on an LDAP database (LDAPAdapter) or search tweets (TwitterAdapter) without writing any code.
We're extremely "write-your-own-model-adapter"-friendly (you'll notice your Sails projects actually come with an adapters directory for bundling app-specific adapters). The goal is to keep as many of your API integrations in the ORM as possible--it makes for much cleaner, normalized code, which is great when you're more than one developer. It also has the nice advantage of letting you with real data from the adapter in your API.
INFOQ: Does Sails.js have the notion of 'migrations'?
Mike: Sails supports hooking its models up to both schemaless and "schema-ful" databases. Obviously, when using a database like Mongo or CouchBase, you don't really need migrations, but for more structured data models, it comes into play. On a per-adapter basis, you have control over what happens when the server starts.
I'm not a huge fan of Java, but even I have to admit Hibernate's auto-migrations are awesome. If you're a java developer, you might recognize the migrate setting, our version of the awesome 'dbCreate' concept from Hibernate and Grails. I came from a Grails background, so this was my inspiration. When I looked at Rails, I was very surprised by the necessity to run manual migrations. I get it for working with data, but not with the schema. But I guess it makes sense if you think about it-- Rails was first to the rodeo almost 10 years ago. Oh how things have changed!
We’re experimenting with different concepts here. There’s no technical reason a programmer needs to be concerned with migrations in a schema-based database. We’ve got enough information to take care of this on-the-fly. However, there are convenience configuration settings like dropping tables on server restarts that can increase efficiency during development. We’re listening to the community to come up with aspects of migrations that add to efficiency without adding unnecessary tasks.
INFOQ: What's next for Sails.js? How do you see the project evolving over the next year?
Mike: In general, the community has been really amazing, and I'm committed to ensuring that Sails will continue to be a project that exists to support real use cases of actual applications. Two days after I released the first screencast, Ted Kulp and Carlo de Celico had built Mongo and Redis adapters for Sails. So ongoing, I think the largest number of community contributions we'll see, based on what we've seen so far, will be around adding support for different model adapters and template view engines.
Our features up to this point have been driven by real apps for real money, and I don't see that changing any time soon. For instance, right now we have a client which needs to store its sessions in CouchBase, so we're adding the ability to hook your session store up via an arbitrary Sails adapter.
The biggest piece I still see missing in Sails which isn't being driven directly from a client need is native support for validations and associations in models. Like Express and Socket.io, you can enforce these constraints yourself, but until now, there wasn't a good tool to do that. Earlier this year, I built anchor as a data validation and typing tool to allow you to manage data validation in a consistent way. The next step is integrating it into Sails, which we're tackling this Spring and early Summer.
On a more whimsical note, I do have some sweeping plans to add more optional blueprint features, but I'm going to keep those to myself for now :)
Sadly Sails is not RESTful nor even valid HTTP. :-(
Rather than explain why this is a major no-no I'll just provide a link to StackOverflow:
Fortunately it's not a huge architecture problem for Sails, assuming they (provide a way to) disable those problematic URLs and to use POST/PUT instead.