Engine Yard Blog RSS Feed

To clarify before getting too far into the politics of the title: this is not a grudge match or a death match. This is not an end-all definitive debate killer. This article serves to take a look at two of the web frameworks available to rubyists and some of the benefits and pitfalls of both. To steal a phrase, "This is not a rebel song." We’ll start by taking a look at each framework.

To begin, a little about Rails. It’s an MVC-based (Model-View-Controller) web framework created in 2004 by David Heinemeier Hansson to give Ruby a way to establish a web presence. The idea was Rails would make developers happier and more efficient while getting Ruby to the web. According to information from 2011/2012, at that point there had been over 7 million downloads of Rails.

Sinatra was created in 2007 by Blake Mizerany and is currently maintained by Konstantin Haase. It took the opposite approach of Rails in that it only has the basics of what you need for a web application. No magic, no unicorns - just simple elegant routes to put your app on the web with a Domain Specific Language (DSL) over a rack layer.

Getting Started:

Part of the appeal of rails is the ease of use. Chances are you are already familiar enough with Ruby to know how to gem install, so you grab the version of rails you want and go for it. Within minutes you have the "Riding the Rails" page up and you feel as though something has been accomplished.

It seems simple enough, but there are some caveats. You are started, but from there you need to acquire a bit of knowledge before moving forward. The more experience you get with Rails the more likely you are to avoid such startup pitfalls as missing templates when trying to access views that don’t exist yet or "Unknown Action" errors for models you’ve yet to create. Keep in mind though, even the most seasoned Rails veterans can have issues.

Obviously after a bit of time, when you iron out the kinks, you can be very successful making a rails app. If that wasn’t possible, no one would use it. It’s easier to get started with database integration, managing larger scale application needs, and running an enterprise level app with minimal code tweaks needed. Yay!

Part of the beauty of Rails is the amount of documentation and literature available on how to get started. Below are just a few URLs to tutorials, books, or interactive web learning tools to help. This list is not conclusive and there are many more resources out there for the beginner and the seasoned developer.

Now we’ll take a look at getting started with Sinatra. The beginning is not so much different in comparison to Rails. It really is all about the gems, folks. In this case, there are fewer dependencies, so loading up Sinatra will not be as time consuming as Rails.

Of course, in the same way, if you aren’t careful when getting started, you can end up with errors. In fairness, Sinatra’s errors are a bit more descriptive and generally get you moving in the right direction, compared to Rails’ more esoteric and sometimes misleading huge stack traces filled with code references.

Once those first roadblocks are overcome, it gets easier to use Sinatra, in the same way that getting familiar with Rails makes it easier. The interesting difference here is probably time. Sinatra, being simpler, takes significantly less time to get used to. One could even argue that Sinatra is a good way to get started in order to understand routes and other parts of Rails. So what is Sinatra for then? Simplicity really is what Sinatra is for.

Unfortunately, there are fewer documented ways to get started in Sinatra. The reason is due to press - Rails has more of it. Here is a short list of ways to get started in Sinatra:

It seems, when we compare the bare basics these frameworks are pretty much the same. Sure, Sinatra is a bit more straightforward and Rails has a bit of magic to make things easier, but isn’t the goal still just to get our Ruby stuff on the web? Is there really a need to choose?

The API and the Application:

When it comes to tapping into the power of an API, Sinatra has the upper hand. Because it’s simple, Sinatra has the flexibility to focus on the main task of pulling the information needed.


get '/ruby' do

  api_result = RestClient.get 'http://api.meetup.com/groups.json/?&topic=ruby&order=members&key=XXXXX'

  jhash = JSON.parse(api_result)

  counter = jhash['results'].count

  output = ''

  jhash['results'].each do |j|

    name = j['name']
    city = j['city']
    focus = j['who']
    count = j['members']
    contact = j['organizer_name']
    link = j['link']
    country = j['country']

    output << "<tr><td>#{name}</td> <td><a href = '#{link}' target = _new>#{city}</a></td><td>#{country.upcase}</td><td>#{focus}</td> <td>#{count}</td><td>#{contact}</td></tr>"
  end

  erb :meetup_table, :locals => {result: output, counter: counter}
end

This is all the code that’s needed in Sinatra to pull information for the top 200 Ruby meetups according to meetup.com. It’s easy to just take this information and display it, manipulate it, whatever needs to be done. When it comes time to move it into a database though….things get kinda railsy.

More often than not, when working with Sinatra and trying look for a way to inject information into a database, the first few suggestions will tell you to implement ActiveRecord. This is where lines start to blur and perhaps you should wonder if Sinatra is the right answer for your application.

Rails has an API Controller that can handle APIs and abstract them away from ApplicationController so they won’t interfere with the function of the main application. If the only function of the app is to pull from the API though, this is overkill. Too much overhead for a simple app. To get the same results as the above Sinatra example, you’d need to do the following:



class MeetupResource < ActiveResource::Base

  self.site = "http://api.meetup.com/"

  attr_accessor :api_key

    ActiveResource::Base.logger = RAILS_DEFAULT_LOGGER
 
  API_KEY = ""
  API_MAX_RESULTS = 200

  def self.inherited(klass)
    klass.send('element_name=', klass.name.sub(/^Meetup/,"").downcase)
  end


  module MeetupXmlFormat
    extend self

    def extension
      "xml"
    end

    def mime_type
      "application/xml"
    end

    def decode(xml)
      from_xml_data(
        (Hash.from_xml(xml.sub('latin_1','ISO-8859-1'))["results"]["items"] || {}).values.first)
    end

    private

    def from_xml_data(data)
      if data.is_a?(Hash)
        Array.new.push(data)
      else
        data
      end
    end

  end

  self.format = MeetupResource::MeetupXmlFormat

  def self.find(scope, args = {})
    if args[:params]
      args[:params].merge!({:key => @api_key || API_KEY })
    end
    super(scope, args)
  end

  def self.find_everything(options = {})
    records = []
    each(options) { |record| records << record }
    records
  end

  def self.each(options = {})
    options[:params] ||= {}
    options[:params][:offset] = 0
    options[:params][:page] = API_MAX_RESULTS

    loop do
      if (records = self.find(:all, options)).any?
        records.each { |record| yield record }
        if records.size < API_MAX_RESULTS
          break
        else
          options[:params][:offset] += 1
        end
      else
        break 
      end
    end
  end
end

A great deal less simple and straightforward in comparison to the few lines of Sinatra written. But this is for a small application pulling a simple API. What about when we go full scale?

When it comes to building a full scale application, Rails is more than likely the better choice. Rails is large…but that also means it’s more robust and can handle a lot of the things you will need so you can focus on what the application really needs to have in order to best serve the end users.

Considering scale, Rails will far outstrip Sinatra. As we grow our application, assuming we started in Sinatra, we’ll see that as the number of users and end points grow, the more we are implementing parts of Rails, such as ActiveRecord, in Sinatra in order to keep up. Once that starts happening, once the Sinatra app has grown difficult to manage, it’s time to rebuild it in Rails. It may be obvious over time, but timing is crucial and knowing your app will help you determine when this switch needs to take place.

Beyond complexity, we always need to focus on performance. Availability, latency, and scalability are the cornerstones of whether or not we have customers using our application at the end of the day. Whether it is a money making venture or an open source gift to the community - if our app has no users, it is useless.

Performance can also come down to the size of the application. As a Sinatra application starts to grow, we are likely to see dips in performance. With Rails, there are many ways to offload certain aspects of an application to lighten the load and improve performance. Database indexing, creating ETLs, and background jobs for the application are much easier to implement in Rails and therefore can boost performance as the application begins to grow.

And the winner is…

Remember what was said in the beginning, this isn’t a death match. In this situation, there is no clear winner. Rails and Sinatra each speak to a specific need. As a developer, your job, or someone on your team’s job, is to see the needs of the code now and the needs of users over time. The more familiar you are with both frameworks, the better off you will be to make that decision.

Rails we reserve for larger scale applications, anything with an expectancy for many users and greater than say 15-20 end points, or places where the application can be accessed, like a URL or login portal. Sinatra is for small projects and API pullers, something that has just a few or some limited number of users and about 5-10 end points.

The decision is in the hands of every developer. It’s really about the needs of what you are developing and your comfort level and familiarity with the tools available. Knowing how to get started in both of these frameworks should help to inform that decision and help you to do what’s best for your needs.


Tagged:

comments powered by Disqus