Table of Contents
In many ways, having an existing codebase you want to decompose into microservices is much easier than trying to go to microservices from the beginning.
Microservices refer to a type of software architecture where the application is decomposed into many smaller applications that each focus on a single business domain. These services usually have their own database, their own server running the service, their own metrics, etc. This way, the services are decoupled from each other and engineering teams can be autonomous developing and specializing in one business domain.
Microservices are a popular architecture for applications that need to scale for huge numbers of users. Companies like Amazon, Netflix, and many others are using a microservice architecture in order to handle the scale that their business demands. When successful tech companies utilize microservices for their business, it's tempting to think your company should adopt a microservice architecture as well. You might be thinking, "microservices are working well for major tech companies, so surely microservices are a good architecture for my company."
Maybe. Maybe not. It depends on the scale of your company, how many users you need to service, and how much engineering effort you can invest. In the rest of this article, I will explain when I think you should avoid using microservices and when you should adopt them.
Programmers waste enormous amounts of time thinking about, or worrying about, the speed of noncritical parts of their programs. These attempts at efficiency actually have a strong negative impact when debugging and maintenance are considered. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil.
If you are an early-stage startup (e.g. have not received funding) and you are still building an MVP, then you may want to develop your application as a monolith instead. By nature, microservices are distributed systems, and distributed systems can be extremely complex to reason about, configure, and manage. When adopting a microservice architecture, you will have to think about the following:
- Business logic— To interact with different features, services must interact using interprocess communication (IPC) protocols such as REST or gRPC. You'll need to set up service discovery so your services can know how to communicate with each other over the network.
- Transactions— You need to figure out a story for managing transactions across multiple services that each have their own database. You can use the Saga pattern but cannot guarantee ACID transactions for transactions that span across multiple services.
- Infrastructure— For each service, you'll need to configure and manage infrastructure such as a local database, compute, metrics, etc.
On the other hand, a monolithic application has its code in one place. When you're able to count the number of people developing the application on one hand, I think you'll find it much easier to reason about a monolithic architecture. In contrast with microservices, when adopting a monolithic architecture, you'll need to think about the following:
- Business logic— Interacting with different features can mostly happen locally within the scope of the application via method calls.
- Transactions— You can provision a single ACID-compliant database to handle transactions if that's what your application needs.
- Infrastructure— You only need to provision infrastructure for a single monolith application.
I don't know about you, but I think the monolithic approach sounds easier. When you are an early-stage startup, you usually have a small team working on your application. You probably want to iterate fast so that you can get to market quickly. Adopting a microservice architecture too soon can lead to spending too much time optimizing for the chance that your application needs to scale.
My suggestion for your early-stage startup is to work fast. Don't worry about trying to overoptimize everything from the beginning. You should be working on getting a product in the hands of your users and investors. Once your company has funding, a larger engineering team, and many users, then you should probably think about migrating your monolith into microservices.
Let's say your company gets funding, your applications has many users, and you have grown your engineering team substantially. This is the time you may want to seriously consider converting your monolith into microservices.
This does not mean you need to completely rewrite your application from scratch in order to adopt a microservice architecture.
The only thing a Big Bang rewrite guarantees is a Big Bang!
Write new features as services so that the size of the monolith application remains static. In doing so, you create a Strangler application to help transition into the new architecture. Over time, engineering effort can break apart the monolith into microservices, little by little, until the monolith is no more. Then, your company can reap all the benefits of a loosely-coupled microservice architecture.
Microservices are great for splitting your application into modular application services that engineering teams can develop autonomously. The problem with microservices is they are naturally more complex to manage. For early-stage startups building an MVP, adopting a microservice architecture could slow down development, and a monolithic architecture would probably help you get to market faster.