Swizec Teller - a geek with a hatswizec.com

Senior Mindset Book

Get promoted, earn a bigger salary, work for top companies

Senior Engineer Mindset cover
Learn more

    What microservices are for

    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.

    Example of concern-based architecture
    Example of concern-based architecture

    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:

    Control flow to add a comment
    Control flow to add a comment

    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.

    Turning modules into microservices
    Turning modules into microservices

    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 :)

    Published on May 13th, 2022 in Microservices, Architecture, Spaghetti, Backend

    Did you enjoy this article?

    Continue reading about What microservices are for

    Semantically similar articles hand-picked by GPT-4

    Senior Mindset Book

    Get promoted, earn a bigger salary, work for top companies

    Learn more

    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 ❤️

    Created by Swizec with ❤️