Well, it depends…
There comes a point in every technology company’s life cycle where the conversation matures from ground floor concerns centered around “making it work” to bigger picture, architectural questions, focused on “building it to scale.” There’s no precise moment, or any specific markers of company size or stage, that launches every senior engineer in the organization into debates about a monolith versus microservices architecture, but it’s bound to happen — when things start to break.
I sat down with my colleague, Manil Gaouar, a principal software engineer with nearly two decades of experience, to explore the pros and cons of these overarching software architecture and design decisions. Here, I’ve laid out the key take-aways from our conversation.
First things first, let’s define what a “monolith” is.
A monolith, sometimes called a “mono-repo,” is effectively a single backend codebase. Because you’re deploying one backend, which contains all of the necessary request/response payloads and database connections in one spot, it is almost always simpler to code, and easier to maintain. For this reason, “monolith” is the default architecture option for a great majority of apps.
What are microservices, then?
The simplest way to visualize a microservices architecture is to imagine taking a hammer to a monolith codebase and breaking it up into a bunch of little pieces.
These independent, and separately deployed, codebases are called “services” because they are subdivided by their individual functionalities. In designing a microservices architecture, it’s important to stay true to software design’s “Single Responsibility Principle,” and ensure that each “micro” code repository handles a single task, or domain. Some examples of common microservices are authentication (sign-in/log-in), payments, and order processing.
These broken-up services are then glued back together via communication protocols, such as standard HTTP, message-based Simple Notification Service (SNS), or event-driven Publish/Subscribe messaging.
As you might suspect, a microservices architecture requires more upfront design, better planning, and more experienced engineers to handle the added complexity. For a comedic take on what that ball of yarn can look like, check out this funny skit of an exasperated software engineer trying to explain to a product manager why adding a birthday field could take him years:
So, why would you do it?
The idea is that the sum is greater than its parts. When you split a codebase up into pieces, you can reuse and extend those siloed services across different products. The most common use case for this is the authentication workflow. Presumably, your entire suite of tech products will need users to log-in, so, instead of bloating a single codebase by adding each new product or feature into it as an ever-expanding set of subfolders, or even worse, copy-pasting the authentication code and all of its broken dependencies into new product codebases, you’d simply and cleanly call the authentication microservice that’s maintained, tested, watched and secure.
What’s more, you don’t have to build your entire codebase in one coding language, database or framework. If the data engineers say Python is more performant, they can use it! The payments team loves NestJS? No problem. As for databases, microservices should have their own database, so each services team can clean and control their own tables, too.
And, how do you do it?
Collecting each shattered and glued-back piece of a monolith requires coordination. To pull off an organized deployment, orchestration technologies like containers are a must, says Manil. Docker, Kubernetes and Amazon ECS are the trifecta for container orchestration, but be warned, these tools are not just buzzwords. Without a mature DevOps process and IT infrastructure in place, container deployment, load balancing and networking will not go off without a hitch.
But, what could go wrong?
Besides production outages and developers losing their mind, the biggest risk of a botched microservices attempt is…the company bleeds cash. Most often, startups start out as monoliths, until they outgrow it, and, as Manil puts it, “the system becomes really hell.” This means microservices architectures are usually re-designs of an existing system, and companies have to go through a transition phase, where, yes, they are maintaining two sets of the same code. The old, monolith system will usually be running in production, so customers don’t experience any disruptions, while the microservices are built. It’s crucial that this overlap time is as short as possible, and, according to Manil, lasts a maximum of six months. If two systems are running concurrently for too long, things have to be implemented twice, data has to be synced and stored, and two groups of engineers have to do the same work. In Manil’s words, “the resource tax is high,” but in my words, that sounds ex$pen$ive.
Still, don’t let that scare you off.
An investment in a well-implemented microservices architecture can build a strong, long-term technical foundation for any company. But, you probably shouldn’t do it if you‘re in a big rush. This isn’t a bandaid solution, and the most important factor in its success is, as usual, “a team effort and management’s support.”