A little over one year ago I jumped ship to a new role at a startup company which required me to get familiar with a new tech-stack. The biggest hurdle by-far was coming to grips with Ruby and Rails, especially given that I had limited experience with anything similar.

The purpose of this post, however, is not to recount each hurdle of the last 12 months but rather to list off a few of my favourite things about Ruby and/or Rails (so far).

Disclaimer: For the purpose of this blog post, I am combining Ruby & Rails as the same thing without differentiating whether a feature belongs to one or the other. (I imagine the enthusiasts will now sharpen their pitchforks đŸ‘żđŸ”„)


1. Date & Time syntax

I think this feature is very deserving of the top spot in this list. Take the scenario you need to set some kind of expiration timestamp (say 10 minutes) on an object in your application. My Java foundation has got me thinking along the lines of:

  • get the current time,
  • convert 10 minutes into milliseconds,
  • find a method on the Date/Time object that allows me to add some milliseconds.

The following Rails syntax is a lot nicer:

expiration = Time.now + 10.minutes  # Wow!

# But wait, there's more!

expiration_better = 10.minutes.from_now # đŸ˜±

The syntax is extremely flexible. Feel free to go absolutely nuts

2.hours.ago
10.years.from_now
3.months.ago

financial_quarter_started = 2.weeks.ago.at_beginning_of_day
team_lunch = 5.days.from_now.at_noon

international_meeting = 3.hours.from.now.in_time_zone("London")
=> Tue, 28 Dec 2021 01:38:45.299432000 GMT +00:00  # Perhaps not then...

2. Syntax abbreviations

They’re a major headache when you’re a Ruby n00b and nothing makes sense, but quite pleasant once you’re comfortable and very common-place in the Ruby community.

Implicit Returns

Who needs that pesky return keyword anyway? The value of the last line of code in a block always gets returned automatically. Prefixing return is optional.

Most of the time I don’t use it. But proceed with caution! It’s still necessary if you wish to return from any line other than the last, E.g.

def lottery_won?
  return false unless lottery_ticket_purchased? # <--- explicit return

  ticket.has_winning_numbers?                   # <--- implicit return
end

Parenthesis Who?

If your method call does not specify any arguments, then you don’t need to specify any parenthesis.

speakers.set_volume(100)   # 👍

speakers.increase_volume() # 👎
speakers.increase_volume   # 👍

NB: Even if you are specifying arguments, parenthesis are still optional. Proceed with caution as it can harm readability, especially with multiple arguments


speakers.set_volume 100    # Valid (albeit controversial) syntax...

3. Safe Navigation

When one chooses to embrace a less-strictly typed language like Ruby, you’d best get comfortable with nil. You’re going to encounter it a lot.

Nil Everywhere

Sometimes the natural reaction to this danger is to write abundently cautious code like:

if currently_logged_in.present? && 
   currently_logged_in.user.present? &&
   currently_logged_in.user.details.present? &&
   currently_logged_in.user.details.address.present?
  postcode = currently_logged_in.user.details.address.postcode
end

The above should avoid an exception being raised if one of the prior method calls returns nil (NoMethodError: undefined method for nil:NilClass), but the postcode itself may still be nil.

The safe-navigation operator allows us to chain these method calls together safely, without explicitly checking each method call to be non-nil. If it encounters a nil value along the chain, execution of the statement does not proceed and nil is returned.

postcode = currently_logged_in&.user&.details&.address&.postcode

If the postcode exists, we get the value. If any of the user, details, address or postcode do not exist we get nil without an error being raised.

As always, with great power comes great responsibility. Only use this when beneficial; Use in situations where a nil return is not possible is a code smell đŸ„Ž.


4. Natural Language Syntax (“syntactic sugar” 💅)

Despite our best efforts, sometimes computers and humans just don’t think the same way. Often the fastest path to solving a problem using code is to think like a computer, but this is easier said than done. Rails makes some strides to allow for more human-like language in code. One such example is shown below:

# This, to me, requires the developer to think like a computer
if oven.include?("roast_vegetables") && oven.include?("roast_chicken")
  puts "Dinner is nearly ready!"
end

# Rails provides some mechanisms to achieve the same functionality 
# in more natural human language
if "roast_vegetables".in?(oven) && "roast_chicken".in?(oven)
  puts "Dinner is nearly ready!
end

Sometimes (context-dependent) one way is simply more readable than the other; Rails gives you the freedom of choice đŸ€—

This difference in readability also extends beyond this individual line of code. Within the context of your entire algorithm, should the developer be more focussed on the fact that the oven contains food, or the fact that food is in the oven?

The same freedoms of expression are offered in English (and many other spoken languages), e.g.

Some maniac in a fast car passed me

Some maniac passed me in a fast car

What’s more important for the reader to understand the rest of your story / algorithm?

  • That the maniac was in a fast car, or
  • That the maniac passed you ?

Thinking



On that philiosophical note, stay tuned for Part 2 🔜