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?
2. Ternary operator ?:
# Bad
if score > 8
result = "Pass"
else
result = "Fail"
end
# Good
result = score > 8 ? "Pass" : "Fail"
3. Avoid == true
, == false
, and == nil
# Bad
if foo == true
# something
end
# Good
if foo
# something
end
# Bad
if bar == false
# something
end
# Good
if !bar
# something
end
# or
unless bar
# something
end
# Bad
if baz == nil
# something
end
# Good
if !baz
# something
end
# or
unless baz
# something
end
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
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
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
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
6. Use ||=
for conditional initialization
# Bad
book = Book.new if book.nil?
# Good
book ||= Book.new
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 ]
8. Use &
(ampersand) operator when iterate over an array
# Bad
titles = books.map { |book| book.title }
# Good
titles = books.map(&:title)
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
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
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
Hope you find this article helpful and please leave comments if you have any suggestions to add!
Top comments (5)
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 thanelements[-1]
.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!
with curiosity.
Did you missed to take a look at Rubocop gem!?
Thank you for your comment, Dharshan! Could you point which code snippets you are referring to?
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).