Practical .NET
Designing Service Messages for Optimal Performance
If you're building services, then getting your message formats right can be the difference between success and failure. Here's an example of what can go wrong and how it could be fixed.
So, it's Christmas in Canada and I'm standing in front of a self-serve gas pump, realizing that the reason it's taking so long before I can start pumping gas is because someone screwed up the design of the messages the pump is using to communicate with its server.
I know the problem isn't the pump's CPU because the UI is quite responsive ... as long as the pump is doing something locally. But, as soon as the pump has to contact its remote server, everything stops for tea. That's a problem because the pump is making at least four separate trips to the server: The first trip is to validate my credit card, the second is to validate my PIN, the third is to determine whether I'll exceed my credit limit, and the fourth is to retrieve the discount that I get on my gas (about 40 cents on the U.S. gallon, by the way).
It's not just that the pump is unnecessarily leaving a customer (me) out in the cold, these repeated trips are also limiting the server's scalability. Each one of those trips to the server has an overhead cost associated with it and the message design is causing that cost to be paid four times.
Fixing the Gas Pump
While I don't know for sure, here's what I suspect was going on with my gas pump:
- Read my card to get its number
- Send the card number to the server to be validated
- If the card number is validated, ask me to enter my PIN
- Send the PIN to the server to be validated
- Ask me to pick a limit to the amount of gas I'll pump
- Send that limit to the server to be validated
- When that validation is received, send a request for my discount
- When that discount is received, apply the discount
- Let me pump gas
(And, before you send me emails about why the transaction is structured the way it is: I realize that the people who wrote the "real" version of this application are smart, clever people. The existing, multi-trip design undoubtedly reflects constraints on these kinds of transactions that I'm unaware of. Or the current transaction reflects some historical constraints and, rather than rewrite an existing, working system that's generating millions of dollars a day, the company has decided to leave well enough alone. I get that also. My naïve assumptions just made for a good example.)
A Better Solution
The request messages have the advantage of being very simple (just the card number on the first request, for example). However, we have three different messages formats: one for validating the card, one for validating the card number and the PIN, and so on. There isn't much good to say about the response messages -- essentially, the pump has to make multiple trips because it gets very little data back in each response.
A simpler process would look like this:
- Read my card to get its number
- Have me enter my PIN
- Have me enter my limit for gas
- Send all three pieces of information to the server (less than 24 bytes of data), wait for a message with all the information a transaction could require (including validation codes and the discount on my gas price)
- If the response has a validation code other than "OK," display the related error message and ask me to try again
- Otherwise, apply the discount
- Let me pump gas
The request message format is simple: It consists of the card number, PIN and dollar amount. The service has three operations:
- If only the card number is present, the card number is validated. All public information (assuming some exists) is sent back in the response, including the card number.
- If the card number and PIN are both present, both are validated. All the information from the first operation is sent back along with any potential transaction-related information (the discount, for example).
- If all three are present, the card number/PIN are validated, and the transaction is also approved. All the information sent in the previous responses is returned, but a flag to unlock the pump is included.
We need two more rules:
- If no card number is present, then the message is invalid.
- Your choice on whether a message consisting of a card number and a dollar amount is treated the like a message with just the card number or as an error.
Assuming we take the appropriate measures around encrypting data, then, with the right message formats, not only do I spend less time freezing my ... thumbs ... off, the application is more scalable. But, while this is a single example, it does build on the three fundamental principles of message design. I'll look at those in my next column.
About the Author
Peter Vogel is a system architect and principal in PH&V Information Services. PH&V provides full-stack consulting from UX design through object modeling to database design. Peter tweets about his VSM columns with the hashtag #vogelarticles. His blog posts on user experience design can be found at http://blog.learningtree.com/tag/ui/.