In the previous article on microservices I was fairly negative, but mentioned in passing that I have observed some benefits, too. Several readers have been curious about these. There are two important benefits I’ve come across so far that seem unique to a small service-based design.
- Shorter cycle times, and
- Components that are fundamentally different can be handled differently in operation.
Services lead to shorter cycle times
At my current employer1 The one with the microservices., I see someone deploying a new version of a service about every 10–20 minutes. At my previous employer2 The one with the monoliths., I had to fight an uphill battle to introduce even daily deployments of one of the most fast-moving products. The slowest moving product had in effect twice-a-year deployments.3 Which is a shame, because that was also the most innovative product that could benefit a lot from shorter cycle times!
“Okay”, I hear you say, “But that’s just a culture difference between two organisations, and not inherent to monoliths/microservices.”
Let’s look more closely. The monolith/microservice distinction is not a dichotomy, but a continuum between large and small independently deployable units. What I’ve oberved in every organisation so far is that the binary size of a deployment strongly correlates with how much time passes between when a change is approved and when it hits production. In other words, even within a single organisation, the larger … things just seem to deploy more slowly.
I don’t know why that happens, but it consistently does.
Besides, there’s another way microservices promote shorter cycle times: the clear service boundaries, combined with separate repositories for each service, force commits to be small. An atomic change can only affect one service, because there’s no way to make cross-repo commits. In some way, this might be one of the biggest benefits I’ve come across so far, because I know how tempting it is to bunch a couple of unrelated changes into the same commit.
Services allows components to be handled differently
One of the monoliths I worked on had a component that was very state-heavy.4 Actually, that’s selling it short – one of the components of that product was an in-memory database. It would have been very nice to be able to treat just that component differently in production to all the nearly-stateless stuff that was running alongside it. Alas, it was a monolith that baked both together5 Ostensibly for performance reasons, but I think that was more of an engineering challenge than a physical limit.
In particular, it was painful to restart the product because then the stateful part needed to be re-populated with data and re-compute views into that data, and for some customers it was a lot of data. This contributed to a low frequency of deployments.
Further, it is nice to be able to change the configuration of components6 Including upgrading them. independently when they are somewhat independent. This reduces the surface area that has to be examined when something goes wrong to just those things which actually changed in recent history. This is opposed to the monolith where everything is deployed in one big bang, including very stable code that hasn’t changed for a year or two.