Lazy Loading and Object Proxying Shenangians - Presentation Transcript
Lazy Loading
..and object proxying shenanigans
John Barton
www.whoisjohnbarton.com
@johnbarton
we’re often* hiring
* a month or two ago, right now, a couple of months from now
The Problem:
To handle ever increasing
page load through the
judicious application of view
fragment caching...
... without resorting to
downright ugly code
For Example:
class PostController < ApplicationController
def index
@posts = Post.all
end
end
<% @posts.each do |post| %>
<%= post.title %>
<% end %>
Make it fast:
<% cache 'slow_posts' do %>
<% @posts.each do |post| %>
<%= post.title %>
<% end %>
<% end %>
What now?
class PostController < ApplicationController
def index
@posts = Post.all
end
end
@posts = Post.all is still
evaluated ... and it’s expensive
What about?
<% cache 'slow_posts' do %>
<% Post.all.each do |post| %>
<%= post.title %>
<% end %>
<% end %>
Separation of concerns?
What about?
class PostController < ApplicationController
def index
unless fragment_exist? 'slow_posts'
@posts = Post.all
end
end
end
Separation of concerns?
What About?
class PostController < ApplicationController
def index
@posts = lazy_load { Post.all }
end
end
Still not perfect ... but
fuck it ... I’ve got a job
to get on with
How?
def lazy_load(&block)
LazyLoader.new(&block)
end
class LazyLoader
instance_methods.each { |m| undef_method m unless m =~ /^__/ }
def initialize(&block)
@_initializer = block
end
protected
# pass everything to _target
def method_missing(method, *args, &block)
_target.send method, *args, &block
end
private
# on first call will instantiate itself with _initializer
block
def _target
@_target ||= @_initializer.call
end
end
Gotchas:
... or when I realised I
wanted to be a
Smalltalk programmer
class PostController < ApplicationController
def show
@post = Post.find(params[:id])
end
end
<% if @post %>
<%= @post.title %>
<% end %>
class PostController < ApplicationController
def show
@post = lazy_load { Post.find(params[:id]) }
end
end
<% cache 'slow_post' do %>
<% if @post %>
<%= @post.title %>
<% end %>
<% end %>
NoMethodError:
undefined method `title'
for nil:NilClass
wtf?
Ruby’s boolean operators don’t ask
the objects for their truthyness
Word on the street is Smalltalk has that covered*
* I don’t know Smalltalk so hopefully I’m not full of shit right here
a = lazy_load { nil }
# this is fine
nil.nil? # => true
a.nil? # => true
# this is broken but.....
# i can fix it by opening up NilClass
a == nil # => true
nil == a # => false
# but what do i do about these?
!!nil # => false
!!a # => true
if a
puts "blah!"
end # => "blah!"
Two Solutions:
<% cache 'slow_post' do %>
<% unless @post.nil? %>
<%= @post.title %>
<% end %>
<% end %>
OR
Learn Smalltalk
http://github.com/joho/lazy-loader
we’re pretty frickin rad, come work for us
0 comments
Post a comment