On the last years we have seen a trend where more and more startups are moving to the Microservices architecture (also known as SOA, or Service-Oriented Architecture). You can see this phenomena as an increase in DevOps work, the culture of containers, Docker and Kubernetes. I don't agree with how this has been hyped, and I want to explain why. But, before that, let's go through some definitions.
What is Microservices?
Microservices is a software architecture where the different aspects of the system (user management, billing, accounting, inter-user communication...) are separated in different processes, and may be run even in different machines. This is in contrast to a Monolithic architecture, where all the aspects of the system live within the same process.
Microservices, as many other recent discoveries, has actually a long story. For example, in the past it was called SOA: Service-Oriented Architecture. Once upon a time you could use a Service Broker, or CORBA, or something like that to construct such architecture.
Why startups choose the Microservices architecture?
There are many reasons why Microservices is the chosen architecture. Among them, we can name:
Microservices help scaling the startup
Scaling is one of those words that is often not well understood, specially in regards to time. People think their ultra-niche startup will be another unicorn with 3 billion users. Yes, because there are three billion people in the world so interested in optimizing the performance of three-wheeled bikes with fluid transmission that are willing to pay for it.
Let's be realistic. At the initial phase of a startup, you don't need to scale to billions of users. You need thousands of users. And, you can serve those thousands of users without microservices.
Investors demand Microservices
Investors rarely understand how to achieve what they want. They want a big business, so they invest in a newly-created startup and apply all the big business rules to it hoping that it somehow transforms into a big business overnight. Among the things they seek is an architecture based on Microservices because...
The big guys use Microservices
Netflix uses Microservices. Amazon uses Microservices. So does Ebay, Paypal, Twitter, and many other big companies. But, all these success stories forget to tell you something very important: all these companies reached their big size scaling a Monolith until they couldn't scale it anymore.
Microservices improve service reliability
When a service fails, the application doesn't fail completely. Only that part that is affected by the service is affected, whereas the rest of the application still runs. Except if that service is critical, which most services at the initial phases of a startup are.
It helps the IT team pad their resumes
Totally. "Worked on several startups based on microservices" looks cool on your resume. Also helps landing the next job.
I want to be a DevOps!
Docker, containers, Kubernetes, Ansible, CI/CD. All of this is lots of fun, can't deny it. It also pays well, and allows you to feel like a badass hacker out of a movie.
Where is the business reason?
We have enumerated many reasons, but none of those reasons include business reasons. How is Microservices going to help acquire more customers? How is microservices going to help you attract more publicity to your startup? How is Microservices going to help your startup hire better workers, and deliver better features in less time?
Where is the business reason for choosing Microservices?
What you pay for using Microservices
Microservices is not free. In fact, you have to pay a significant price to have it. Let's go through the associated costs of Microservices:
Microservices complicates the deployment story
On a Monolithic architecture, you deploy a single server, or a group of servers all of them with the same software. You don't need exceptions in your deployment rules. You have a single model server, or a single container type. You have a single piece of software. Either the feature is in this single piece of software, or it isn't anywhere.
On the other hand, with Microservices, each service has its own deployment story, each service has its own code base, its own database, and it may be deployed to a different server. This complicates the deployment story significantly, costing you time and an increase in problems. Now you have to hire a DevOps to manage the deployment story, instead of hiring another Developer to develop the features that will get the next paying customers.
Microservices complicates data consistency
On a Monolithic architecture, every request is usually served in a single database transaction. If everything goes right, the transaction completes, and the database stores the updated state completely. If something goes wrong, the transaction aborts, and the database ends up just like if nothing happened. Either case, the transactionality of your old and boring SQL database simplifies your data story.
On the other way, with Microservices, any transaction that spans across two or more services can end up with data inconsistencies. With an accounting service and a delivery service, any failure (including slow-network days) can end up with either the client being charged but no service being delivered, or with the service being delivered but the client not being charged. Now you need someone to go to the database and look for incomplete transactions, and fix them. You also need to get another developer to create some system to fix automatically the most common data inconsistencies.
Of course, to prevent this, you can implement a 2-phase-commit protocol so that you can have transactionality in between your databases.
All of this forces you to spend a lot of time babysitting the architecture, either fixing inconsistencies, or invoking convoluted protocols to prevent inconsistencies. All this time you and your team could spend improving the product in order to attract more paying customers.
Microservices complicates hiring
It's hard to find good talent. Good developers are expensive, they are busy applying to work at your competition, and they may not fit your cultural values. On top of that, software is so complex that developers tend to specialize in order to be able to understand the complexity of a modern stack and be competitive in the market.
This magic frontend developer is already very hard to find. So, let's make it harder by also demanding that this frontend developer also knows Docker and docker-compose, and how to call and serialize data from multiple services concurrently, so that he can run the Microservices backend and use it.
Congratulations, you just made the hiring story significantly harder.
Microservices complicates software intercommunication
In a Monolithic architecture, it's easy to call functions and operations from other modules. You just call the function, and that's it. Of course, this can lead to leaky interfaces, and exposing too much of a module.
On the other hand, on a Microservices architecture, every cross-concern call needs to be serialized, sent over the network, serialized, processed, the answer serialized back, sent back over the network, and serialized. Any of these parts can fail. Today, it happens that the connection between the delivery API and the user service is slow, and this causes a network timeout to bubble to the accounting service. Now go and find the real reason.
If everything happened to be in a single process, within a single server, either this timeout would not have happened, or you would have a massive traceback that, at the bottom, points directly to a timeout exception being thrown in the context of the delivery API, with contexts in the user module and the accounting module. Significantly easier to understand.
Again, you spent a lot of time chasing this serialization or timeout issue in order to figure out what went wrong. Time that you could have spent adding that other feature to improve customer acquisition.
A journey through the startup lifecycle
To understand the need for Microservices in a startup, we need to go through the life of a startup.
Two founders in a garage
We start our startup with two founders in a garage, with big ideas, bigger hopes, and even bigger expectations. On this first stage - the pre-seed stage - the objective is getting enough attention around your business idea so that investors are willing to give a first seed to make it happen. You usually try to show that there is some traction to the idea, that there exist some people interested in a product related to the idea.
Microservices for a pre-seed startup?
Considering that your initial objective is getting a first seed of funds, do you need Microservices at this stage? No, of course not.
At this point, with a simple static website for the 100 daily users (an average user every 15 minutes) is more than enough. Even better, you can ignore the website and just make a Powerpoint presentation to pitch the ideas to the investors.
You managed to get some investors to invest $100K. Your next objective is proving that a business can exist, and that your team is the right team to execute this business. To prove this, you have to construct enough of a system to convince the visitors to your site to actually enter your sales funnel and pay for what you offer. So you need to:
- Hire a basic engineering team that can provide something that looks like a basic product that someone would pay to use.
- Make a basic sales funnel and marketing team so that the startup can attract some users, and get a part of these users to pay.
At this point, you are trying to validate your idea, and you are looking to get some revenue. Not enough to make the startup profitable, but enough to show to the investors that people out there are willing to pay for it, and that your team is the right one to make this into a full-blown business. You are targeting to hire a Tech Lead/Architect/Main Developer and a Sales/Marketing/Evangelist Executive.
Microservices for a first-seed startup?
With $100K of runway, you don't have too much time to waste, and your objective is serving 1000 visitors per day, hopefully with 10 of them paying. 1000 visitors per day is a visitor every few minutes, 10 users per day is a user every two hours. At this point, your objective is figuring out how to make users pay, and how to get the next round of funding. So, do you need Microservices at this stage? No, totally no.
You managed to get investors to invest $500K on your startup that now has some users, some of them paying for the service. At this point, your objective is scaling the operations. You need to scale everything so that you can grow the business a lot, hopefully into profitability. You need to hire:
- 5 to 10 engineers for the engineering team to deliver great features
- 10 to 20 salesmen/women for the sales team to figure out what the clients will pay for, and hopefully land your first enterprise sales
- 2 to 4 marketing specialists to broadcast your startup to the world
- 2 to 4 administrators (HR, accounting & others) to reduce the friction as the operations grow
At this point, you are growing the operations and figuring out the secret sauce to reach and acquire a significant part of your niche, get decent revenues from it, and push hard into profitability.
Microservices for the Growth phase?
During this period, you are very likely to need to scale your technology. You should reach a point where your simple architecture is not able to serve more users. But, does this mean we need to change our Monolith now to Microservices? Hey, don't rush without considering the alternatives.
Case 1: you don't actually overload your single server.
Turns out the business you are constructing doesn't actually use that much processing power, so it can actually run on a single server while making significant money. So you don't bother scaling your software architecture.
Case 2: your single server becomes somewhat overloaded.
Ok, your single server is not strong enough. Have you tried purchasing a single, bigger server? Sounds like the obvious thing everyone would do, but it's hard to understand the size of some servers out there. Amazon offers you some really big machines out there, with up to 4 TB of RAM (yes Terabytes) and hundreds of cores. This is one hell of a single beefy machine.
So, maybe, you can fix your scalability problems by paying your cloud provider another $200 per month, which is significantly cheaper than hiring a DevOps and modifying the architecture.
Case 3: your bigger single server is still overloaded.
This is becoming harder. You purchased a single bigger server, the business grew a lot more, and is still overloaded. It's time for you to start splitting some of the responsibility of serving to other machines. Your database should be extracted to another server. The SSL encryption layer should be in another machine. You should look to add some caching for the hot paths, and start optimizing whatever is slowing you down.
This is more expensive than the previous options, but still it's affordable.
Case 4: you cannot do it anymore with a single server.
Aha! You cannot do it any more with a single server, therefore it's time to go to Microservices!
No. Stop putting the cart before the horse.
At this point, you should look to parallelize your single server, and scale horizontally. If you are still on a single database (as you should), all your persistent operations and concurrency will be ultimately organized by this single database, that you hope to eventually make into the bottleneck. So, now, the objective is modifying the codebase so that every operation can be served in parallel while operating on a single database. All the stuff about immutability, no-global-variables (except the database) and referential transparency that the Functional Programming crowd pushes will help you a lot. In fact, almost every modern web framework ships with these ideas bolted in, and easy ways to deliver parallelism:
- Your Django projects can easily use many threads by using Gunicorn, and that should have taught you to not depend on cross-thread data.
- Your ExpressJS projects teach you to use promises to read and process data from the database in pseudo-simultaneous operations. Scaling this to multiple threads is easy.
- All your PHP projects serve each request from a different thread, and you actually have to go out of your way to go into concurrency problems.
At this point, and after some tweaks to the codebase, and checking that all the DB operations are run through transactions, you should have a Monolith that can be deployed in multiple servers operating on the same database. You put a load balancer in front of them, and now your architecture can serve another order of magnitude of clients. Then you optimize the DB, put it on a beefier machine, and you can squeeze another order of magnitude of clients.
Hopefully, by this point, your systems should be serving so many clients that you can go to the next phase.
After growing, and growing, scaling the operations, scaling marketing, and sales, and billing, and scaling your Monolith again and again, it's now serving so many clients that your startup is making a significant chunk of money after paying your employees, infrastructure and investors. At this point, you won. You have a profitable business that makes significant money. It is not a scrappy startup anymore.
But you want more. You want to grow your business into a big business. So you never stop your growth phase. You continue hiring, growing and expanding.
At some point, your engineering team becomes so big (usually >30 engineers) that you start to see some recurring problems:
- The codebase is so big that none of your seniors have a decent grasp on how every subsection works.
- You are reaching the limits of your single database.
- Onboarding new team members becomes ridiculous because it takes a week to go over the basic details of your codebase.
- Specialists appear. On top of the usual frontend/backend/dbadmin, some of your frontend/backend/dbadmins start to become specialized in subsystems of the codebase, such as billing, accounting, and user intercommunication.
- As a result of this, communications become more and more expensive. You have 2 or 3 Project Managers full time, whose job is keeping the Engineers busy by ensuring each Engineer has the next task ready, and no Engineer is blocking (or about to block) other Engineers.
At this point, your cohesive engineering team is starting to fracture, and is starting to become several teams, each with some seniors, juniors, and a PM.
This is the point where Microservices may start to make sense. Microservices allows you to accept this fracture, and split several engineering sub-teams that are small enough to be cohesive.
Why don't we do Microservices before this happens?
Some people will say that at this point the software architecture is strangling the growth of the company, and it's too painful to do so late. They are wrong. Let's go again through the price of Microservices:
- Microservices complicates the deployment story
- Microservices complicates data consistency
- Microservices complicates hiring
- Microservices complicates software intercommunication
All these complications are hard to do when you are small. But there is a difference now: you are not small anymore. You can hire a DevOps (or two) to keep track of your deployment story. You can hire a couple of Distributed Systems Engineers so they can go full time at fixing your data inconsistencies. You can hire another pair of Engineers and put them full time to doublecheck APIs and API consumers so everything is properly checked. And, finally, you should have a decent HR team so that all this hiring, and onboarding, can be done.
At this point, you can afford Microservices. This is the difference.