Microservices in an early-stage company is a huge mistake
The microservice architecture is a good solution. When you are a large company, with multiple teams, working on independent and well-defined domains.
But if you're an early-stage company, it's a mistake to use this architecture to build your product.
And still, there are early-stage companies that decide to use microservices anyway.
Early-stage companies must move fast to survive. Ship features and get feedback from customers. Ideas and features change from one week to another. There's no clear domain or boundaries at this stage.
It's not hard to understand why engineering teams get tempted to use microservices. The technical media coverage is always talking about it. About how "Big Company" used a microservice architecture to scale.
But the thing is: your early-stage company doesn't have the same problems as the "Big Company".
The Marketing team doesn't copy the "Big Company" strategy, nor does the Finance team. Then why should the Engineering team copy it?
What is a microservice?
Microservices are small, autonomous services that work together. Each service runs in its own process and communicates with other services through well-defined APIs. Microservices are built around business capabilities and are independently deployable by fully automated deployment machinery — Sam Newman, Building Microservices: Designing Fine-Grained Systems.
The idea of "small, autonomous services that work together" is appealing.
Let's expand the meaning of "small, autonomous":
- Each service is self-contained and should implement a single business capability
- Each service should be independently deployable
- Each service should own its own data storage
- The communication between services should be lightweight and stateless
- Services can be developed, deployed, and scaled independently
Why microservices are a mistake for early-stage companies
Imagine that you are building a new SaaS product. You have a team of 5 software engineers. The team decided to use the microservice architecture. They split the product into 5 services:
Each service has its own project, database, and deployment pipeline.
The workflow of account creation after a user submits the form looks like:
Authservice receives the request
Authservice creates the user in its database
Usersservice receives the request
Usersservice creates the user in its database
Notificationsservice receives a request
Notificationsservice uses a 3rd-party to send the welcome email.
Notificationsservice stores information in its database.
Lots of stuff happening, hun?
A simple feature requires a team of 5 people to:
- Change 3 projects
- Deploy 3 projects to a test environment
- Deploy 3 projects to a production environment
- Migrate 3 databases in a test environment
- Migrate 3 databases in a production environment
- Ensure there's data consistency between the 3 databases
Lots of effort. Solid ground for bugs.
And with no benefit to your business.
Here are the reasons why microservices are a mistake for early-stage companies:
They slow down development
As the example above shows, even a simple feature requires changing multiple projects. To test these changes, the team must set up all projects on their machines. Not only the projects but also the infrastructure that comes with them.
That's a high premium to pay for a small engineering team.
They are more prone to bugs
Each service has its own database. There's no single source of truth. And keeping data consistent between all services is not trivial.
Databases have mechanisms to ensure data consistency: transactions. When each service uses its own database, it's not possible to rely on database-level transactions.
If the team forgets to update one of the services, the data will be inconsistent. And data inconsistency leads to bugs.
Using our previous example, if the
Notifications service fails to store it has sent the welcome email, the user might receive the email again.
This example is annoying, but it's not the worst case.
Imagine data inconsistency between the
They are expensive
Your simple MVP with 5 services will require the engineering team to:
- Create 5 projects in a source control system
- Create 5 databases (for production) and 5 databases (for testing)
- Configuring the servers for 5 projects (in production) and 5 projects (in testing).
Good teams will invest time to automate these tasks. And automation helps to run these things faster. But that means the team is working on tools instead of features. Fine for a large company with many teams. Not fine for an early-stage company.
And that's just the beginning.
I'm not covering here the time spent working on:
- API Gateways
- Load balancers
- Caching layers
- Message buses
- Full-text search
The approaches that make sense for large companies, are often the exact opposite ones that’ll make sense for you.
I hope that by now you're convinced the microservice architecture is not a good fit for early-stage companies.
The microservice architecture solves a problem that early-stage companies don't have.
So, what's the alternative?
The monolith is an architecture where all the different components of an application are in a single codebase. Everything is in one place.
It doesn't mean everything is mixed together.
An engineering team can build a modular monolith. With clear boundaries between the different components.
The components of the monolith access the same database. That enables it to benefit from database transactions and constraints to ensure data consistency.
As a monolith, the entire codebase is started and stopped as a single unit. It simplifies running it in local machines, as also reasoning about the codebase.
When adding new features to a monolith, the team can collaborate on changing the same project and testing things together.
A well-designed monolith can even support an eventual migration to microservices. If the business needs it.
Starting a new product with a monolith help an early-stage company to:
- Have speed to launch new features
- Invest time building features, not operational tools
- Reduced risks to introduce bugs in the product
- Less effort to test the product
- Save money, since it is a fraction of the costs of running multiple services.
A complex system that works is invariably found to have evolved from a simple system that worked. A complex system designed from scratch never works and cannot be patched up to make it work. You have to start over with a working simple system — John Gall, The Art of Systems Architecting.
I'm used to hear people saying that microservices are the solution to all problems. And that's not true.
Here are some of the most common arguments I hear:
Microservices is the only way to decouple your application
Not true. Monoliths can be decoupled too. Experienced teams can design a monolith that is easy to change. And benefit from well-known design patterns.
Small teams can work on microservices
Well, yes. But that's not the point. The amount of time spent on infrastructure and operations is insane. It might become the team full-time job.
We use Serverless, it means we already have microservices
No. You can use Serverless to build microservices. But you can also use Serverless to build monoliths.
We have multiple projects, it means we already have microservices
No. If all your projects share the same database, it's not a microservice. It's a distributed monolith. (And that's an even worse scenario).
Monoliths do not scale
Not true. Monoliths scale. Ask GitHub and Shopify.
Migrating from Monolith to Microservices is impossible
Not true. A team can split a modular monolith into microservices. Both can even coexist for a while.
Are you still not convinced?
That's fine. Feel free to contact me me. I would love to hear your thoughts and discuss your challenges.
How to Avoid Costly and Time-Wasting Mistakes when building softwaredecisionpragmaticmistakesnot-invented-here
Engineering teams make decisions that dictate whether a project takes 12 or 3 months to launch, or costs $300.000 instead $30.000 to achieve the same outcome. Here are the decisions responsible for slow and costly software development...