Majesties! Cease groveling before your codebase, and issue your applications Decrees! A Decree is a pattern designed to aid developers in extracting processes to places where they can be usefully reused.
A class that implements the decree pattern has several benefits: it can easily be replaced as the API surface area is a single method; it can compose other Decrees; it can easily be faked for development; and it can easily be mocked for testing. The Decree pattern helps to both isolate and centralize the core logic of your app.
In Rails apps, service objects are pretty much any object that’s not a controller or model. A service object can follow the Decree pattern by having names that tell our code what to do (it’s imperative to do this) and a single class-level entry point called .(...)
.
A few examples of imperative names are CreateObject
, GenerateReport
, and PerformMentalGymastics
. Names like these, combined with the shorthand #call()
syntax, give us very nice ergonomics compared to other naming and calling conventions. GenerateReport.(params)
is much nicer to read than ReportGenerator.new(params).generate_report
.
In the method signature, ...
represents any set of arguments, keyword arguments, and a block. Each of those arguments are optional to define as part of the signature.
The Decree’s entry point method defined at the class level as def self.call(...)
. Thus, the code to execute a decree is DoSomething.(params)
. A Decree is useful for anything in the space between responding to a controller action and writing to the database. It is where the logic that is central to your system goes.
A simple example of a decree whose job is to create a new player being used from a Rails controller:
class PlayersController