Conventional wisdom counsels starting out with a monolith, but are there exceptions? I asked some top CTOs about their experiences to determine what to consider when making a decision between starting with a monolith versus using microservices straightaway.
My good friend Darby Frey recently kicked off a greenfield project after assuming his new role as Senior Platform Engineering Lead of Gamut. Despite starting out with monolith at his previous company Belly, he discovered that — in the right circumstances — starting with a monolith isn’t always the best way to go.
"As one does, I allowed much of my thinking in my early days [at my new company] to be influenced by my previous company," Darby told me.
"I was firmly a member of Team Monolith. [I thought] let’s build a single application and just pull things apart later if we start to feel pain." - Darby Frey
At Belly, Darby and his team broke down their monolith into a fairly large microservices architecture. They managed to get it to a good place, but only after months of trials and tribulations migrating to microservices.
With this experience fresh in his mind, he approached his new project at Gamut a bit more cautious of microservices.
While this was a greenfield project, Darby’s team was small, and he had aggressive timelines, so on the surface, a monolith seemed like the obvious choice.
"[But with this new project], I was anxious to not repeat the mistakes of the past."
And with that, he found himself faced with a decision we all struggle with, should we start with a monolith or microservices and how do we decide?
The terms monolith and microservices get tossed around a lot, but it’s important to remember that "System architectures lie on a spectrum," as Zachary Crockett, CTO of Particle told me during an interview.
"When discussing microservices, people tend to focus on one end of that spectrum: many tiny applications passing too many messages to each other. At the other end of the spectrum you have a giant monolith doing too many things. For any real system, there are many possible service oriented architectures between those two extremes." he explained.
Meaning of Monolith
A monolithic application is built as a single, unified unit. Often a monolith consists of three parts:
- server-side application
Another characteristic of a monolith is that it’s often one massive code base. Server side application logic, front end client side logic, background jobs, etc, are all defined in the same code base.
This means if developers want to make any changes or updates, they need to build and deploy the entire stack all at once.
A monolith isn’t a dated architecture that we need to leave in the past. In certain circumstances, a monolith is ideal. I spoke to Steven Czerwinski, Head of Engineering at Scaylr and former Google employee, to better understand this.
"Even though we had had these positive experiences of using microservices at Google, we [at Scaylr] went [for a monolith] route because having one monolithic server means less work for us as two engineers," he explained. This was back in the early beginnings of Scalyr.
In other words, because his team was small, a unified application was more manageable in comparison to splitting everything up into microservices.
Fewer cross-cutting concerns: a major advantage associated with monolithic architecture is that you only need to worry about cross-cutting concerns, such as logging or caching, for one application.
Less operational overhead: focusing your finances on one application means that there’s only one application that you need to set up logging, monitoring and testing for. A monolith is also generally less complex to deploy since you aren’t organizing multiple deployments.
Easier testing: with a monolith, automated tests are easier to set up and run because everything is under the same roof. With microservices, tests will need to accommodate for different applications on different runtime environments — which can get complex.
Performance: a monolith can also boast performance advantages in comparison to microservices. That’s often because a monolith uses local calls instead of an API call across a network.
Overly-tight coupling: while monoliths can help you avoid entanglement as previously mentioned, a monolith becomes more vulnerable to entanglement the larger it grows. Because everything is so tightly coupled, isolation of services within the monolith becomes arduous, making life difficult when it comes to independent scaling or code maintenance.
Harder to understand: it’s common to find that monoliths are more difficult beasts to understand in comparison to microservices, a problem which rears its head when on-boarding new team members. This is sometimes a direct result of the tight coupling, or perhaps dependencies and side-effects which are not obvious when you’re looking at a particular service or controller.
The developer community has done itself a disservice with the naming of this architecture. The problem is that that there is nothing inherently "micro" about microservices per se. While they tend to be smaller than the average monolith, they do not have to be tiny. Some are, but size is relative and there's no standard of unit of measure across organizations.
There is no industry consensus of what exactly microservices are. Nevertheless, here’s my take on the definition of microservices:
Microservice architecture refers to the concept of developing a single application as a suite of small services, in contrast to developing them as one, large ‘monolith.’
Each of those broken-up, individualized services run on their own process, communicating with lightweight mechanisms, often an HTTP resource API. Fully-fledged microservices are independently deployable, and yet can work in tandem when necessary.
Better organization: microservice architectures are typically better organized, since each microservice has a very specific job, and is not concerned with the jobs of other components.
Decoupled: decoupled services are also easier to recompose and reconfigure to serve the purposes of different apps (for example, serving both the web clients and public API). They also allow for fast, independent delivery of individual parts within a larger, integrated system.
Performance: under the right circumstances, microservices can have performance advantages depending on how they’re organized because it’s possible to isolate hot services and scale them independent of the rest of the app.
Fewer mistakes: Microservices enable parallel development by establishing a hard-to-cross boundary between different parts of your system. By doing this, you make it hard – or at least harder – to do the wrong thing: namely, connecting parts that shouldn’t be connected, and coupling too tightly those that need to be connected.
Cross-cutting concerns across each service: As you’re building a new microservice architecture, you’re likely to discover lots of cross-cutting concerns that you did not anticipate at design time. You’ll either need to incur the overhead of separate modules for each cross-cutting concern (i.e. testing), or encapsulate cross-cutting concerns in another service layer that all traffic gets routed through. Eventually, even monolithic architectures tend to route traffic through an outer service layer for cross-cutting concerns, but with a monolithic architecture, it’s possible to delay the cost of that work until the project is much more mature.
Higher operational overhead: Microservices are frequently deployed on their own virtual machines or containers, causing a proliferation of VM wrangling work. These tasks are frequently automated with container fleet management tools.
Although it’s important to have a general sense of the pros and cons of monoliths and microservices, knowing those doesn’t necessarily guide decision-making. To help with that, I asked dozens of CTO’s that have made this decision how and why they made the decision they made. Distilled below are several key considerations you should make when deciding for your own organization.
Consideration #1: Are you in familiar territory?
Darby and his team at Gamut were able to delve directly into microservices because he had experience with eCommerce platforms, and his company had a wealth of knowledge concerning the needs and demands of their customers. If he was traveling down an unknown path on the other hand, a monolith may have actually been the safer option.
Often startups are born out of pains experienced at previous companies. In those scenarios sometimes it’s quite clear scaling is going to be a primary requirement, especially in infrastructure based services like cloud log management.
Consideration #2: Is your team prepared?
Does your team have experience with microservices? What if you quadruple the size of your team within the next year, are microservices ideal for that situation? Evaluating these dimensions of your team is crucial to the success of your project.
Julien Lemoine, CTO at Algolia, chimed in on this point:
"We have always started with a microservices approach. The main goal was to be able to use different technology to build our service, for two big reasons:
1) We want to use the best tool for each service. Our search API is highly optimized at the lowest level and C++ is the perfect language for that. That said, using C++ for everything is a waste of productivity, especially to build a dashboard!
2) The want the best talents and using only one technology would limit our options. This is why we have different languages in the company."
If your team is prepared, starting with microservices is wise as it allows you to get used to the rhythm of developing in a microservice environment, right from the start.
Consideration #3: How’s your infrastructure?
In reality, you’re going to need cloud-based infrastructure to make microservices work for your project.
"[Previously], you would want to start with a monolith because you wanted to deploy one database server. The idea of having to set up a database server for every single microservice and then scale out was a mammoth task. Only a huge, tech-savvy organization could do that," David Strauss, CTO of Pantheon explained to me.
"Whereas today with services like Google Cloud and Amazon AWS, you have many options for deploying tiny things without needing to own the persistence layer for each one."
Consideration #4: What’s your business risk tolerance?
"Every time we consider introducing a new service, we have to consider the operational cost of doing so. Each new service adds to the complexity of the infrastructure and makes it a bit harder to reason about service relationships within the system." — Oleksiy Kovyrin, Head of Swiftype SRE, Elastic
You may think microservices is the "right" way to go as a tech-savvy startup with high ambitions. But microservices pose a business risk. David Strauss explained:
"A lot of teams overbuild their project initially; everyone wants to think their startup will be the next unicorn and that they should, therefore, build everything with microservices or some other hyper-scalable infrastructure. But that's usually wrong, almost all the time," he said.
One example of this from his early days at Pantheon was a system that was limited to a single VM. They thought it would be a month or two until they’d be forced to scale it. It ended up being over a year — and they ended up scaling it a completely different way than they had anticipated.
He went on to say that, in these cases, the areas that you thought you needed to scale are probably not the parts that will need to scale first, and that results in misplaced effort even for the systems that will need to scale.
Context, context, context
"Know thyself" is a crucial mantra for teams looking to make a decision about microservices versus a monolith. Through trial, error, and success, CTOs described what worked best for them given their specific context, and I’ve distilled this into scenarios that indicate that you should strongly consider one architectural approach over another.
When to start with a monolith
Your team is at founding stage: Your team is small, between 2-5 members, and is thus unable to tackle a broader and high-overhead microservices architecture.
You’re building an unproven product or proof of concept: Are you building an unproven product in the market? If it’s a new idea, it’s likely going to pivot and evolve over time, so a monolith is ideal to allow for rapid product iteration. Same applies to a proof of concept where your goal is just to learn as much as possible as quickly as possible, even if you end up throwing it away.
You have no microservices experience: If your team has no prior experience with microservices, unless you can justify taking the risk of learning "on the fly" at such an early stage, it’s likely another sign you should stick to a monolith to start.
When to start with microservices
You require quick, independent service delivery: If it’s snappy, isolated service delivery that you need, microservices are your best bet. However, depending on the size of your team, it can take some time before you see any service delivery gains versus starting with monolith.
A piece of your platform needs to be extremely efficient: If your business is doing intensive processing of petabytes of log volume, you’ll likely want to build that service out in a very efficient language (i.e. C++) while your user dashboard may be built in Ruby on Rails.
You plan to scale your team: Starting with microservices gets your team used to developing in separate small teams from the beginning, and having teams separated by service boundaries makes scaling your development organization easier.
Do not attempt to take on microservices just because other engineering teams are having success with them or because microservices seem like a hot topic. Your own context, evaluated against the above considerations, is the key to deciding if you should start with monolith or microservices.
For more content like this, check out our free eBook, *Microservices for Startups*.