Sails vs Rails


If you're an avid or long-term Rails user then most of what you've learned could easily be reused moving forward. Take for example, Sails.js, a Node.js web framework that resembles an MVC architecture, routes, ORM, assets pipeline, etc...so for one it could be an easy transition from one technology stack to another.

Rails clearly wasn’t designed to be just an API back-end. It provides so much more and things like middleware stack, views generation, view/form/route helpers; apparently go down the drain so there aren't many reasons out there to use Rails to just spit out a JSON to a Bootstrap or Angular. Front-end support is another story. While there were some attempts to make JavaScript and CSS first-class citizens, they still reside somewhere in /app/assets/javascripts/app/controllers or in /lib/assets/javascripts/... or in /vendor/assets/javascripts/... depending on which direction the wind was blowing when the developer was trying to come up with a convention. Once you start thinking about performance and scale, it isn't hard to come up with a faster language or framework that will suit your needs. Building an MVP, on the other hand, might be a different story since developer time in a startup is often far more expensive then performance time of the app. And because Rails is famous for fast development, plenty of defaults can get you up and running very quickly.

So Sails.js comes handy with all of the benefits of Node.js asynchronousity where even request and response are readable and writable streams, the ability to use front-end engineers on the back-end without them scratching the back of their heads too often, being able to use npm and bower that actually make front-end assets a first-class citizen, non-blocking architecture of node, etc...

The following is a quick comparison of a simple Sails.js app and a Rails app. Standard apps created using default generators mean they do the same simple thing: respond to a 'GET /products.json' and spit out a list of 10 products, without using a database.

Rails app
ab -n 1000 -c 200 -C NO_CACHE=1 http://127.0.0.1:9292/products

Gemfile:

gem 'rails', '4.2.0'
gem 'pg'

Route:

resources :products, only: [:index]

Controller:

class ProductsController < ApplicationController
  def index
    items = []
    10.times { items.push({ id: 1, name: 'Name'}) }
    render json: items
  end
end

Start:

puma config.ru --env production

Results:

Concurrency Level:      200
Time taken for tests:   3.103 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      580000 bytes
HTML transferred:       231000 bytes
Requests per second:    322.32 [#/sec] (mean)
Time per request:       620.510 [ms] (mean)
Time per request:       3.103 [ms] (mean, across all concurrent requests)
Transfer rate:          182.56 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   1.8      0       6
Processing:    11  572 241.5    516    1057
Waiting:        7  568 241.0    513    1050
Total:         17  573 240.4    516    1057

Percentage of the requests served within a certain time (ms)
  50%    516
  66%    527
  75%    611
  80%    779
  90%   1016
  95%   1038
  98%   1044
  99%   1050
 100%   1057 (longest request)
Sails
ab -n 1000 -c 200 -C NO_CACHE=1 http://127.0.0.1:1337/products

Route:

get /products': 'ProductsController.index

Controller:

module.exports = {
  index: function (req, res) {
    var items = [];
    for (var i = 0; i < 10; i++) {
      items.push({id: 1, name: 'Name'});
    }
    return res.json(items);
  }
};

Start:

sails lift --prod

Results:

    Concurrency Level:      200
Time taken for tests:   1.894 seconds
Complete requests:      1000
Failed requests:        0
Write errors:           0
Total transferred:      712726 bytes
HTML transferred:       231000 bytes
Requests per second:    527.99 [#/sec] (mean)
Time per request:       378.794 [ms] (mean)
Time per request:       1.894 [ms] (mean, across all concurrent requests)
Transfer rate:          367.49 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    2   2.9      0       9
Processing:    16  375 108.6    375     691
Waiting:        1   36  71.8      5     298
Total:         17  377 109.7    376     695

Percentage of the requests served within a certain time (ms)
  50%    376
  66%    396
  75%    410
  80%    428
  90%    484
  95%    589
  98%    663
  99%    680
 100%    695 (longest request)

Not that even thought I didn't utilize multi-core usage library or pm2 for Sails app, Sails still seems almost twice as fast.

Below are two trends: