Ruby Science
Introduce Explaining Variable
This refactoring allows you to break up a complex, hard-to-read statement by placing part of it in a local variable. The only difficult part is finding a good name for the variable.
Uses
- Improves legibility of code.
- Makes it easier to extract methods by breaking up long statements.
- Removes the need for extra comments.
Example
This line of code was deemed hard enough to understand that adding a comment was necessary:
# app/models/open_question.rb
def summary
# Text for each answer in order as a comma-separated string
.order(:created_at).pluck(:text).join(', ')
answersend
Adding an explaining variable makes the line easy to understand without requiring a comment:
# app/models/open_question.rb
def summary
= answers.order(:created_at).pluck(:text)
text_from_ordered_answers .join(', ')
text_from_ordered_answersend
You can follow up by using replace temp with query.
def summary
.join(', ')
text_from_ordered_answersend
private
def text_from_ordered_answers
.order(:created_at).pluck(:text)
answersend
This increases the overall size of the class and moves
text_from_ordered_answers
further away from
summary
, so you’ll want to be careful when doing this. The
most obvious reason to extract a method is to reuse the value of the
variable.
However, there’s another potential benefit: It changes the way developers read the code. Developers instinctively read code from the top down. Expressions based on variables place the details first, which means that developers will start with the details:
= answers.order(:created_at).pluck(:text) text_from_ordered_answers
And work their way down to the overall goal of a method:
.join(', ') text_from_ordered_answers
Note that you naturally focus first on the code necessary to find the array of texts and then progress to see what happens to those texts.
Once a method is extracted, the high-level concept comes first:
def summary
.join(', ')
text_from_ordered_answersend
And then you progress to the details:
def text_from_ordered_answers
.order(:created_at).pluck(:text)
answersend
You can use this technique of extracting methods to ensure that developers focus on what’s important first and only dive into the implementation details when necessary.
Next Steps
- Replace temp with query if you want to reuse the expression or revert to the order in which a developer naturally reads the method.
- Check the affected expression to make sure that it’s easy to read. If it’s still too dense, try extracting more variables or methods.
- Check the extracted variable or method for feature envy.
Ruby Science
The canonical reference for writing fantastic Rails applications from authors who have created hundreds.