Imagine this case:
class Account < ActiveRecord::Base
def transfer(other, quantity)
tries = 0
begin
tries += 1
transaction do
self.quantity -= quantity
other.quantity += quantity
self.save!
other.save!
end
rescue
retry if tries < 5
raise
end
end
end
The method has lots of "noise", it is difficult to see the business rules with all the control flow on the way.
The idea is to extract most of the things that are not really business rules to separated classes, and then decorate the method with the selected extractions.
For instance, let's extract the "Transaction" part of the method:
class Transactional < Annotation
def call(method, *args, &block)
ActiveRecord::Base.transaction do
method.call(*args, &block)
end
end
end
Then we can decorate the method like this (note that the Retry
decorator is already defined by the gem):
class Account < ActiveRecord::Base
extend Annotations
+Retry.new(5)
+Transactional
def transfer(other, quantity)
self.quantity -= quantity
other.quantity += quantity
self.save!
other.save!
end
end
Só mencionando o @pedroteixeira, com quem falei sobre isso recentemente.