This document discusses ways to create lightweight Ruby solutions by simplifying frameworks and components. It suggests replacing ActiveRecord with the simpler and faster Sequel ORM. It also recommends using Zepto.js instead of jQuery for mobile apps, and Rack and Sinatra to build lightweight web apps instead of full Rails applications. Benchmarks show these lightweight approaches can significantly improve performance compared to default Rails. Tools mentioned that aid lightweight development include Pow for local web serving and rbenv for Ruby version management. The document concludes by reminding developers not to see Ruby as the only solution and to consider other languages like Erlang, Scala and C++ for certain problems.
3. Less code
=
Easier to maintain
=
(often)
Faster
4. Motives to travel light
• Production performance
• Complexity overhead
• Learning curve
• More flexibility
• Self-improvement
5. Do you always need all
$ ls
of that?
app/
config/
db/
doc/
Gemfile
lib/
log
public/
Rakefile
README
script/
spec/
test/
tmp/
vendor/
www/
Gemfile.lock
.rspec
config.ru
6. Do you always need all
$ ls
of that?
app/
config/
db/
doc/
Gemfile
lib/
log
public/
Rakefile
README
script/
spec/
test/
tmp/
vendor/
www/
Gemfile.lock
.rspec
config.ru
7. Lightweight plan
• Replace components of your framework
• Inject lightweight tools
• Migrate to a different platform
• Don't forget to be consistent
8. ActiveRecord? Sequel!
• http://sequel.rubyforge.org
• Sequel is a gem providing both raw SQL and neat
ORM interfaces
• 18 DBMS support out of the box
• 25—50% faster than ActiveRecord
• 100% ActiveModel compliant
9. Sequel ORM
class UsersController < ApplicationController
before_filter :find_user, :except => [:create]
def create
@user = User.new(params[:user])
end
protected
def find_user
@user = User[params[:id]]
end
end
10. Sequel Model
class User < Sequel::Model
one_to_many :comments
subset(:active){comments_count > 20}
plugin :validation_helpers
def validate
super
validates_presence [:email, :name]
validates_unique :email
validates_integer :age if new?
end
def before_create
self.created_at ||= Time.now # however there's a plugin
super # for timestamping
end
end
11. Raw SQL
DB.fetch("SELECT * FROM albums WHERE name LIKE :pattern", :pattern=>'A%') do |row|
puts row[:name]
end
DB.run "CREATE TABLE albums (id integer primary key, name varchar(255))"
db(:legacy).fetch("
SELECT
(SELECT count(*) FROM activities WHERE
ACTION = 'logged_in'
AND
DATE(created_at) BETWEEN DATE(:start) AND DATE(:end)
) AS login_count,
(SELECT count(*) FROM users WHERE
(DATE(created_at) BETWEEN DATE(:start) AND DATE(:end))
AND
(activated_at IS NOT NULL)
) AS user_count",
:start => start_date, :end => end_date)
13. Clean frontend with
Zepto.js
• http://zeptojs.com
• JS framework for with a jQ-compatible syntax
and API
• Perfect for rich mobile (esp. iOS) web-apps, but
works in any modern browser except IE
• 7.5 Kb at the moment (vs. 31 Kb jQ)
• Officially — beta, but used at mobile version of
Groupon production-ready
15. Xtra Xtra Small: Rack
• Rack is a specification of a minimal Ruby
API that models HTTP
• One might say Rack is a CGI in a Ruby
world
• Only connects a webserver with your
«app» (actually it can be just a lambda!)
16. Rack
• You need to have an object with a method
call(env)
• It should return an array with 3 elements
[status_code, headers, body]
• So now you can connect it with any webserver
that supports Rack
require ‘thin’
Rack::Handler::Thin.run(app, :Port => 4000)
• Lightweight webapp completed
17. Rack App Example
class ServerLoad
def call(env)
[200, {"Content-Type" => "text/plain"}, ["uptime | cut -f 11 -d ' '"]]
end
end
18. Metal. Rack on Rails
• ActionController::Metal is a way to get a valid Rack
app from a controller
• A bit more comfortable dealing with Rack inside
Rails
• You still can include any parts of ActionController
stack inside your metal controller
• Great for API`s
19. Metallic API
class ApiController < ActionController::Metal
include AbstractController::Callbacks
include ActionController::Helpers
include Devise::Controllers::Helpers
before_filter :require_current_user
def history
content_type = "application/json"
recipient = User.find(params[:user_id])
messages = Message.between(current_user, recipient)
if params[:start_date]
response_body = messages.after(params[:start_date]).to_json
else
response_body = messages.recent.to_json
end
end
end
20. Sinatra
• Sinatra should be considered as a compact
framework (however they prefer calling it DSL)
replacing ActionController and router
• You still can include ActiveRecord, ActiveSupport
or on the other side — include Sinatra app inside
Rails app
• But you can also go light with Sequel / DataMapper
and plaintext / XML / JSON output
21. Sinatra
require 'rubygems'
require 'sinatra'
get '/' do
haml :index
end
post '/signup' do
Spam.deliver(params[:email])
end
mime :json, 'application/json'
get '/events/recent.json' do
content_type :json
Event.recent.to_json
end
22. Padrino. DSL evolves to
a framework
• http://www.padrinorb.com/
• Based on a Sinatra and brings LIKE-A-BOSS
comfort to a Sinatra development process
• Fully supports 6 ORMs, 5 JS libs, 2
rendering engines, 6 test frameworks, 2
stylesheet engines and 2 mocking libs out
of the box
• Still remains quick and simple
23. Padrino blog
$ padrino g project sample_blog -t shoulda -e haml
-c sass -s jquery -d activerecord -b
class SampleBlog < Padrino::Application
register Padrino::Helpers
register Padrino::Mailer
register SassInitializer
get "/" do
"Hello World!"
end
get :about, :map => '/about_us' do
render :haml, "%p This is a sample blog"
end
end
24. Posts controller
SampleBlog.controllers :posts do
get :index, :provides => [:html, :rss, :atom] do
@posts = Post.all(:order => 'created_at desc')
render 'posts/index'
end
get :show, :with => :id do
@post = Post.find_by_id(params[:id])
render 'posts/show'
end
end
25. A little bit of useless
benchmarking
• We take almost plain «Hello World»
application and run
ab ‐c 10 ‐n 1000
• rack 1200 rps
• sinatra 600 rps
• padrino 570 rps
• rails 140 rps
27. Pow
• http://pow.cx/
• A 37signals Rack-based webserver for
developer needs
• One-line installer, unobtrusive, fast and only
serves web-apps, nothing else
• cd ~/.pow
ln ‐s /path/to/app
30. Ruby is not a silver
bullet
You should always consider different platforms and
languages: Erlang, Scala, .NET and even C++
31. Ruby is not a silver
bullet
You should always consider different platforms and
languages: Erlang, Scala, .NET and even C++
Don't miss Timothy Tsvetkov's speech
tomorrow