In Defense Of Microservices Architecture
These days I have read too often that microservices architecture is an unnecessary and over-complicated trend companies don’t need at all.
The reasons use to be related to complexity, especially in communications and asynchronicity. The claim “what your company needs is productivity and value delivering” has been listened to very often.
Is microservices architecture actually hype, another excuse for developers to learn new things regardless of what is better for the company?
Microservices architecture in opposition to a monolith architecture approach
One of the most usual attacks to a microservices architecture is in comparison to a monolith-based one. People look for complex things in the former to then affirm this is easier in the latter: microservices require more complex infrastructure, it use to depend on a more asynchronous approach, context mapping is hard, domain definition gets tough, etc.
But, aren’t these dependencies a microservices architecture have only related to this architecture trend, or are they actually dependencies of any good development project?
Should we think these developers are not using any SOLID in their monoliths? And, if they are not using any SOLID, aren’t they having any problem at all? It’s hard to imagine.
So, when they say “microservices architecture needs a very complex infrastructure”, isn’t the monolith-based infrastructure a microservices infrastructure for only one microservice? Aren’t autoscaling, logging, queues, or databases a thing for a monolith-based architecture?
When we talk about asynchronicity, aren’t monoliths using queues for long-living processes, aren’t they using circuit breakers for calling external services, aren’t they using context mapping to map information from the monolith to the external services domain models they use?
And, for God's sake, aren’t monolith developers trying to understand the domain to build a good representation of the real-world concepts involved in their business?
Developing microservices is hard. Developing a good monolith is hard too.
Developing microservices is hard. As you have many services communicating between them and out to the world, you need to ensure this communication is happening optimally.
You can do this in two ways -the most important ones, at least:
- Synchronously: you just call the service and wait for the response. What happened if the receiver is down? You need to fix this situation, and a circuit breaker uses to be the answer.
- Asynchronously: you send a message to a queue, and one or more daemons are listening for these messages. You can suppose things gonna be fine in an undefined time in the future. If your messages can be executed in any order and they are also idempotent -they can be executed many times- you have the previous scenario -a service down- fixed because you can process again the message when the service is up again or the bug has been fixed.
Both cases are complicated. In the first one, you need to manage all the possible paths a user can arrive at, and give an acceptable response; also, build the necessary stuff to avoid losing any information when a service call fails. In the second one, you need to manage the asynchronous operation, and this means having monitoring for daemons, deadlock queues, etc; also, you need to architecture the platform to communicate throw messages that should don’t rely on any order and being able to be executed more than one time.
The other hot topic is context mapping. As a microservice is, per se, a bounded context, you cannot share any aggregate, VO, or whatever with other microservice.
Let’s put an example: you have a football manager software. You have players, and you have users that use the platform. Let’s say you have two microservices: auth and football. In auth, you have a User aggregate, which has name, surname, username, password, etc. In football, you have a Player aggregate, which has name, surname, height, weight, team, etc. Moreover, let’s say some players have access to the platform as users. Do you see it? The name and surname are common information in both microservices. Is the very same information. You need some way to sync information between both microservices. And you need to map id’s to know that the user with ID 1 is the player with ID 32 -you can use the same IDs to avoid having the context mapping, but let’s imagine you don’t. The example could be more complicated, having more microservices.
To manage this kind of situation in microservices you have to trigger information changed events when a field is changed, and then listen to events and process it to update information in other microservices. This is tough, and there are corner cases you need to fix.
There are other complicated things when you are developing microservices, like infrastructure, that these days use to be docker images in a Kubernetes cluster. But the two topics below are, in my opinion, the more complex ones.
So, yes, developing a microservices architecture is hard enough. But…
It’s 2021. Years ago, the “Twelve-Factor App manifesto” was the new thing, the architecture good software aspired to. But, as I said, it’s 2021, and now Twelve-Factor is the bare minimum.
Even monoliths are now communicating to external services like CRM’s, media storage systems, social network APIs, etc. What happens when we communicate with these services? The very same thing I told you below. You need to do it synchronously or asynchronously, with the same problems and the same solutions. You also need context mapping to relate your aggregates with the external services aggregates. You need to sync information.
You need to have very good developers to develop a good microservices architecture. So you need for a good monolith. If we compare bad monoliths with good microservices we will always find it easier to develop monoliths.
So, what is all this noise about microservices, all this hate?
Wouldn’t be the problem that we are comparing very under-developed monoliths to microservices, so monoliths need many of the dependencies of a microservices architecture but they have just ignored it?
Wouldn’t be the problem that some teams try to develop microservices from a very bad monolith as a silver bullet, but with the same actual knowledge that built the failed monolith, so they fail and blame the microservices architecture?
Built your software using an architecture you are good in. Your knowledge and ability will decide whether the result is good or bad, no matter the architecture you chose.