With zero dependencies, a minimal API, and virtually limitless configuration options, S̶o̶l̶i̶d̶ Strong Service1 is the gem you should use when you implement service objects in Ruby. It's compatible with Rails and all other Ruby frameworks — or no framework at all!
After hours of furious online debate, you've decided that you want to use service objects, AKA the Command pattern, AKA classes that do things of use in your Ruby app. Great! But how should you implement them? There are dozens of libraries, all claiming to do a slightly different variation of the same thing.
Some might argue that a PORO is sufficient, but these people should be dismissed as purists; most of us warm-blooded Ruby engineers know that adding dependencies to our projects is the only way to make them better and deliver actual value.
Strong Service is what you need. If you're not convinced by the claims above, consider the name: it's Strong. It may or may not be related to the other gems in the popular S̶o̶l̶i̶d̶ Strong family (this made more sense before the rename). And, at the time of writing, it was made recently. Everyone knows that new things are better than old things, right? Exactly. You can trust Strong Service to push the bar on what is possible in the vibrant service object community, sprinkling a dash of that je ne sais quoi that imitators can't capture.
bundle add strong_service
Alternatively, if you're still on a Pentium 4 and/or have no idea what you're doing, you can just use:
gem install strong_service
Standard usage is simple: just subclass StrongService
and implement your call
method:
class CoffeeService < StrongService
def call
puts "Brewing coffee!"
end
end
Then, to run your service, just execute call
:
CoffeeService.new.call # => "Brewing coffee!"
If that weren't enough, services can even call other services and they are guaranteed to run in order!:
class CoffeeService < StrongService
def call
puts "Brewing coffee!"
end
end
class ToastService < StrongService
def call
puts "Toasting bread!"
end
end
class BreakfastService < StrongService
def call
CoffeeService.new.call
ToastService.new.call
end
end
BreakfastService.new.call # => "Brewing coffee!"
# => "Toasting bread!"
You can configure StrongService to have access to instance variables on the service by defining parameters on a special #initialize
method:
class GreeterService < StrongService
def initialize(name)
@name = name
end
def call
puts "Hello, #{@name}!"
end
end
Then, pass arguments into the new
method:
GreeterService.new("Jamie").call # => "Hello, Jamie!"
StrongService includes an advanced DSL which allows you to configure any aspect of the call
method — even going as far as to rename it.
class MyService < StrongService
def execute
puts "This service is STRONG."
end
end
MyService.new.execute # => "This service is STRONG."
Strong Service's powerful DSL includes an experimental feature, which allows you to inherit the full library of functionality from Strong Service without formally subclassing it. Example:
class CoffeeService
def call
puts "Brewing coffee!"
end
end
This is equivalent to the previous example defining CoffeeService
, but without the explicit subclassing of StrongService
.
How is this possible? I could explain, but you probably wouldn't understand. Just 🌈 embrace 🪄 the magic 💫.
Subclassing StrongService
gives you access to many useful methods, which you can read about more at the documentation.
In order to fund development, I am now offering a premium version of Strong Service alongside consulting services. Contact me for more details.
As of 1.0.0, development on Strong Service is finished. This is because it is perfect software with zero bugs. I know that this is a difficult claim to make, and that others claim that all software has bugs, but this software does not. It's done. End of discussion.
As such, development instructions are completely unnecessary, because no one will ever need to develop on top of this.
See the development section above: there is no need to contribute, because the gem is already perfect. Your contributions would be superfluous and only smudge the proverbial windows of this masterwork.
The chief visionary, architect, and Scrum Master behind Strong Service is Jamie Schembri. You can contact him on Bluesky or read more of his nonsense on his blog.
This open-source version is available under the the WTFPL.
Footnotes
-
This gem was originally called Solid Service, but Rubygems rejected that because of security or something :-( ↩