Microservices are a pain in the ass. They turn every system into a byzantine mess of complexity. But this week ... they saved my butt.
You'll see people talking about how microservices enable scale. They do. But not scale in a computer performance sense! Microservices are worse for performance. They're about scaling teams!
The ultimate evolution of Conway's Law
Any organization that designs a system (defined broadly) will produce a design whose structure is a copy of the organization's communication structure ~ Melvin E. Conway
Microservices take that idea and say "Yeah that sounds great!". You take your teams, give each a small subsystem to maintain, make them talk through APIs, and hope for the best.
You get systems like this:
Look why is this taking 3 years? It's not that simple! Fills whiteboard with incomprehensible scribbles of all the services required to make a login button.
😅
Makes you pine for the good old monolith days.
Microservice vs Monolith
A well-structured monolith will get you far. But the discipline to keep a monolith well-structured ... oof.
"The code is right there! Why can't I just use it 😩" ~ me, every time
You start a monolith with some sensible design. Fat controllers, fat models, fat services, fat components. Somewhere in your code lives The Business Logic and everything else calls that.
Sliced based on areas of concern. Fantastic. The User
module has functions to handle users, the Article
module for articles, and Comment
for comments.
The control flow to add a comment goes like this:
You call addComment
on the Comment
module and it talks to the Article
module to get the article and check if comments are enabled. Then it talks to the User
module to get the commenter and check if they're allowed to make comments. Finally it writes the comment.
Looks sensible as code:
async function addComment(...) {
const article = await getArticle()
if (commentsEnabled(article)) {
const user = await getUser()
if (authenticatedToComment(user)) {
await writeComment()
}
}
}
Here's an important question: where does the commentsEnabled
function go? Is it more of an article concern or more of a comments concern. 🤔
Same for authenticatedToComment
.
The answer almost doesn't matter in a monolith. You can import * from 'Articles'
inside Comments and vice-versa. Call the function and VSCode will find where to import it from.
Throw everything on a pile, let computers do the searching.
Microservices force the decision
In a microservice world, those modules live on separate machines. Different repositories even.
Each of those cross-module calls turns into an API request. With all the necessary error handling
async function addComment(...) {
let article
try {
article = await getArticle()
} catch (e) {
throw new Error("Failed to get article")
}
if (commentsEnabled(article)) {
let user
try {
user = await getUser()
} catch (e) {
throw new Error("Failed to get user")
}
if (authenticatedToComment(user)) {
await writeComment()
}
}
}
Getting the user and article isn't just a function call anymore. It may fail at any time for any reason. You have to handle errors.
It's an order of magnitude slower as well. Even the fastest API call on a private network takes a few dozen milliseconds. A comparable function call is measured in nanoseconds.
Suddenly it really matters where you put commentsEnabled
and authenticatedToComment
. Are they an API call to the Article and User service, or a local function call? 🤔
I don't know the answer, all I know is that microservices force the conversation. And that's a good thing.
This week microservices saved my butt
Aside from forcing the conversation about your architecture, microservices excel at one other thing 👉 partial deploys.
That's what saved my butt this week.
At work we're in a distributed monolith world. The worst of both worlds as we transition from full monolith to full microservice. The hard part is cleaning the concerns between modules.
Because of this micro-but-not situation we have to Deploy The World regularly. You never know if a feature is going to work unless everything's deployed together 😅
I did the deploy and assumed all was fine. As it was the last 20 times.
Then the Product Owner slacks me "Hey Swiz I can't login"
Ah shit ... dig into logs, find the only new commit on auth-service
. Suspicous! No idea what the commit is doing or how. Rollback that one little service and voila the system comes back 🥳
To make it even more fun: another service failed to deploy at all. And everything was fine
Deploy a bunch of things, one fails, one gets rolled back, and everything is fine. That's what microservices are for.
Cheers, ~Swizec
PS: an issue that makes my User-Article-Comment example tricky is that it's based on object oriented ideas of entities. Imagine if the architecture was instead sliced by task – actions users want to achieve. I once called that The Magic Function Principle, but that doesn't quite fit. Noodling continues :)
Continue reading about What microservices are for
Semantically similar articles hand-picked by GPT-4
- You don't need a big team to automate your work
- That time serverless melted my credit card
- Finding modules in a big ball of mud
- How JAMStack helps you ship
- The Italian foods theory of bad software design 🍝
Want to become a Serverless and modern Backend expert?
Learning from tutorials is great! You follow some steps, learn a smol lesson, and feel like you got this. Then you go into an interview, get a question from the boss, or encounter a new situation and o-oh.
Shit, how does this work again? 😅
That's the problem with tutorials. They're not how the world works. Real software is a mess. A best-effort pile of duct tape and chewing gum. You need deep understanding, not recipes.
I've been building web backends since ~2004 when they were just called websites. With these curated essays I want to share the hard lessons learned. Leave your email and get the Serverless and Modern Backend email series.
Curated Serverless & Backend Essays
Get a series of curated essays on Serverless and modern Backend. Lessons and insights from building software for production. No bullshit.
Have a burning question that you think I can answer? Hit me up on twitter and I'll do my best.
Who am I and who do I help? I'm Swizec Teller and I turn coders into engineers with "Raw and honest from the heart!" writing. No bullshit. Real insights into the career and skills of a modern software engineer.
Want to become a true senior engineer? Take ownership, have autonomy, and be a force multiplier on your team. The Senior Engineer Mindset ebook can help 👉 swizec.com/senior-mindset. These are the shifts in mindset that unlocked my career.
Curious about Serverless and the modern backend? Check out Serverless Handbook, for frontend engineers 👉 ServerlessHandbook.dev
Want to Stop copy pasting D3 examples and create data visualizations of your own? Learn how to build scalable dataviz React components your whole team can understand with React for Data Visualization
Want to get my best emails on JavaScript, React, Serverless, Fullstack Web, or Indie Hacking? Check out swizec.com/collections
Did someone amazing share this letter with you? Wonderful! You can sign up for my weekly letters for software engineers on their path to greatness, here: swizec.com/blog
Want to brush up on your modern JavaScript syntax? Check out my interactive cheatsheet: es6cheatsheet.com
By the way, just in case no one has told you it yet today: I love and appreciate you for who you are ❤️