What do you see as the pros and cons of using callbacks for domain logic? (I\'m talking in the context of Rails and/or Ruby projects.)
To start the discussion, I wanted
Avdi Grimm have some great examples in his book Object On Rails.
You will find here and here why he do not choose the callback option and how you can get rid of this simply by overriding the corresponding ActiveRecord method.
In your case you will end up with something like :
class Order < ActiveRecord::Base
def save(*)
normalize_card_number if paid_with_card?
super
end
private
def normalize_card_number
#do something and assign self.card_number = "XXX"
end
end
[UPDATE after your comment "this is still callback"]
When we are speaking of callbacks for domain logic, I understand ActiveRecord
callbacks, please correct me if you think the quote from Mongoid referer to something else, if there is a "callback design" somewhere I did not find it.
I think ActiveRecord
callbacks are, for the most (entire?) part nothing more than syntactic sugar you can rid of by my previous example.
First, I agree that this callbacks method hide the logic behind them : for someone who is not familiar with ActiveRecord
, he will have to learn it to understand the code, with the version above, it is easily understandable and testable.
Which could be worst with the ActiveRecord
callbacks his their "common usage" or the "decoupling feeling" they can produce. The callback version may seems nice at first but as you will add more callbacks, it will be more difficult to understand your code (in which order are they loaded, which one may stop the execution flow, etc...) and test it (your domain logic is coupled with ActiveRecord
persistence logic).
When I read my example below, I feel bad about this code, it's smell. I believe you probably do not end up with this code if you were doing TDD/BDD and, if you forget about ActiveRecord
, I think you would simply have written the card_number=
method. I hope this example is good enough to not directly choose the callback option and think about design first.
About the quote from MongoId I'm wondering why they advice to not use callback for domain logic but to use it to queueing background job. I think queueing background job could be part of the domain logic and may sometimes be better designed with something else than a callback (let's say an Observer).
Finally, there is some criticism about how ActiveRecord is used / implemented with Rail from an Object Oriented programming design point of view, this answer contain good information about it and you will find more easily. You may also want to check the datamapper design pattern / ruby implementation project which could be replacement (but how much better) for ActiveRecord and do not have his weakness.