I have a question in regards to the Putting your events on a diet article. My question assumes a web/mobile UI consuming a web api backend that uses viewmodel composition to compose read models from multiple service DBs, and also to send commands to each service. See https://github.com/ServiceComposer/ServiceComposer.AspNetCore to understand what I use.
Although the article doesn’t go into the detail of order total charging, in my opinion, the Sales service is responsible for calculating order charge totals (subtotal, fees, taxes = total). By calculated I mean Sales is responsible for ensuring calculation happens but not necessarily what calculations are done, i.e. a Shipping service might want to add a fee so it would supply a component that would implement ICalculateSalesFees (owned and published by Sales).
When it comes to the Billing service authorizing a payment WHEN an order is placed it will need to have the currency and total at hand. I see 3 options:
-
Sales publishes OrderPlaced with OrderId, Currency and Total. Billing has an AuthorizePolicy saga that reacts to the event and continues with its authorization process.
-
Sales publishes OrderPlaced with OrderId only. Billing reacts to the event and a handler makes use of a Billing-owned ICalculateOrderCharges which surfaces a method to obtain OrderCharges (total and currency) for a given OrderId. Sales must implement this interface and publish (via nuget say) so that Billing can consume as required for deployment. The implementation could be direct to sales db, web api, rpc, whatever, Billing doesn’t care nor should it.
-
Sales publishes OrderPlaced with OrderId only. Sales has an IChargeCustomer that it consumes in an OrderPlacedHandler and passes OrderCharges to the interface’s ChargeCustomer method. Billing implements IChargeCustomer as a component (again published to nuget) and Sales consumes component as the implementation of its IChargeCustomer. The implementation sends a ChargeCustomer command (owned by Billing) with the OrderCharges data.
No 1. feels wrong, as per the reasons detailed in the article mentioned.
No 2. means both services are only coupled by the need for Billing to be deployed with a registered (in DI) SalesOrderChargesCalculator component.
No 3. means both services are only coupled by the need for Sales to be deployed with a registered (in DI) BillingChargeCustomerProvider component.
Are there any benefits to using no 2. over no 3, or vice-versa. Or perhaps I’m missing some other approach to the problem?