Things don't need to be so hard to read October 8th, 2007
Application.rb seems to be a repository for tidbits of shameful delight. How about getting the current user and checking if we're logged in? Pretty common stuff, yadda yadda.
def user
return @_user unless @_user.nil?
unless cookies['logged_in'].nil? || cookies['logged_in'].empty? || !AppConfig.features['personalization']
@_user = Personalization::User.find :first, :conditions => ["cookie_id = ?", cookies['logged_in']]
end
@_user ||= Personalization::CookieUser.new(self.cookies)
return @_user
end
def logged_in?
return false unless AppConfig.features['personalization']
cookies.include? "logged_in" and cookies["logged_in"] and user.is_a? Personalization::User
end
This really doesn't need to be nearly so verbose.
First off, #user is checking all of the same cookies and config settings that #logged_in? checks.
def logged_in?
user.is_a? Personalization::User
end
What about the user method with all those returns and assignments and conditions?
def user
@_user ||= find_personalization_user || Personalization::CookieUser.new(self.cookies)
end
private
def find_personalization_user
if AppConfig.features['personalization'] && !cookies['logged_in'].blank?
Personalization::User.find :first, :conditions => ["cookie_id = ?", cookies['logged_in']]
end
end
And we end up with methods that are readable and understandable.
Premature Extraction October 2nd, 2007
You should break common HTML fragments into seperate files to keep things DRY. These reusable fragments are called partials.
If you want to render an 'example' partial and pass it the '@variable' variable as 'local_name':
<%= render :partial => 'example', :locals => {:local_name => @variable } %>
Which is pretty "verbose" syntax, but isn't too bad. You can even hide it behind a helper. Today I see this:
<% with_options({:locals => {:listing => listing}}) do |products| %>
<%= products.render :partial => 'listings/products/services' if listing.services %>
<%= products.render :partial => 'listings/products/brands' if listing.brands %>
<% end %>
And each partial is basically:
<h3>Brands</h3>
<p>
<%= with_newlines_as_breaks listing.brands %>
</p>
with_options is a helpful method mixed into #Object by ActiveSupport. It saves space when you need to pass a big hash to several methods. Jamis Buck has a great writeup on it. Here, it's a sign you're being too clever.
This template doesn't need partials. The HTML is never reused. The partials only add obfuscation. When you load the template the first time, first you have to figure out what's going on with the partial. Then, you have to jump to the partial. This is simpler:
<%- if listing.services -%>
<h3>Services</h3>
<p>
<%= with_newlines_as_breaks listing.services %>
</p>
<%- end -%>
<%- if listing.brands -%>
<h3>Brands</h3>
<p>
<%= with_newlines_as_breaks listing.brands %>
</p>
<%- end -%>
A good rule of thumb in refactoring is "three strikes and you're out." So if we had another attribute, say "hours," we'd refactor it to:
<%- %w[services brands hours].each do |attribute| -%>
<%- if listing.send(attribute) -%>
<h3><%= attribute.capitalize %></h3>
<p>
<%= with_newlines_as_breaks listing.send(attribute) %>
</p>
<%- end -%>
<%- end -%>
Fizz Buzz October 1st, 2007
It's frustrating to spend hours with a prospective hire only realize he couldn't code to save his life. The only thing worse is finding out after you've hired him.
It's not their fault. Studies show incompetent people don't know they're incompetent. It's up to you to save everyone's time. Use a short test to screen out the fools.
An example is "Fizz Buzz." The instructions are dead simple. Write a program that:
- Prints the number 1 to 100
- When it reaches a number divisible by 3, print "fizz"
- When it reaches a number divisible by 5, print "buzz"
- When it reaches a number divisible by both, print "fizz buzz"
Too many candidates can't do this. Even if they can, you can tell how bad they are by the implementation.
Here's a submission ported from Visual Basic to Ruby. It's ported because Ruby is a great common language, and to avoid legal trouble from posting a candidate's submission.
1.upto(100) do |i|
fizz = false
buzz = false
if i % 3 == 0
fizz = true
end
if i % 5 == 0
buzz = true
end
if fizz == false and buzz == false
puts i
elsif fizz == true and buzz == false
puts "#{i} fizz"
elsif fizz == false and buzz == true
puts "#{i} buzz"
elsif fizz == true and buzz == true
puts "#{i} fizz buzz"
end
end
Of course he failed before his first line of code. If you're interviewing for a Ruby position, and you're allowed to pick any language, don't pick Visual Basic.
How would I write it?
1.upto(100) do |i|
output = [i]
output << 'fizz' if i % 3 == 0
output << 'buzz' if i % 5 == 0
puts output.join(' ')
end
dry? September 7th, 2007
<% if params[:auto_play] %>
<%= render :partial => 'more_info_listing_box_video',
:locals => {:listing => @listing, :auto_play => true} %>
<% else %>
<%= render :partial => 'more_info_listing_box_video',
:locals => {:listing => @listing, :auto_play => false} %>
<% end %>
Why not...
<%= render :partial => 'more_info_listing_box_video',
:locals => {:listing => @listing,
:auto_play =>(!params[:auto_play].nil? && params[:auto_play] == true)} %>
or something along those lines?