DEV Community

Junko T.
Junko T.

Posted on • Edited on

Refactoring checklist for beautiful Ruby code

checklist
You should never underestimate the importance of refactoring. If you're new to Ruby, you might be writing longer or more complex code than it should be without knowing how to use Ruby's convenient syntax. Since I learned basic Ruby at a coding bootcamp, I have been trying to learn from the code of experienced developers and realized that my code was much more verbose and thus confusing. In this article, I will introduce some techniques I came across to make Ruby code more readable, less expensive, and easy to change.

Conditional expressions

1. Use unless

This might depend on your preference.

# Bad
user.destroy if !user.active?

# Good
user.destroy unless user.active?
Enter fullscreen mode Exit fullscreen mode

2. Ternary operator ?:

# Bad
if score > 8
  result = "Pass"
else
  result = "Fail"
end

# Good
result = score > 8 ? "Pass" : "Fail" 
Enter fullscreen mode Exit fullscreen mode

3. Avoid == true, == false, and == nil

# Bad
if foo == true
  # something
end

# Good
if foo
  # something
end
Enter fullscreen mode Exit fullscreen mode
# Bad
if bar == false
  # something
end

# Good
if !bar
  # something
end
# or
unless bar
  # something
end
Enter fullscreen mode Exit fullscreen mode
# Bad
if baz == nil
  # something
end

# Good
if !baz
  # something
end
# or
unless baz
  # something
end
Enter fullscreen mode Exit fullscreen mode

Or, if you need to check if the value is specifically nil and not any other falsey value, this might be a better option:

# Good
if baz.nil?
  # something
end
Enter fullscreen mode Exit fullscreen mode

4. One-line if statement

# Bad
if num > 5
  puts "#{num} is greater than 5"
end

# Good
puts "#{num} is greater than 5" if num > 5
Enter fullscreen mode Exit fullscreen mode

5. Safe navigation operator &. (after Ruby 2.3.0)

The safe navigation operator &. allows skipping method call when the receiver is nil.

In the example below, if book.author or book.author.name returns nil, you need to check that to avoid NoMethodError exception.

# Bad
if book.author
  if book.author.name
    puts "#{book.title} was written by #{book.author.name}"
  end
end
Enter fullscreen mode Exit fullscreen mode

If you use the safe navigation operator, this can be achieved with fewer lines of code.

# Good
if book.author&.name
  puts "#{book.title} was written by #{book.author.name}"
end
Enter fullscreen mode Exit fullscreen mode

6. Use ||= for conditional initialization

# Bad
book = Book.new if book.nil?

# Good
book ||= Book.new
Enter fullscreen mode Exit fullscreen mode

Array

7. Use %w() or %i() when create an array (Percent strings)

I would say using percent strings is a better way because it will prevent you from forgetting quotation mark or colon and making errors.

# Bad
genres = [ "fantasy", "adventure", "mystery", "romance" ]

# Good
# String
genres = %w(fantasy adventure mystery romance)
# =>[ "fantasy", "adventure", "mystery", "romance" ]

# Symbol
genres = %i(fantasy adventure mystery romance)
# =>[ :fantasy, :adventure, :mystery, :romance ]
Enter fullscreen mode Exit fullscreen mode

8. Use &(ampersand) operator when iterate over an array

# Bad
titles = books.map { |book| book.title }

# Good
titles = books.map(&:title)
Enter fullscreen mode Exit fullscreen mode

For more details, here is my blog post about iteration and & operator


9. Use .last method to get the last element of an array

genres = [ :fantasy, :adventure, :mystery, :romance ]

# Bad
genres[genres.length - 1] # => :romance

# Good
genres.last # => :romance
Enter fullscreen mode Exit fullscreen mode

10. Destructuring assignment

Destructuring is a convenient way of extracting multiple values from data stored in objects like arrays.

quotient, remainder = 20.divmod(3) # => [6, 2]
quotient # => 6 
remainder # => 2 
Enter fullscreen mode Exit fullscreen mode

Others

11. Heredoc(Here documents)

If you are writing a large block of text, heredoc will help you make it cleaner and more readable.

# Bad
text = "Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit,\nsed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\nUt enim ad minim veniam,\nquis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."

# Good
text = <<-TEXT
Lorem ipsum dolor sit amet,
consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
TEXT
Enter fullscreen mode Exit fullscreen mode

Hope you find this article helpful and please leave comments if you have any suggestions to add!

Top comments (5)

Collapse
 
marcelolipienski profile image
Marcelo Lipienski

Congratz! These are really helpful tips. I hope you don't mind me sharing a few more :)

The second tip features an example that realistically would be better solved by introducing a Value Object, but it is still a good example on how to clean up your code by replacing simple if/else with ternary operator.

To learn more about Value Objects, you can check out this article.

For the ninth tip, personally I would also drop the usage of [-1] syntax.
Imagine you're code pairing and you're telling your partner that they should pick the last element.

You see? It's easier to read through a code that is written kind of the way we are used to speak. So elements.last reads much better than elements[-1].

Collapse
 
junko911 profile image
Junko T.

Hi Marcelo, thank you so much for your suggestions!

I didn't know about Value Objects. This article is really helpful.

Also, I was actually thinking about dropping [-1] syntax from the ninth item. I decided to keep it as another option but your explanation really makes sense. I might be going to update my article.

Thank you, again!

Collapse
 
dharshann profile image
Dharshan Bharathuru

with curiosity.
Did you missed to take a look at Rubocop gem!?

Collapse
 
junko911 profile image
Junko T.

Thank you for your comment, Dharshan! Could you point which code snippets you are referring to?

Collapse
 
dharshann profile image
Dharshan Bharathuru

Junko Tahara. Most of the code snippets you mentioned are mentioned in ruby style guides(github.com/rubocop-hq/ruby-style-g...). And rubocop gem automatically points out these code smells and have the option to auto correct it safely(github.com/rubocop-hq/rubocop).