-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Limit use of conditional modifiers to short, simple cases. #738
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd be interested in finding a standardized layout, form, or pattern (informal definition) for guideline pages. Something akin to Pattern Forms. Though I acknowledge that we aren't generating formal patterns here, but more sharing best practices, maxims, preferences, conventions, heuristics, lessons learned, etc. Still, I would argue that creating a structural consistency across guideline pages would facilitate the readability, scanability, searchability, navigability, and organization of the pages. This would encourage internal consistency across a diverse set of guidelines. I'm not sure what this form would look like (we might need to build out several pages first and discover the common pattern). Perhaps something like: problem, solution, tradeoffs (indications/contraindications; pros/cons; advantages/disadvantages). I could also see us using a variant the portland form as well...
It enacts just enough structure to assist with pages being consistent while still being ad hoc and flexible. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
# Limit use of conditional modifiers to short, simple cases | ||
|
||
Conditional modifiers (i.e., `if` or `unless` at the end of a line) can be | ||
surprising when they appear on long or complex lines. The reader might not see | ||
them while scanning the code. | ||
|
||
So, prefer to use them only for short, simple cases. For example: | ||
|
||
```ruby | ||
do_later if async? | ||
``` | ||
|
||
The example above can read more naturally than: | ||
|
||
```rb | ||
if async? | ||
do_later | ||
end | ||
``` | ||
|
||
## Complex conditions | ||
|
||
However, if the line is too long (around 80 characters) or complex (e.g., an | ||
`if` with multiple conditions like `if a && b`) prefer the multi-line form: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is especially true with |
||
|
||
```ruby | ||
# Avoid | ||
block_access! if signed_in? && !current_user.active? | ||
MatheusRich marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
# Prefer | ||
if signed_in? && !current_user.active? | ||
block_access! | ||
end | ||
``` | ||
|
||
There might be cases where the conditional modifier work well with multiple | ||
conditions, so use your best judgment. | ||
|
||
## An opportunity to refactor | ||
|
||
If the conditions are related, consider extracting a method that groups them. | ||
This might allow you to use the conditional modifier form again. | ||
|
||
```ruby | ||
def inactive_user? | ||
signed_in? && !current_user.active? | ||
end | ||
|
||
block_access! if inactive_user? | ||
``` | ||
Comment on lines
+39
to
+50
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems to be moving towards the Triangle of Separation style of code |
||
|
||
## Conditional modifiers feel informal | ||
|
||
The modifier form of conditionals can feel more casual than the multi-line form. | ||
Conversely, the multi-line form _draws attention_ to the conditional and the | ||
code that follows it. Use this to your advantage when you want to emphasize the | ||
conditional and the code that follows it. | ||
|
||
```rb | ||
# Avoid | ||
def action | ||
return destroy_all if really? | ||
|
||
do_nothing | ||
end | ||
|
||
# Prefer | ||
def action | ||
if really? | ||
destroy_all | ||
else | ||
do_nothing | ||
end | ||
end | ||
``` | ||
|
||
You can also refactor the code so the less destructive action uses a conditional | ||
modifier, which pairs well with the informal feel of the modifier form: | ||
|
||
```rb | ||
def action | ||
return do_nothing if chill? | ||
|
||
destroy_all | ||
end | ||
``` | ||
Comment on lines
+52
to
+86
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this section is really about what is the "main action" of the method, and what is the edge-case blocked by the guard close. It seems less about formality and more about verifying invariants? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd say both conditions can be equally valid, which is highlighted in the if/else example? The writer has the power to bring focus to particular branch by not using the guard. Maybe that's what I was trying to communicate with formal/informal. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: I think the file name should match the link label