Consider Sinatra application on Sinatra (or Rails is not important). I have 2 separated components: Payments and UserProfile. Each component is in its catalog:
payments
routes.rb
payment_entity.rb
payments_confirmation.rb
user_profile
user_profile_assigner.rb
Payments has route /api/payments/notification. The external payment system calls webhook to this route when the user make a payment. routes.rb - is simple entry point which receive requests from external world and call application service, in this case call PaymentsConfirmation.
# routes.rb
post '/api/payments/notification' do
PaymentsConfirmation.process(params[:user_id])
end
PaymentsConfirmation changes status of payment. Responsility of Payments module is processing payments. This module should not know about user privilegies.
# payments_confirmation.rb
class PaymentsConfirmation
def self.process(user_id)
# confirm payment
payment_model = PaymentModel.find_by(user_id: user_id)
payment_model.update_attributes(status: :PAID)
# assign premium to user
UserProfileAssigner.make_premium(user_id)
end
end
UserProfileAssigner assign premium flag to user
# user_profile_assigner.rb
class UserProfileAssigner
def self.make_premium(user)
assign_model = AssignModel.find_by(user_id: user.id)
assign_model.update_attributes(premium: true)
end
end
I'm concerned about the coupling of modules
I thought about several solution, but none of them seems to me quite optimal:
- Call UserProfileAssigner from routes.rb. I think that this will add to the routes extra responsibility.
- pass UserProfileAssigner to PaymentsConfirmation with dependency injection. Again, the PaymentsConfirmation should know only about self responsibility, but not that there is some module that has to do something else.
- PaymentsConfirmation should send some event to some EventBus (eg SUCCESS). UserProfileAssigner should subscribe to SUCCESS event, and process when SUCCESS will fired. This method seems to me unreasonably complex.
- I should create add-on component, which will called from route (eg ExternalPaymentNotificationProcessor). ExternalPaymentNotificationProcessor calls PaymentsConfirmation and UserProfileAssigner sequentially.
What is the best practices to reduce the modules coupling for similar cases?
Aucun commentaire:
Enregistrer un commentaire