How to Quickly Build Reliable Microservices Using Serverless Cloud
The following fictional scenario is derived from a case study in Microsoft's Cloud Workshop for Serverless Architecture. Its material intended for a whiteboarding session where a group of architects would take the case study and have to come up with a solution in about an hour.
In the story you're about to read, all names, characters, and incidents portrayed are fictitious. No identification with actual persons (living or deceased), places, or buildings is intended or should be inferred.
...No animals were harmed in the making of this story.
Serverless Is For Closers
-----------------
My name Chris Dasilva. I'm a solutions architect working for Contoso, Ltd., a company who handles license plate processing for toll booths. It's not a big company--about 250 people. I'm good with that, though. We have great people and that's what matters to me.
I was hired a little over a year ago to lead the "transformation of the architecture to cloud". That's code for "get the company out of the datacenter which is costing us too much money". So far things have been going well. The only things left on premises now were some back office systems, including billing.
Oh, one thing I want to mention before I go any further: many times, during an interview process, handwaving occurs on portions of a system's implementation. Well, one of those hand-waves I experienced during my interview was how license plate images from the toll booths were processed. I assumed some things since it was called the "license plate detections service".
What do they say about making assumptions? Exactly.
Within the first week, I learned what was meant by the "license plate detection service". The company was farming out the license plate identification to a firm that examines each plate manually and sends a nightly batch file with the license plate data so we could handle the billing!
Of course, the choice to do this was before I came on, primarily for financial reasons (it was incredibly cheap). Even with all the migration efforts to Azure, I've been jonesing to replace this whole “sub system” for the last few months, but Abbey Burris, my CTO, has deferred the work so our resources weren't diverted from the cloud migration.
That was yesterday.
Today, we were awarded a large, yet unexpected contract to manage toll booths across most of the state of Texas, resulting in a 2500% increase in coverage for us.
Great.
I was thrilled to finally get my chance to do some green field. But…development and IT were now under the gun to deliver it in pretty short order was my guess.
A pit started forming in my stomach as I watched Abbey give her remarks during to the announcement. Not because of the pressure, but because I could almost smell the carryout pizza in the air. You know, the ones that get delivered so you could pull yet another all-nighter; and don't forget about the "hero awards" being handed out for the one who slept the least and ignored his or her family for the last month--God I hate those things.
But I quickly pushed those emotions aside and decided to focus on the benefits. I really was looking forward to implementing an automated license plate detection system.
A day later after the big announcement, I walked past Karl Ellis's office on the way to the grab something I had forgotten in my car (Karl Ellis is our sales director.).
"Well, Chris. You're finally getting what you hoped for!" Karl called out, pressing the button on his conference speaker.
"What was that?"
"The automation work you've been saying we needed for the plate processing. My team is killing it. We just finished two calls today with Oklahoma and New Mexico on their toll booth services. We're 'this close' to landing the deals thanks to the new automated system we’ve done for Texas. Can you believe it?!"
I feigned excitement now.
"That's fantastic, Karl. We do still have to build it," I said deliberately slow, winking.
"Sure, but this is really going to help us grow. Thanks to Mike's work on Texas, we already have marketing material going out on the potential volume we can process."
I finished up the small talk and kept walking down the hallway. Suffice to say, as soon as Mary's development teams found out a few days later about the additional contracts, they weren’t smiling. The pressure was on.
It was true. The sale team had done a great job winning new business. We watched them high-fiving and celebrating but we knew the weight of delivering this was on us, and the sales people were already acting like it was something we had up and running.
Abbey was very concerned about the massive increase in the number of plates that the company had to process—on a continual and constant rate. The outsourcing approach wasn't going to work anymore.
We all knew it.
She called me into a meeting with the director of software engineering, Mary Sunderland, to discuss the situation.
"First, I want to thank you both for the success we've had migrating to Azure. We now have 80% of the workloads out of the datacenter, and the only thing left is back office."
Here it comes, I thought.
"We're going to put the remaining work on hold. With the Texas contract, the license plate detection is top priority now."
"How much time did we pad into the onboarding process to get this done?" Mary asked.
"I know what you're asking, Mary,” she said, pausing for more than just a moment.
“Development has four months to get into pilot, " she stated matter of fact. "I did my best to give us more time on this, but with such a large opportunity, Texas basically demanded and we had to say yes or we would have lost the business."
Mary's lips pursed tightly. She leaned back a little in her chair and sighed, exhaling while looking down at her hands which were now pressed together like she was praying.
Maybe we need a prayer right about now, I thought. We were on the hook to automate a critical piece of our business, completely green field, in only a few months.
Mary looked over at me.
"Well, Chris. You've got your chance to do microservices, finally. How we're going to do it in a few months is something we'll have to figure out. I'll get my senior developers and we'll get some design sessions planned, but I need to know you've got a high level solution to bring to the table."
"I've already started," I said.
-----------------
All too common a problem
Whether large or small business, you’ve either experienced or will experience some form of this situation if you’re in IT, regardless of the underlying reason (like a big deal/sale).
If you’re designing and constructing software, particularly the solutions architect, understanding the project constraints and having a thorough grasp of the available options available to fulfill the business need is a must.
Putting ourselves in Chris's shoes, we're going to design a microservice style architecture and use “serverless” cloud services to solve for our fictional scenario.
Serverless needs rigorous design too
Our first goal is to understand the business and to model a system’s design to fulfill the business problems being solved. If this isn’t done from the beginning, the outcome will be difficult to predict. Because business problems, particularly for very large systems, are difficult fully understand in the beginning, emergent architecture techniques should be leveraged, including:
- Accepting that there will be change and accommodating for it in our design
- Componentizing our architecture, rigorously seeking for clarity and maintainability
Can serverless deceive you in the progress you're making?
Can a team really develop faster on top of serverless? In my experience the answer is probably, yes. However, if a development team implements a design by coupling themselves to the physical platform their running, for example Azure Functions or HTTP request/response, then you will end up with poorly implemented software, faster.
Serverless may support faster software development, but poorly written code using serverless platforms will simply achieve poorly implemented software at a faster rate.
Will the software seem to work, initially? Probably, yes, but as time moves on, non-trivial problems often arise; and this is one of the dangerous aspects of serverless, so we must understand the practices of the development teams that will be using the serverless platform. They should be writing code that is modular. This means that it should be:
- Decoupled from the production environment infrastructure (by incorporating seams into the codebase)
- Testable outside a "real environment"
The recommended design from the case study
OK, so let’s refer back to the case study from the cloud workshop. Here is the recommended design for the serverless solution in the workshop:
Looking at this diagram, It certainly has a number of different Azure icons representing "serverless", including:
While these services are probably suitable for solving many of the problems, it's difficult to understand the logical design, if at all. I see "vehicle photos" and that's one of the only things that stands out to me, but what else about the diagram describes problem domain?
Not much.
Designing for Reliability and Speed of Development
Let’s remedy this situation. First, I'll begin with decomposing the system into the microservices I've identified. I did this by reading through the case study, and determined boundaries of behavior and data consistency. We want diagrams that clearly depict the problems we're trying to solve for the business. Someone should be able ascertain that this is a toll booth, license plate processing system that integrates into a separate back office billing system.
Decomposing a system into microservices
Here are the microservices. We have TollBooth, LicensePlates, Vehicles, Billing, and Alerts.
Again, read through the case study to compare this list against the business scenario, but what I want you to notice is although this visual artifact is fairly trivial at first glance, we're making some crucial decisions.
- There are clear boundaries in our system
- This isn't one codebase, but at least five (5).
- Vehicle data isn't necessarily license plate data
- Billing is represented as a microservice, not just something we integrate with.
What is a microservice?
Here is a perfect point for a public service announcement and plug for Udi Dahan's definition of a microservice (or what some used to call a service in the old SOA days:
A service is the technical authority for a specific business capability. Any piece of data or rule must be owned by only one service.
So remember, if microservices are going to be implemented with serverless, start with a sound logical design, decomposing the system as much as possible until there’s “nothing left over.” If there are unknowns, that's fine. Remember, allow for change in the design.
What we don't want to do is start by throwing cloud services onto a piece of paper and call this our architecture. This should be our last step--implementation details--important details, but nonetheless subservient to the logical design.
Decomposing microservices.
Everything is not a microservice. Don't forget the rich set of abstraction types available when designing a system.
It's perfectly normal if something in the system cannot be called a microservice.
Here are the microservices, including a few of the most important components and message contracts (commands and events) I've identified.
For the sake of brevity, I'm not going to dig into the justifying details, so I suggest studying it closely on your own, comparing this against the case study's description of the business requirements.
Microservices and behavioral / consistency boundaries
One very important design decision you may have noticed is that there is a Vehicles and a LicensePlates microservice. Couldn't we have just made one? No, and I'll explain why.
For starters, Billing doesn't really care much about a license plate. It cares about cars. It can't do much with just a license plate. In Vehicles, we probably have an owner, make, model, year, color, etc. Vehicle data is not the same thing as license plates in this domain.
Secondly, The license plates are detected, stored, and processed in a much different way for the business than vehicle information. How do we know this?
Recall that a microservice is the technical authority for a business capability. In this context, we apply this principle to mean that regardless of a license plate being detected automatically or manually by a person using a UI, it must be handled by the same microservice. The LicensePlates microservice is the owner of this data, so it must be implemented to support OCR as well as the manual process. Once the license plate is detected, it will publish its event that the license plate was detected.
The Vehicles service will wait for a plate to be processed by subscribing to LicensePlates events. Once it receives all the bit it needs to identify a vehicle, it will publish an event that states "Hey, I've identified a vehicle". Billing microservices is very interested in this event and will subscribe to it, and perform the integration with the back office system.
Microservices and system integrations
I'd like to call out an important aspect of the design I've created so far. The case study has us integrating with a back office billing system. You may have even designed a system that integrated with something like billing, and integrated directly from one or more microservices.
In a microservice architecture, it's easy to trip up here and forget to include a Billing microservice for the integration, and end up with incoherence in our logical design where events about billing are published from "LicensePlates" or "TollBooth" services.
Why is this so important? Because Billing must have its own agency.
We know this because the billing context has it's own data and "language." A heuristic that we can use as evidence to support the design decision, here, is that other parts of our system are interested in facts (past occurrences, e.g. events) about what happened in billing.
What could possible be authoritative for events in a system? Well, the technical authority for the business capability, and that happens to be Billing in this case! So we can be reasonable certain now that a Billing microservice is going to be in our logical design. Having a Billing microservice in the design also provides the added benefit of an anti-corruption layer and bulkhead for the back office system.
Microservices interaction
Here is a draft of the interactions between the microservices. I've excluded some details from the picture to conserve space (alerts for example), but we should be able to see the crucial details.
We can tell right away that we're looking at a representation of a system that's processing toll booth images by collecting vehicle information, detecting license plates, and integrating with billing.
We can also see, although the system has microservices that communicate, flowing from left to right, they are communicating 100% with messaging. There are zero direct calls to a "microservice API", aka a "REST API". This will keep our microservices loosely-coupled. In fact, the only direct messaging call depicted, if you noticed, is the DetectLicensePlate command from Vehicles service to LicensePlates service, using Azure Service Bus queues.
Conclusion
Microservices with serverless can be a very powerful way to implement your software systems on cloud platforms like Azure.
To leverage the tool's ability for us to quickly create and deploy our software, begin with sound design and implementation practices as the foundation. Start with the logical design, then work from there, including the infrastructure and deployment designs.
With serverless, we can easily be tricked into thinking we've made progress, when what we're doing is triple knotting our software into brittle "serverless monolith", holding us back from continuous improvement and delivering value to the business.
Kevin great article. Loved how you define the business solution into the micro service diagram. Interesting case to read through.