It’s a quiet Sunday morning, and I’m tinkering with my side project. As I look at the service object I’m writing, I catch myself seeing the same pattern… again.
# This is what I keep doing.
class UserService
def self.create(name:, email:, permissions:)
new(name: name, email: email, permissions: permissions).save
end
def initialize(name:, email:, permissions:)
@name = name
@email = email
@permissions = permissions
end
def save
puts "Saving user #{@name}..."
end
end
See that self.create
method? All I’m really doing is grabbing arguments and passing them straight to new
. It works, but it feels clunky. Every time I add a new argument to initialize
, say an age
parameter, I have to update it in two places. It’s a small hassle today, but tomorrow it’s a classic recipe for bugs.
Somewhere along the way I read about Ruby’s argument forwarding syntax (...
). I need to burn this into my brain because it makes life so much easier.
Here’s the rewrite for my future self:
# This is how I should be doing it.
class UserService
def self.create(...)
new(...).save # <-- So much better
end
def initialize(name:, email:, permissions:)
@name = name
@email = email
@permissions = permissions
end
def save
puts "Saving user #{@name}..."
end
end
The self.create(...)
says, “Grab whatever comes in,” and new(...)
replies, “Pass it all along.” Clean. Simple. Done.
Why this is better
-
It’s DRY. No more repeating
name:, email:, permissions:
twice. Less typing, less clutter. -
It’s resilient. If I add
age:
toinitialize
,self.create
doesn’t need a single change. Argument forwarding takes care of it automatically. -
It covers everything. Positional args, keyword args, even blocks. The
...
operator forwards it all.
And if I ever need to intercept just one argument while passing along the rest, say for logging, that’s easy too:
def self.create(name:, ...) # grab `name`, forward the rest
puts "About to create a user named #{name}..."
new(name: name, ...)
end
Memo to self
Use ...
for forwarding arguments. It keeps code cleaner, avoids duplication, and saves future-me from unnecessary headaches.
Top comments (0)