15 April 2013

Pub/Sub Revisited

How many enterprises say they want a "Publisher/Subscriber" architecture?  "We want," they say, "For the Ordering system just to send one message, and for everyone who needs it to get it.  Ordering shouldn't know anything about the down-stream systems."  Okay, that's fine as far as it goes.  But what about the other way around.  The current paradigm says that *someone* has to know about both up-stream and down-stream systems.

Either every "down-stream" system knows about every up-stream system that it cares about (and you'd be amazed at how many that is.  You'd also be amazed at how fast Ordering finds that it is down-stream of Inventory in the right circumstances), or some central system (or "Broker") knows about everybody and keeps them all straight.

Now, the first option is terrible.  Suddenly this "Publisher/Subscriber" methodology becomes Code-thulu.

The second option is fine, but it's not actually Publisher/Subscriber.  It's Hub-and-Spoke with a Broker.  Nothing wrong with that, but it has certain ramifications which will be different if you were expecting publisher/subscriber.

"But how," I hear you asking, "Can we get 'real' Publisher/Subscriber?"  And you have a point.  At some point, someone has to know about both up-stream and down-stream systems, don't they?

Well... no.  Not really, if you're willing to do a little work.

Now, let me be clear here- what I'm suggesting does not reduce complexity in any significant way.  We're talking about complex interactions between complex systems.  We can abstract that complexity away all we want, but that complexity will still exist somewhere.  What I'm suggesting allows the complexity to exist where it can most readily be changed/fixed- within the individual business domains inside your company.

How does this methodology work?  Enter the Dragon, err... Database.  Publisher/Subscriber does exist in the wild- it's called RSS, or Email, or any number of other things.  In those systems, the Publisher simply publishes a message (a blog post, an email, whatever), and the subscriber goes to look for new messages on a schedule.  Ours will work the same way.

Let us say we have a business that sells widgets online.  We'll have a system that takes the orders and owns them- it's job is to say "I've got a new order."  Also to say, "Okay, warehouse, the order is confirmed; go ahead and ship it."  We'll have a billing system.  The billing system's job is to listen for a new order, and then verify the customer paid (or has sufficient credit to pay).  We'll have an inventory system whose job is to listen for a new order and make sure we have the available inventory.  We could go on.

So how do all these systems communicate?

A common messagebox, and defined message types.

Our system will have a base "Message" from which will be derived a "NewOrderMessage," a "BilledOrderMessage," an "AllocatedOrderMessage," and a "FulfillmentRequestOrderMessage."  (There would be more as well IRL).

Then, we'll define (on top of those Messages) a MessageBox (I call it Broker on my system, but don't get confused- I merely mean that it "brokers" the DB functions), and two interfaces: IPublisher<Message> and ISubscriber<Message>.

Because these are Typed interfaces, I can actually implement several of the same one (and, in some cases I'll have to) without much difficulty.  For instance, our OrderSystem will be IPublisher<NewOrderMessage> and IPublisher<FulfillmentRequestMessage>, and it will be ISubscriber<BilledOrderMessage> and ISubscriber<AllocatedOrderMessage>.  This is why Explicitly Implemented Interfaces exist, after all.

Then, in general, an Order will come in, and the OrderSystem will publish the requisite NewOrderMessage.  Billing and Inventory will be listening for that message, and will each do their job based on the information therein.  When done, Billing (IPublisher<BilledOrderMessage>) will publish it's message saying "yay" or "nay," and Inventory will publish (IPublisher<AllocatedOrderMessage>) it's message saying "yep, we've got enough" or "nope, we'll have to back-order."  The OrderSystem will then wait until it has both an AllocatedOrderMessage and a BilledOrderMessage for the order, before requesting Fulfillment ("Hey, billing and inventory say this is a go- somebody call FedEx!").

No comments:

Post a Comment