Good Ruby Times

If you're new here, you may want to subscribe to our RSS feed. Thanks for visiting!

In the last few weeks I’ve had the chance to glance into several different codebases, some written years ago by devs in their Rails-infancy (rainfancy?).

Doing the travelling codes-man like that is a golden opportunity to see what people’s stumbling blocks are and how a few easy tricks can improve the code substantially.

What follows is not your new cutting edge coffe making kitchen sink script-fu, but a rather dull list of everyday Ruby that I learned people need to learn.

One-stop requires

This is a short one: requires go into the environment.rb.

Really, don’t use it elsewhere. I’ve seen people reason along the lines of “I keep the ‘require hpricot’ in my xe.com currency rates scraping class as to keep things local and closely knit”. There is some truth to that argument and if a gem is only used by a rake task, maybe it even saves us a second during app startup and some RAM. Still, load order issues, poor readability and maintainability makes it a real pain to deal with down the road.

Trust me: don’t. Put it in environment.rb with a comment describing its purpose in your project.

Whenever possible use the “config.gem”. Advantages:

  • allows you to specify the lib name even if the gem name is different (e.g. for github gems)
  • allows you to require sub libs

    Not used very often perhaps but put to good use by e.g. the right_aws gem where you can choose to load just the SQS part with:

    config.gem 'right_aws', :lib => 'sqs/right_sqs'

    or maybe you just wanted the SDB part?

    config.gem 'right_aws', :lib => 'sdb/right_sdb_interface'

    I personally believe this particular feature is more confusing than helpful, but it’s good to know it’s there.

  • allows you to specify the library version

    Towards the end of the development cycle, before rolling out to production, gems should generally be frozen. An alternative is to define exact versions in the config. I generally advise doing both as having the environment.rb as the one-stop source for gem requirements is a boon for everybody involved, capistrano scripts or new devs on your team.

  • all in one place, easy to find out requirements

Singleton methods (creation)

Ruby provides three (common) ways to define a singleton method:

  1. Explicitly name the class


    class RapidInterventionGroupTeam < ActiveRecord::Base
    def RapidInterventionGroupTeam.load_group_allocations_and_teams(project_id, curr_user)
    # Code
    end
    end

    PROs: hmm, dunno. Makes it easy to know what class you're looking at if the source code file is very long?

    CONs: long, ugly

  2. Use self


    class RapidInterventionGroupTeam < ActiveRecord::Base
    def self.load_group_allocations_and_teams(project_id, curr_user)
    # Code
    end
    end

    PROs: easy to spot here-comes-a-singleton-marker. Some people like to use the 'self' keyword. I call them self-ish people. Sorta short.

    CONs: I think it's ugly. For more than two singletons that repeating 'self' annoys me.

  3. Use the metaclass


    class RapidInterventionGroupTeam < ActiveRecord::Base
    # ==========================
    # = Class methods go here! =
    # ==========================
    class << self
    def load_group_allocations_and_teams(project_id, cur_user)
    # Code
    end

    def team_allocations
    # Code
    end

    def group_allocations
    # Code
    end
    end

    # ============================
    # = Instance methods go here =
    # ============================
    def beef_cow_and_fowl
    # Code
    end
    end

    PROs: shortest. Encourages devs to gather singletons in one spot, and perhaps they will notice when it gets out of hand and start creating mixins. Maybe. Also allows devs to show off their Ruby metaclass knowledge at bars. Maybe.

    CONs: that class < < self is funky and if funky doesn't rub well with you (or your boss) then I guess it's no good.

I personally favor c) whenever the number of class methods goes above two or three; b) is fine when there are just a few of them.

Invoking singleton methods

In Ruby there are many ways to invoke a class method. A few common ones:

  1. Name the class explicitly:


    user = User.find(123)
    Predators.feed_to_wolves(1, user)

  2. When used from an instance of the class, use the context: self.class


    class Predators < ActiveRecord::Base
    def self.feed_to_wolves(pack_id, meat)
    # code
    end

    # we know how we were born...
    def feed_us!(meat)
    self.class.feed_to_wolves(id, meat)
    end
    end

  3. Use a helper instance method


    class Steak
    def self.logger
    @logger ||= Logger.new('log/steak.log')
    def

    def logger
    self.class.logger
    end

    def beef
    logger.debug "MONDAY BEEF!"
    beef_for!(:monday)
    end
    end

    Using an instance method this way to invoke a class level method is of course useful only if you invoke it very often and readability becomes very important. In the above example we're also memoizing (caching) the class level Logger object for fast access.

I personally try 1) to avoid singletons altogether, 2) use method b) whenever possible and 3) start asking myself hard and awkward questions when doing a) more than 3 times a day. Too many singletons might be a codesmell.

Multiple return values

First an example of how people often fake multiple value returns in Ruby:


class Something
def many
[calc_monday_beef, calc_total_beef]
end
end

s = Something.new
retval = s.many

DON’T: when coding a method and you realize you need to return more than one value from a method, you should stop and think. You’re probably doing something wrong.
This is actually the reason why Ruby does not provide a way to return multiple values.

If you’re sure you know what you’re doing and want to return more than value here are some tips:

  1. do NOT do what I did in the example.

  2. use descriptive variable names. “retval” above sucks. Use Ruby multiple value assignments like so:


    >> cows, sheep, fish = [1, 5, 3]
    => [1, 5, 3]
    >> cows
    => 1
    >> sheep
    => 5
    >> fish
    => 3

    Use this to assign multiple return values to local variables with helpful names:


    s = Something.new
    monday_beef, total_beef = s.many

  3. c) if you’re returning many values and you don’t know beforehand how many values are coming back, use the splat operator (*):


    >> me, *others = [:abe, :bob, :caesar, :donald]
    => [:abe, :bob, :caesar, :donald]
    >> me
    => :abe
    >> others
    => [:bob, :caesar, :donald]

  4. d) avoid using array indexes and prefer using Array#first, Array#last:

    • BAD:


      s = Something.new
      retval = s.many
      Beef.find(retval[0], :limit => retval[1])

    • STILL BAD SOMEWHAT BETTER:


      s = Something.new
      retval = s.many
      Beef.find(retval.first, :limit => retval.last)

      Why better? Because you communicate to the reader that that ‘retval’ variable only have two values. (Yeah, it still sucks I know)

    • ALSO BAD BUT SOMEWHAT-ER BETTER STILL:


      s = Something.new
      monday_beef, beef_count = s.many
      Beef.find(monday_beef, :limit => beef_count)

    • GOOD:


      s = Something.new
      Beef.find(s.monday_beef, :limit => s.total_beef_count)

Drop the return

Use the fact that Ruby methods return the value of the last expression. The only place where I think an explicit return is legit is when we want to return early and that’s a performance optimization and as we know, premature optimization is the root of all evil, so unless you have benchmarks at hand proving the need for speed, just don’t user ‘return’.

  • Instead of:


    def course_description
    retval = course_shortname
    retval = course_shortname + "(#{project.shortname})" if project
    return retval
    end

  • Do:


    def course_description
    course_shortname + (project ? "(#{project.shortname})" : '')
    end

Enumerable

Learn to use and love ruby Enumerable module. It’s really really useful.

  • Instead of:


    def Vacation.holidaytype_selectbox
    types = Array.new
    for vt in VacationTypes
    types < < vt[:name]
    end
    @holidaytype_selectbox_model ||= types
    end

  • Use:


    def self.holidaytype_selectbox
    @holidaytype_selectbox_model ||= VacationTypes.map(&:name)
    end

  • Instead of:


    for result in @candidate.results do
    result.destroy
    end

  • Use:

    @candidate.results.each(&:destroy)

  • Instead of:


    @approved = 0
    unless @do_it.nil?
    @events = Event.hourreporting_entries(@person.user_id, params[:projectid], @week.first.date, @week.last.date)

    for e in @events
    if e.approved == 1
    @approved += 1
    end
    end
    end

  • Do:


    if @do_it
    @events = Event.hourreporting_entries(@person.user_id, params[:projectid], @week.first.date, @week.last.date)
    @approved = @events.sum{|e| e.approved ? e.approved : 0}
    end

    The Array#sum method is a Rails addition.

In the app where I spotted the above, the default value for the ‘approved’ field is set to NULL. Had the default value been 0 instead, we could have written the above in an even shorter way:

@events.sum(&:approved)

Truth

In Ruby, everything except false and nil evaluates to true. For realz.

  • Instead of:


    if options[:add] == true && check_id.to_i != 0
    meanie = MeanGuy.find(check_id)
    if meanie.reason != '' && !meanie.reason.nil? && meanie.type == MeanGuy.allowed_types[0]
    # Code
    end
    end

  • Do:


    if options[:add] && !check_id.zero?
    meanie = MeanGuy.find(check_id)
    if !meanie.reason.blank? && meanie.type == MeanGuy.allowed_types.first
    # Code
    end
    end

When chaining conditional checks like above with “&&”, remember that Ruby will stop the checks at the first failure, so always put the ‘cheapest’ checks first (e.g. put any checks that require a database query last).

In the above snippet we see the very common “!something.blank?” idiom. I personally really don’t like the prepended “!” and always try to avoid it. Hurts my eyes and makes me stumble while reading. Ideally the above should be:


if meanie.reason && meanie.type == MeanGuy.allowed_type

but if the meanie reason is allowed to be the empty string — which Ruby will consider True — then we need the explicit blank?-check.

Unrelated neat trick using &&:

  • Instead of:


    def safe_death(dude)
    if dude
    if dude.destroy
    if DudeMailer.deliver_destruction_notification
    Call.his_mum
    end
    end
    end
    end
    safe_death(Dude.first)

  • Do:


    def safe_death(dude)
    dude && dude.destroy && DudeMailer.deliver_destruction_notification && Call.his_mum
    end
    safe_death(Dude.first)

  • This works well only if you don’t care about handling any error conditions
    and success depends on *all* method calls being successful.

    To improve readability in general create as many predicate methods as possible. They are short,
    cheap and really helps readability.

  • Instead of:


    if @person && @person.active == true && @person.projects.include?(:beef_on_monday) && (@person.type == :human || @person.type == :dog)
    # Code
    end

  • Do:


    class Person
    def active_monday_beefer?
    actvive? && member_of?(:beef_on_monday) && (human? || dog?)
    end
    end

    if @person.active_monday_beefer?
    # Code
    end

Method naming

When naming your methods, avoid prepending “get_” or “set_”. The Ruby convention is that getters are just the value name and the setter has the “=” postfix. Avoid the quasi-get_’s too: load_, retrieve_, store_, put_. Sometimes they’re ok, but just stop a second and think if:

store_incoming_beef()

is really really better than

more_beef_in_the_holds()

or

beefers_keepers()

or

not_pork_not_sheep_not_fowl_but?()

As always rules are made to be broken, judiciously. ;)

DON’T:

#get_premium, #get_unix_time_stamp, #load_dates, #retrieve_mums etc

Do:

#premium, #unix_timestamp, #dates, #mums, #beefs

DON’T:


Server.set_clock(Time.now)
@doc.store_signer(Dude.new)
@tellus.put_fire(:wild)
Time.set_back(1.year.ago)

Do:


Server.clock = Time.now
@doc.signer = Dude.new
@tellus.fire!(:wild)
Time.now = 1.year.ago

Keep method names short: e.g. #shorten_timespaces_because_of_special_holiday is too long. Long method names are often a sign of complex methods. Complex methods are often a sign we should refactor the code into smaller pieces.

Sometimes the work done by a method is simply too complicated to be expressed properly
by a short and self-explanatory method name. If so, don’t even try. Leave the method name
short and cryptical. It becomes a marker for the reader of “hey, wanna understand this one?
Sorry but you really really have to go read the code!”.

DON’T:

#shorten_timespaces_because_of_special_holiday

DO:

#holiday_adjustment

Use the “?” for predicates (should *always* return true/false or at least something that evaluates to true false, such as “abc”/nil)


class Session
def finished?
finished_at
end
end

sess = Session.new
sess.finished_at = Time.now
sess.finished?

GOOD:


if sess.finished?
coffee!
end

BAD:


if sess.finished_at
coffee!
end

Use rdoc!

User rdoc for your rails apps. It’s actually nice. When your mum asks you what it is you actually do you can show her the rdocs with links and text and colors and lists and it will make her happy too. And very useful for people trying to read your code (ok, they can run the freakin’ rake task themselves, but you should do it too!).


rake doc:app
open doc/app/index

21 Comments

  1. Posted October 27, 2009 at 3:50 pm | Permalink

    thanks David Palm!
    This is super awesome.

  2. Posted October 27, 2009 at 3:50 pm | Permalink

    Great writeup, lots of good practices in here!

    Regarding the explicit return statement: another good reason not to use it unless you need to is that it’s slower. See Chris Wanstrath’s benchmarks: http://gist.github.com/160718

    An additional con for using class << self for class methods is that you may not be able to tell whether this is a class or instance method just by looking at it without scrolling up to see if it’s inside a class << self block.

    For predicate methods (i.e. finished?), you can precede the return value with !! which forces it to true/false.

  3. jeff
    Posted October 27, 2009 at 4:01 pm | Permalink

    Is it more accurate to call the “singleton” methods “class” methods? To me, singletons are objects that may be instantiated only once.

  4. Posted October 27, 2009 at 4:22 pm | Permalink

    @jeff: do a search in the ruby-lang ML archives. That question has been discussed and re-discussed many many times over the years! Matz calls them ’singleton methods’ in the C sources and hence many feel that settles it. You’re right though, ‘class methods’ is the more common idiom. I think there was a third nomenclature as well. Can’t remember right now.

    As long as we all know what we’re talking about I guess it’s ok, right? :)

  5. Posted October 27, 2009 at 4:25 pm | Permalink

    @arya: I didn’t know about the !! trick, very cool. :

    I’d argue that predicate methods should always be used as such and their return value never used for anything but true/false-like tests, so it’s not really important that the actually return TrueClass/FalseClass.

    I know many programmers that feel queasy about returning, say, a Date object from a predicate method and if an extra cast or two makes them feel safer I’m all for it.
    :)

  6. Posted October 27, 2009 at 7:14 pm | Permalink

    This is a short one: requires go into the environment.rb.

    You can, but that’s not really the place it for stuff like that anymore. Since somewhere around Rails 2.1, custom code like that is meant to go into a file in config/initializers.

  7. remix
    Posted October 27, 2009 at 7:21 pm | Permalink

    thanks for a nice list! my 2 cents:

    - you can use something.present? instead of the ugly !something.blank? (present? was added in some recent Rails version)

    - i like “andand” gem, f.ex, not: if beast && beast.loose?, but:
    if beast.andand.loose? A little bit more DRY.

    - sometimes i find useful this construction:
    if (someobject. ..some ugly chain.. rescue false)

  8. Posted October 27, 2009 at 7:47 pm | Permalink

    @remix: #present? is a great idea, thanks! (use #any? if you want to check collections only).

    Re-andand and similar. I used to be a great fan of the andand (much better than #try imho) but in the end I feel that spelling it out wins:
    if @dude && @dude.surfs? vs. if @dude.andand.surfs?

    Both are ok though I think.

    My point in the article though, was that it really pays off if you can code in such as to be able to trust your data not to be nil ever (or put differently, in such a way so that Nils are exceptions and bugs to be fixed).

    @peter: I disagree. config/initializers is where I put *app* initialization code, not where I like my environment to be created. I see your point and using config/initializers works excellently. I for one don’t want to browse through 10 files to see what libs are required.= to run the app. I want *one* spot.

  9. Posted October 27, 2009 at 7:52 pm | Permalink

    Useful and hilarious. Lazy returns should be used 99% of the time, once in a while you need to make it explicit (def contains a few if statements, etc).

  10. chris
    Posted October 27, 2009 at 8:34 pm | Permalink

    @events.compact.sum(&:approved) can handle those nil’s

  11. Posted October 27, 2009 at 8:56 pm | Permalink

    @chris: nah, it’s not the @events that may contain Nils, it’s the attribute values that, allowed to be NULL in the DB, can come across as Nils instead of 0. :)

  12. Posted October 28, 2009 at 12:52 am | Permalink

    Great stuff, enjoyed reading it! How about @approved = @events.sum{|e| e.approved || 0}

  13. Posted October 28, 2009 at 3:44 am | Permalink

    Am I missing something, or is DO:
    Time.set_back(1.year.ago)

    The same as DON’T:
    Time.set_back(1.year.ago)

    Great article – I’ve found a few things I can clean up in my own code.

  14. Posted October 28, 2009 at 8:33 am | Permalink

    @mlambie: you’re right, typo. Thanks!

  15. Posted October 28, 2009 at 8:34 am | Permalink

    @michael: you’re right, that’s a great solution. :)

  16. Posted October 29, 2009 at 9:29 am | Permalink

    Regarding multiple return values, I suggest that “you communicate to the reader that that ‘retval’ variable only have two values” is perhaps optimistic: all that using #first and #last tells me is that I’m only interested in the two extremeities of a possibly aribitrarily long array! But as you say, it sucks. I think it’s an evolutionary thing: at some point we learn that we can return multiple values into a list of receivers (possible terminology fail there) and we feel much more Ruby-ish. Then – and I’m only just arriving there at the moment – we realise how we could be more intention-revealing. I’ve been having a lot more fun returning Structs or OpenStructs (for the lazy) of late.

  17. David Palm
    Posted October 29, 2009 at 10:32 am | Permalink

    @mike: you’re right of course and #first/#last is merely the first baby step to unsuckify the code. Often times when talking to inexperienced programmers I find that I have to be mighty careful not to step on egos and hurt peoples’ feelings. In those cases it’s useful to convince them of small changes and then come back the week after suggesting a helper method or two, and in the end help them see how refacotoring the whole thing not to need multiple returns at all is the way to go…

  18. Posted November 1, 2009 at 11:54 pm | Permalink

    Amazing list, thanks :)

  19. Posted November 4, 2009 at 4:57 am | Permalink

    you forgot the most elegant way to open the singleton class:

    class C
    class << C
    def singleton_method() end
    end
    end

    i personally always add this method

    def singleton_class(&block)
    @singleton_class ||= (
    class << self
    self
    end
    )
    block ? @singleton_class.module_eval(&block) : @singleton_class
    end

    to pretty much every ruby project. it allows for

    class C
    singleton_class do
    def singleton_method() end
    end
    end

    and also

    a = Array.new
    a.singleton_class.module_eval{ alias_method ‘length’, ’size’ }

    really very useful.
    end

  20. David Palm
    Posted November 4, 2009 at 10:17 am | Permalink

    @ara: how is

    class B
    class << B
    def beefer() end
    end
    end

    …different from what I suggested:

    class B
    class << self
    def beefer() end
    end
    end

    I agree that having a reference to the metaclass around is very handy and the ’singleton_method(&blk)’ is neat, but the beauty of it becomes apparent only when you begin to grasp how the whole class/metaclass machinery fits together. I believe many programmers don’t (yet!) and I often meet resistance at the “class << self” part. There is so much bad Ruby code out there right now that need the basics taken care of first that I’m hesitant rising the level further…

    :/

  21. andresgutgon
    Posted November 4, 2009 at 6:10 pm | Permalink

    thanks :)

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">