Stop Using Microservices. Build Monoliths Instead.
Published on by Mirko TFX, mirko.krstic@tallyfox.com
Microservices can seem like the perfect solution.
In theory, they increase development speed while allowing you to scale different parts of your app independently.
But in reality, microservices come with hidden costs. That said, I don’t think you can truly appreciate their complexity without building them firsthand.
Here is what I learned building (and sometimes failing) with microservices.
Managing Data Is a Nightmare
Keeping data in-sync across microservices can be challenging.
A database per microservice is the recommended pattern. It allows loose coupling and permits service-specific teams to function independently without slowing down to collaborate on a shared code.
But what happens when one of two microservices that are supposed to fire in sync fails? For instance, one of those microservices updates its database but the other does not.
Situations like this create inconsistencies in data.
From personal experience, investigating data inconsistencies across services can be painful. The cross-service nature of the error requires a person to work across multiple services to rectify the error. Unfortunately, this then invalidates one of the benefits of microservices to begin with — team-specific services.
The same situation in a monolithic app could have easily been prevented by wrapping both DB calls in a single atomic transaction, so all inserts succeed or none of them do. Easy peasy.
But with microservices, loose coupling makes that more difficult.
More Time Setting Up
Building out a microservices architecture takes longer than rolling the same features into a monolith.
While an individual service is simple, a collection of services that interact is significantly more complex than a comparable monolith.
Functions in a monolith can call any other public functions. But functions in a microservice are restricted to calling functions in the same microservice.
This necessitates communication between services. Building APIs or a messaging system to facilitate this is non-trivial.
Additionally, code duplication across microservices can’t be avoided. Where a monolith could define a module once and import it many times, a microservice is its own app — modules and libraries need to be defined in each.
Microservices Work Best for Large Teams
The luxury of assigning microservices to individual teams is reserved for large engineering departments.
Although it’s one of the big touted benefits of the architecture, it’s only feasible when you have the engineering headcount to dedicate several engineers to each service. Reducing code scope for developers gives them the bandwidth to understand their code better and increases development speed.
But most startups don’t have this luxury.
In an early-stage company without sufficient resources, some engineers will need to work across all services.
Unfortunately, this reduces productivity because jumping across apps can be a serious switch of context.
I found that investigating bugs in microservices I hadn’t worked on in awhile was exhausting.
DevOps Is More Complicated
One of the most compelling reasons for choosing microservices is the ability to run different services on different types of servers.
Why? A React frontend can have very different memory, CPU, and up-time requirements than a service that trains machine learning models. The right type of infrastructure for each service can drastically lower costs.
But it comes with its own challenges.
Case in point: Early in my career, I once lost a tonne of production data because I forgot to restart a service on which I’d updated code. The outdated code received data via API requests, but then silently failed instead of recording it in its database. That data was lost forever.
I give this point to illustrate that it’s more work to configure, maintain and monitor multiple microservices compared to a single monolithic app. Having multiple apps also increases the attack vector for hackers.
In theory, “loosely coupled” services allow each service to continue functioning if others fail. But that’s wishful thinking —true loose coupling is rarely possible for a complex business with customers.
In the end, your app architecture is only as reliable as the weakest piece. The more moving pieces, the more chance for error.
Taxonomy
- Software & Services
- Web Development
- Enterprise Software
- Cloud Solutions
- Networking Solutions
- Enterprise Services
- A/D converters
- All In One
- Blockchain
- Documents Pursuant to NEPA and CEQA
- Master of Arts in Development