Ruby Best Practices - Method Arguments

Ruby Best Practices - Method Arguments

To write readable and maintainable code, follow a few simple rules about argument ordering.

Tip 1: Optional arguments go last

When a method takes several arguments, and some of them have default values, make sure to put the optional ones at the end.

Take this method definition:

def foo(a, b = "val_b", c)
  # some code...
end

Looks fine at first glance. But in practice, it’s impossible to call this method with values for a and c without also specifying b. You end up writing:

foo("val_a", "val_b", "val_c")

…which defeats the purpose of setting a default for b if you're forced to specify it every time. ¯_(ツ)_/¯

Solution: move optional arguments to the end

def foo(a, c, b = "val_b")
  # some code...
end

Now you can call:

foo("val_a", "val_c")

No problem 😎.

Tip 2: Use keyword arguments (aka kwargs)

Tip 1 only gets you so far. What if you have multiple optional arguments and want to override just the last one? You’d still need to specify all the previous ones.

For example:

def foo(a, b, c = "val_c", d = "val_d", e = "val_e")
  # some code...
end

Want to change only e? Too bad — you still have to write:

foo("val_a", "val_b", "val_c", "val_d", "my_val_e")

Now imagine this in a large codebase:

foo(user.id, "DONE", true, false, 1, "always", true, post.id)

And you're left thinking: "Wait, what’s that false again? What does the 1 do? Why 'always'?"

Not ideal, especially under pressure in a production bug fix.

Solution: switch to keyword arguments when you hit 2+ optional params

Benefits:

  • Argument order doesn't matter anymore
  • You can ignore defaults entirely

The method now becomes:

def foo(a, b, c: "val_c", d: "val_d", e: "val_e")
  # some code...
end

To change only e, you write:

foo("val_a", "val_b", e: "my_val_e")
💡 BONUS: keyword args make your calls self-documenting. You don’t need to check the method signature to remember what each value means.

Ninja-level tip — the clean coder’s take:

If your method takes more than 1 argument, make everything after the first a keyword argument. Always.

Example:

def send_message_to(recipient, confirm: true, bcc: "[email protected]", cc: "[email protected]")
  # ruby code
end

Here, the first argument is obvious thanks to the method name: you're sending a message to someone.

Called without options:

send_message_to("[email protected]")

Clear and concise.

Compare a non-keyword version:

send_message("[email protected]", false, "[email protected]", "[email protected]")

…with the keyword version:

send_message_to("[email protected]", bcc: "[email protected]", confirm: false)
And by the way, naming matters. Ruby reads like English — write code you can speak out loud.

If you adopt these habits, future you will thank you when you revisit the code to debug or tack on yet another parameter.

Mastodon