Building Serverless Microservices — Picking the right design
Well, in the last article, we built a serverless microservice. But one microservice on its own doesn’t do much “by design”.
In this post, we will start accelerating our microservice game, by adding a “simple” requirement that will shape our system.
Well, looking ahead we will be building some new microservices, also with azure functions, because serverless, but the information in this post will apply to microservices in general, .net or otherwise.
As of now, we have the cart microservice, which, in the scope of an online shop should be the bread and butter, but by its self, unfortunately, it’s useless. So to enable us to build our digital empire, we will be adding a few other microservices to enable some more business logic.
To successfully place an order, we need to push the contents of the cart, along with the user’s address, get a quote for the transportation, get the VAT for that specific address, reserve the products in the warehouse for a set amount of time, issue the payment request and then push the order to the fulfillment service.
So, to fulfill an order, we just need to add:
- Product Catalog Service
- Order Service
- Shipping Cost Service
- Payment Service
- Warehouse / Stock Service
- Fulfillment Service
Easy, right? Right …? Well, not really… Just looking at the above list gives me a slight headache, and makes me question my life choices… I mean all of this, for one action, seriously? What is this guy thinking?
In all seriousness, this is usually the point where people usually get a chilling feeling and start backing off to a classic MVC project , with most of the stuff stuffed in the controllers. Since you are reading this, my friend, you are not one of those, you will gloriously blaze your own path in this brave new world, it will be awesome!
So, now that we have an idea on what we will be building, I’d like to go against one of my favorite quotes and do a bit of planning ahead.
Weeks of coding can save hours of planning!
Someone on the internet
The way I see it, there are several ways on how we can implement the above requirements.
Repository Of Repositories
This is the “pattern” I noticed a lot of teams use.The way this works is more or less the following, we break up the requirement into, let’s say stories, with one service per story.
For each story, we will have more or less a CRUD API. And we will have another 2 or 3 stories at the end to integrate everything. The integration itself would be done more or less a class somewhere that will try to bend the CRUD APIs into submission by applying all of the business logic, something in the lines of a domain service.
It is usually accompanied by a diagram that looks more or less like this:
This is something that I consider to be like the first step into dabbling in microservices, basically, if you think a bit about it, it just getting some regular application services and slapping an API in front of them, and deploying them separately. It’s a good step forward, but this is a journey we will not take for our tutorial.
Vertical Slice / Workflow approach
I also like to call this UI Driven Design. In our case, we will be taking “one” from DDD’s book, and implement just the bare minimum to satisfy our requirement. We won’t bother too much with anything other than this. I know, that for some of you this might look quite sloppy (to say the least), as it looked to me a while ago, but this is more or less a mindset shift (YAGNI!).
If we look closely at the requirements, it looks quite similar to a workflow, because, well, it is a workflow.
Workflow — the sequence of steps involved in moving from the beginning to the end of a working process.
If we take the time to break this out, here is how this might look in the form of a diagram:
You have to admit, this looks better. Now that you’re on board, let’s roll our sleeves and get down to business go to our next big decision.
At this point in time, this is one of the hottest questions in the microservices space. Some people prefer one, some people prefer the other. If you ask which one is better, as almost everything in the land of software and consulting, it depends.
If you “google” “orchestration vs choreography microservices” you would be amazed how many opinions are there. Here are two links with articles that I found quite interesting:
If you plan to save those links for later, and probably never get to read them, here is my take on this, in a really really high-level and personal view (think helicopter).
Here we have a very traditionally looking (maybe even totally uninteresting) “workflow”. We have a start, we have an end, we have several steps, and one specific “entity” ( in the esoteric sense), the “orchestrator” that keeps a close eye on the process. This entity is responsible for orchestrating the whole process.
The pros of this approach are:
- Tracking, if done properly, is very is to see each flow’s state.
- Lego-ness (???), you could define your code in such a manner that you would treat each “microservice” / function call as capability, and only using the orchestrator to glue them together. This way, the same functionalities could yield different results depending on how they are set up.
- Easy to debug
- Did I mention tracking?
- 2-way binding (ish),
- You end up having a lot of business logic in your orchestrator
- The orchestrator is highly specific, thus it should NEVER EVER be reused between workflows. (Now, that I think about it, this might also be a pro… meh…) (this is like the MediatR discussion all over again…)
- Not very scalable
- Quite difficult to handle flow changes ( versioning )
- Not very “cool”
Choreography — Event Driven
Who doesn’t love a good choreography?
This is the place, this is where we want to be,here everybody knows what to do, it’s like a scrum masters dream. Literally, the premise of a choreography based system is that everybody that takes part needs to pay attention and react in sync with everybody else. More technically, it’s like pub-sub on steroids. A lot of people bind the idea of an event-driven system or “choreography” to a message bus of some sort, while it makes it easier and it is one way of doing it, it is not the only way, and by all means, it is not the single way.
So, how does this actually work?
Well, everybody is connected to a common source of events. Each of the microservices has at least a subscription and once the event was fired on the bus it reacts by processing it and depending on the job of the service it also produces one or more events, to whom everybody else reacts in turn.
The pros for a choreography based service:
- Incredibly versatile
- Super scalable, if one service is getting too many events and starts to struggle, spawning multiple instances should instantly distribute the load without any issues.
- Looks like magic when it works
- Very extendable
- Handling different versions of events / flows concurrently
- It is really difficult to track a flow
- It is mostly one way, according to the philosophy behind event-driven systems, an event could and should never be rejected and also, if you need to reply, you probably are doing something wrong.
Well, it is quite a tough one, and one that shouldn’t be taken lightly under any circumstances. If we look at both approaches through the lens of cynefin, we could argue that while the “Orchestration” approach might be in the “obvious” to “complicated” part of the grid, the “Choreography” would be in the complicated to complex, and depending on the size and execution might even get to the chaotic part.
Now, as a personal preference, I am in the the choreography’s camp. I find it mesmerizing and the possibilities endless. It’s like taming a wild animal, and it’s elegance blissful. But as we all know, this shouldn’t be the criteria that one should use when designing a system.
So, this being said, for our business requirement defined at the top, we will be picking the “Orchestration” approach (this is more or less an introductory material, and I wouldn’t want to scare you away).
Since this post has already reached the length of a questionable, purchasable for only 9.99, eBook, we will stop here.
Starting with the next post we will commence the work on our first flow.
Like the content on this blog ? Well, you could subscribe to the mailing list to get a notification email when something new is published.
Originally published at http://laurentiu.codes on September 23, 2020.