Welcome fellow explorer! It seems like you are deep into microservices already. It must have taken a lot of effort to find this article!
Let’s start with a heart-felt congratulations first 🥳🎉!
To honour your efforts, I’m going to get straight to the point.
Deciding whether you want to adopt a microservices-based architecture is hard. Embarking on the journey to build one is even harder!
How do you decide where to start?
What all should one consider? Should you start with a monolith and then break down into microservices? How to break down your services? What are the common pitfalls which can come your way?
There are so many questions one needs to answer.
In this article, we’ll try to address the question of where to start and what are the crucial aspects we need to consider while getting started with microservices.
Step 1: What’s your objective of going ahead with microservices?
I’m sure you want to punch me in the face right now 😅. It’s almost like taking a step back!
I’m sure you have done your research. But let’s answer this one more time.
Why do you want a microservices-based architecture in the first place?
Is it to make your application scalable? Or is it for making things more reliable?
The answer to that question decides whether you should go ahead with building a microservices-based architecture or not.
If you are looking for scale and/or reliability, you are better off building a monolith.
Trust me when I say that. In fact, many are considering going back to monoliths in 2020. Istio, a popular Kubernetes based service mesh, has already made the switch.
2020 prediction: Monolithic applications will be back in style after people discover the drawbacks of distributed monolithic applications.
— Kelsey Hightower (@kelseyhightower) December 11, 2017
So when do microservices make sense?
Consider microservices when you want development agility at scale.
Yup. That’s right!
Microservices achieves agility by breaking a large project down into smaller applications and encouraging smaller, more independent teams.
The words smaller applications and independent teams are important here.
All our efforts to get started with microservices are concentrated around them.
To conclude, opt for microservices only when you want to rapidly ship out new features while your app and organisation are growing rapidly in size.
That’s the real secret to getting started with microservices!
Step 2: Breaking down your app into the right-sized components.
This is more difficult than it sounds. It requires careful planning and consideration to get it right.
The burning question is, What functional pieces do we break our app down to? How small does a service need to be? What do we even mean by the word “micro”?
I personally think that the term microservice is misleading. It tempts us to think of these services being “micro” or as small as possible.
This isn’t the right way to get started with microservices.
Let’s look at a real-world use-case.
I’m gonna take the example of an app like Medium to explain the challenges of developing microservices with misplaced functionalities.
At its core, Medium is a blogging platform.
You and I can sign up on Medium as users. By default, we are on a free subscription plan. As you may know, users can opt for a paid plan to view all the metered or premium posts.
I might be inaccurate, but try to not focus on Medium’s business model. We should be more focused on the use-case.
Let’s say I have two microservices to handle this - users
and billing
. The users
microservice deals with user management along with recording the plan each user has activated. The billing
microservice handles everything to do with a payment gateway.
The problem arises whenever a user needs to be upgraded from the free to the paid plan. What we require now is a distributed transaction across two microservices.
We need to create a new billing subscription (in the billing
microservices) and update the plan of the user (in the users
microservices).
As you may know, transactions is a difficult topic to get right. And here we are talking about a distributed one across two different microservices!
There are ways to get around this problem. You might be aware of them. I’m going to talk about one such solution in my next point. But let’s look at the bigger picture here.
Mutations spanning multiple microservices must be avoided.
Don’t make your microservices so small that you end up with such a scenario too often.
Making your microservices too large doesn’t help either. It might beat the purpose of microservices altogether.
Always design your microservice as an independent SaaS offering with all external APIs being completely out of your control
Comparing a microservices with a SaaS offering may be going a bit overboard. But I really like that analogy.
You would want everything you depend on to deliver your APIs to be in that microservice itself. Even if it means, you end up denormalising your schema.
This doesn’t mean all data should be served from your database. It is okay to fetch data from other services or external APIs. In that case, you act more as a presentational or aggregator service.
This brings me to my next point.
The aspect of losing control or influence over external APIs is important. You cannot assert influence over other teams and have to accept the API contract/schema provided by them.
This applies to other teams as well.
I’m not saying that you can evade all communication between teams. Each API design draft has to be thought of collectively. But the implementation flexibility will reside with each team.
This forces a culture of working around the existing API and minimises cross-team interference.
I know this might sound a bit too restrictive. I totally agree with you. It kinda is.
With time your teams will develop the mindset and the right processes to implement and get started with microservices based architectures.
They will start synchronising their releases with others. Things will start working like one well-oiled engine composed of several independent parts.
Remember this,
Microservices based architecture is a design pattern and not a framework.
And no design pattern can be successfully implemented without imbibing the right mindset.
This point turned out to be a bit too heavy. Let’s move on to the next one.
Step 3: Use Eventing as Glue.
Eventing is a great way to glue or stitch microservices together while keeping them fairly decoupled.
I know what you are thinking. I just used the words stitch together and decoupled in the same sentence.
Now that I think about it, it does sound funny 🤣. But hear me out once.
Eventing is a mechanism to synchronise different services. It does so by emitting events, which other services, called targets, can subscribe to. Its semantics are similar to a pub-sub system in that regard.
Events can be generated by various sources - database mutations, file storage operations, function invocations or manually via an API.
Services interested in these events can trigger certain actions based on them - sending emails on user signups, updating internal state, etc.
If you think about it, we can handle the cross-service transaction problem I discussed earlier (in the Medium example) by using eventing. Let me know in the comments on how you would solve it.
I’d strongly suggest you read up on what eventing is and how it fits with microservices to know more.
A great characteristic about eventing is that it decouples the source from the target.
This means you can have zero or hundreds of targets subscribed to a particular event without affecting the source at all.
Functions as a Service are a great fit for this task.
In short, eventing provides a great mechanism to synchronise different microservices.
In my experience, most events are triggered via the data layer.
Most cloud providers support this for their native solutions. For example, AWS DynamoDB and Google Firestore all trigger events on mutations.
If you would like to explore an open source eventing system which is cross-platform, i.e. works with open source databases, check out Space Cloud - An open-source Firebase + Heroku.
Step 4: Consider using GraphQL at the API layer.
This one should be fairly straight forward.
Your clients or end-users would require information from multiple services to populate a single page. This article itself is touching the users
and posts
microservices.
This means you’ll require to write an aggregator service to do anything meaningful. This service would join data from multiple sources and make it available to the end-user.
I think you know where I am going from here.
The scenario explained above is the perfect use case for GraphQL.
We tried it at Space Up Tech. We were so happy with the results that we wrote an article on why GraphQL is such a good fit for your microservices and how you can go about implementing it..
Its use extends well beyond your end users. Your microservices can use the GraphQL layer as well.
You could put your databases and microservices behind a GraphQL API creator like Space Cloud. This would give you a consistent access pattern for data sources.
Okay okay! I’m getting a bit too excited!
Lets continue focusing on getting started with microservices for now 😅.
Bonus: Start with a monolith
I see you’ve got your guns all loaded up. Ready to fire.
After all this information, I’m asking you to start with a monolith. I would be angry with myself if I didn’t know what’s coming next.
If you are working with smaller teams, having multiple microservices is an unnecessary burden.
Let’s be honest. At that scale, it isn’t giving you any benefits.
Instead of having multiple microservices and increasing your DevOps complexity, you can have a single codebase for all your microservices. All of them packed into a single binary.
Don’t get me wrong here.
I’m not asking you to disregard any of the points I’ve covered earlier.
What I am asking is building a monolith with all the practices we have discussed till now.
This implies that each module in our monolith can talk to each other via HTTP (or gRPC) only. Each module will have it’s own set of tables which other modules can not access.
I guess you get the point.
The process of breaking down the monolith, in that case, should be fairly simple, provided all the above principles are followed diligently.
And it gives you ample opportunity to decide which functionality should be assigned to which module.
If things go as planned, each module will grow up to be an independent microservice someday. And that day shall come soon. I feel like a proud father already 😂!
Its time to finally get started with microservices!
I really wish you success in this journey of getting started with microservices.
As you may have noticed, I’ve tried really hard ranking for the phrase getting started with microservices and the term microservices 😂.
It would be great if you could help me as well by sharing this post on twitter.
Do check out Space Cloud as well. I believe it can help you get started with microservices really quick. It will help you from autogenerating a GraphQL API for your microservices and databases to deploying your services on Kubernetes and Docker.
Here’s a quick start guide to get your hands dirty. Don’t forget to star us on github!