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)