Thursday, June 12, 2008

Outsourcing Business Capabilities (continued...)

Continuing my recent post on outsourcing business capabilities to third parties, I wanted to extend the example to include a Shipping service and a Billing service which outsources its billing function to PayPal.

If you recall from last time, our online sales channel (part of the Sales service) was outsourced to eBay. When a customer places an order on eBay, eBay needs to inform us of the order details. We achieve this by setting up a local Web service which is invoked by eBay whenever an order is placed.

eBay however does not guarantee delivery of this notification message. They do however provide a Web service we can interrogate in order to retrieve order details on demand. This involves a synchronous request-reply message exchange over an HTTP transport.

PayPal also provides a notification mechanism whereby PayPal invokes a Web service hosted by our organisation. A notification is sent whenever a payment is processed. Unlike eBay, PayPal does guarantee notification delivery.

Unfortunately, HTTP is not a guaranteed message delivery transport. Connection failures may occur. As a result, PayPal will keep sending the notification message until it receives confirmation that the message was successfully processed in the response from our Web service operation.

If our response message back to PayPal is lost somewhere along the way, we'll end up receiving duplicate notification messages. So we need to make sure that the service logic that handles the notification is idempotent.

We want to abstract away the details of these Web service interactions from other services in our enterprise. As far as the online sales channel is concerned, this is achieved by way of publishing a NewSaleNotification message within our organisation when we receive a sale notification from eBay via our Web service. The Sales service also stores a record of the sale in its database.

The eBay notification however is not guaranteed to arrive, so we're going to have to find a way of dealing with that. Let's deal with that later though and look to the Billing service. PayPal sends us a notification which I'll assume will contain the order number and a payment number.

When we receive a payment notification PayPal, we save the payment in the Billing service database and then publish a PaymentReceivedNotification. In order to protect ourselves from duplicate notifications, before publishing our PaymentReceivedNotification we first check to see if we already have a payment with the given payment number in the database. If it is already present, then we disregard the message.

The Sales service needs to be subscribed to the "payment received" event. When it receives notification of this event, it checks to see if an order with the given order number is in its database. If not, it makes a request to eBay using the eBay Web service to retrieve the order details and then saves the order in the database. The service then stores a record of the payment against the order and raises an OrderPaidNotification.

By virtue of the "order paid" event, we have abstracted away all the complexities associated with compensating for inadequate service level agreements of third parties. We can then subscribe the Shipping service to the "order paid" event (which would contain the full order and payment details) so that it can arrange shipment of the order once it has been paid.

Note that with this architecture the contracts of the Sales and Billing services are devoid of any details concerning the third party organisations eBay and PayPal. This means we can replace these suppliers without impacting the remainder of our architecture.

It also means we decouple our other services from the Web service contracts exposed by third party organisations. This is very important as we will have little to no influence on whether or how often these contracts change. The abstraction layer limits the impact of these changes to the boundary of the service interacting with the third party.

No comments: