The three types of methods in Ruby
Tags: ruby, rails
Published: 2024-02-16 16:41:17

---
title: The three types of methods in Ruby
published: true
description: Naming is hard™
tags: ruby,rails
cover_image: https://i.postimg.cc/MKrs10mV/ainur-iman-FEu-Is-Xxhz-Q0-unsplash.jpg
# published_at: 2024-02-16 15:23 +0000
---

In this short post I will look at some patterns in Ruby methods and their naming conventions.

The most prominent pattern is delineation of methods that produce a value and no side-effects from methods with side-effects. I achieve this by only using verbs in side-effect-producing method names, whereas methods with only return value get adjectives and nouns.

## Return-value-only

Let's have a look:

```
def get_name
def name

def produce_red_cube
def red_cube

def normalize_params(params)
def normal_params(params) # or normalized_params

def make_request
def response # sidestep the process by which the response is obtained altogether

def render_view
def content # here as well, focus on the result
```

As you can see, it's irrelevent *how* the value is obtained, no need to mention it in the method name. Otherwise we'd end up with `def obtain_<thing>_by_deep_coding_magic` methods all over the place.

Naming things this way has the functional side-effect of aligning initialization with getter, making memoization straightforward. Everything becomes self-ensuring and safer.

```rb
# before
attr_reader :company
 
def load_company
  @company = Company.find(params[:company_id])
  authorize @company, :show
end

def do_something_important
  load_company # important that loading occurs before first call to #company, brittle
  company.something
end

# after
def company
  @company ||= Company.find(params[:company_id]).tap { |c| authorize c, :show } 
end

def do_something_important  
  company.something
end
```

You may have noticed that this also makes before_action filters unnecessary. 😼

## Methods with side-effects

Naming is simple - start with a descriptive verb, followed by the signifying noun.

```rb
def enqueue_job
def process_upload
def reorder_toys! # throw in a bang to really show things will change
```

These come in two flavours - where the return value is wholly unimportant, indeed, having one would be confusing, and where there is a return value, usually an "outcome" object.

For methods without interesting return values I recommend explicitly returning `nil` to signify this. It's also useful to prevent leakage of unintended return values, consider:

```rb
# bad
def close_old_cases
  cases.each do |case|
    case.close! if case.old?
  end
end #=> cases

# good
def close_old_cases(cases)
  cases.each do |case|
    case.close! if case.old?
  end

  nil
end #=> nil
``` 

If a method has both significant side-effects (writing to DB, filesystem, etc.) *and* has an interesting return value, I recommend being explicit about this with a YARD-style comment at least:

```rb
# @return [ConversionReport] # convert's an accounts currencies and returns a report object with details
def convert_currencies!(from, to)
  ...
  ConversionReport.new(at: Time.current, from : from, to: to)
end

convert_currencies!.success? #=> true
```

Naming things can be hard, especially for non-native speakers. I usually try to use expressive and precise words - all those `process` and `calculate` get a bit repetitive :)

Another pattern I like is using Ruby's special `call` method to push the naming into the class. There are many approaches to naming when doing this since there can be several considerations (for example, leading with context/concept to get alphabetical grouping etc.), but I prefer noun-ification with an emphasis on professions, for example:

```rb
def process_upload
UploadReviewer.call

def manage_record_lock
Receptionist.call

def calculate_pay
PayrollClerk.call
```

Photo by <a href="https://unsplash.com/@mynameisiknow?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Ainur Iman</a> on <a href="https://unsplash.com/photos/a-row-of-white-cups-sitting-on-top-of-a-counter-FEuIsXxhzQ0?utm_content=creditCopyText&utm_medium=referral&utm_source=unsplash">Unsplash</a>