Always start with a monolith
Like everything else in software development, microservices have trade offs. They can do much good, but they can also be harmful. How beneficial they are depends on the context they are used in.
I’ve seen microservices work well for an organization if:
- teams are stable and long lived
- there is a strong sense of ownership for services
- clear boundaries between teams and services exist
- people have enough slack time to practice new skills
- there’s already some kind of product/market fit
Of these five points, I feel that product/market fit is the most important one. A system that already has a decent amount of customers will less likely be exposed to big changes. After all, customers are expecting that the system continues to work for them.
A system that has little or no users, on the other hand, will probably have to change quite a lot. It’s quite likely that there’ll be major changes until the system finds some kind of product / market fit.
I’ve learned this lesson while working on a team that was asked to build a new system from scratch. The goal for the new system was to extend the capabilities of one of the company’s core products.
On the first glance, the team had everything necessary to make microservices work well for them.
The group’s managers had done everything to retain people and to keep teams stable. There was a strong sense of ownership paired with clear boundaries between the teams. Furthermore, developers in the group had enough slack time to practice new skills.
On the second glance though, the team was missing product/market fit. The team had reasons to believe that the new system would turn into an immediate success. But they did not know for sure.
The team believed that microservices would fit their environment perfectly, so they decided to build the new system as a set of microservices right from the start.
Unfortunately, two unexpected changes took place:
First, the product that the team was trying to extend ceased to exist. The company no longer thought they could win that particular market. So they decided to retire the product and reallocate resources.
Second, the group’s key management positions changed to different people. The new managers had different ideas about strategy and collaboration. As a result, teams got shuffled around frequently.
The team was still expected to complete work on the new system. Although they could no longer target the initial product, there was some hope that they could extend another product (in retrospect, everyone might have fallen for the sunk cost fallacy).
After these two changes, the team found itself in an environment where:
- teams were constantly in flux
- service ownership was handed forth and back between teams
- as a result of that, team and service boundaries blurred
- people were under constant pressure to find new consumers for the new system
Because of the new environment, the system’s microservice architecture turned out to be a really bad fit. The team could no longer benefit from microservices, but they definitely suffered from the drawbacks.
The team spent a majority of its time struggling with the complexities of distributed systems. The members had to deal with issues like handling retries, getting data to become eventually consistent, implementing a sensible backup strategy, or setting up a local dev environment, just to name a few.
What they spent very little time on was actual product development. Even making small changes required several weeks of effort. Changes had to be coordinated across multiple services. Data migrations had to be run across several data stores. As a consequence, the new system changed very slowly.
This was unfortunate, since the number one goal for the system was to find some kind of product/market fit. Nothing should have been more important than experimentation and fast feedback loops. Yet, the new system failed to support these goals.
Given the team’s environment, they would have been better off with a monolith.
That’s why I think that having some kind of product/market fit is quintessential for microservices to be successful.