UseCasePattern
A module that helps you to implement the Use Case design pattern.
This pattern is widely used by the teams at Abletech. We were first introduced to this pattern by Shevaun Coker at RubyConf AU 2015 in Melbourne, Australia. You can read more about this pattern in her blog post A Case for Use Cases, and also in the video of the presentation that she gave.
Installation
Add this line to your application's Gemfile:
gem 'use_case_pattern'
And then execute:
$ bundle
Or install it yourself as:
$ gem install use_case_pattern
Basic Usage
When you follow the use case design pattern, you normally define a class with a constructor, and a perform method. You should include the UseCasePattern
module. Here is a simple example:
class NumberMultiplier
include UseCasePattern
attr_reader :product
validates :number1, :number2, presence: true
def initialize(number1, number2)
@number1 = number1
@number2 = number2
end
def perform
@product = @number1 * @number2
end
end
You could call this simple example from a Rails Controller, or anywhere else really. Here is an example:
def multiply
multiplier = NumberMultiplier.perform(params[:number1], params[:number2])
if multiplier.success?
@result = multiplier.result
else
redirect_to :new, notice: multiplier.errors.full_messages
end
end
Normal workflow
This section defines the expected approach to implementing a class which uses the use case pattern.
Initialisation
You would normally define a constructor for your use case. The constructor should store any supplied parameters as instance variables. You shouldn't perform any processing or business logic in the constructor.
The constructor is called with the parameters that are passed to the perform
class method. For example, using the NumberMultiplier defined above, making a call to NumberMultiplier.perform(1, 2)
will result in the initialiser being called as initialize(1, 2)
.
Validation
You should use ActiveModel validators to check that supplied parameters and any other dependencies are correct. You can also write custom validation methods using the validate method. Following the standard validation approach, you should add to the errors
collection if validation fails.
Execution
The perform
method is where the execution of the use case should happen. In this method, you should perform all of the processing and business logic of your use case. Results of the execution should be stored as instance variables.
Sometimes during the execution of the perform
method, an error may occur. You could choose to add to the errors collection or alternatively raise an exception. You should only add to the errors collection if you expect the caller to handle the error.
You should note that the value returned from the perform method is discarded. This encourages the caller to make use of the public accessor methods to access the results of the operation.
The alternative perform!
method
The perform!
method works in a similar manner to the ActiveRecord save!
method. Should a validation or other error occur, an exception is raised. This method should be used in scenarios where the caller does not expect any errors to occur. One example of this is when the parameters have been pre-checked by a controller class or similar.
Post-execution
During the perform
method, you should have stored the results as instance variables. You would normally make these publicly accessible using a attr_reader
method declaration. You should avoid declaring public methods that further process the output of the perform
method.
Checking for errors
The caller can check the success or failure of the use case by calling the success?
and failure?
helper methods. If the use case has had a failure, the errors will be available on the standard errors
collection.
Development
After checking out the repo, run bin/setup
to install dependencies. Then, run rake spec
to run the tests. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and tags, and push the .gem
file to rubygems.org.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/abletech/use_case_pattern.