We’ve got a lot of classes following this general command pattern:
class SomeCommand
import ['subcommand_a', 'subcommand_b']
def call(args)
dependency_a.(...)
# ... processing specific to this command ...
dependency_b.(...)
# ...
end
end
There are a lot of things I like about this pattern. It’s easy to test with dependency injection, I can re-use the subcommands elsewhere cleanly, and because there’s no per-call state in the object, dry-system can (could?) memoise and re-use it.
But sometimes subcommand_a
and subcommand_b
will both call the same expensive operation (e.g. a remote API request). Ideally I’d like to run this once, and use the result in both places.
I could add an argument, like so:
def call(id, args)
cached = expensive_operation(id)
dependency_a.(..., cached)
# ...
dependency_b.(..., cached)
# ...
end
But if there’s a lot of existing arguments, this gets quite verbose. It also breaks abstraction: if A calls B, B calls C, and C’s implementation changes to need expensive_operation
, all of them need extra parameters.
I’ve also considered a full-fledged cache in the expensive_operation
code, but that raises the spectre of cache expiry. Right now I only keep the expensive data for one call so I haven’t had to worry about that.
How have other people handled this situation? Is there some principle or tool I’m missing that would help?