Servers as Factories - a simple metaphor for thinking about web servers
Date: 2024-01-02 | create | tech | software | system-design | server-as-factory |
A good metaphor allows you to compress an idea such that you get a lot of leverage out of a little information. Software can often be hard to reason about because it seems to live under different rules than we're used to, thus making it hard to intuit.
In my years working as a software engineer I've seen many odd software decisions / conclusions that seem to be built on false assumptions about how software works. This is bad but it can be very hard to explain why these decisions are wrong without shared context on foundational assumptions.
So in this post we're going to explore a metaphor I've been toying with for thinking and reasoning about software servers - factories. I think it works pretty well and can serve as a 3S (Simple Scalable System) we can build on for further explorations of software principles.
Q: What is a good metaphor for thinking about software servers and their functions / constraints?
Answer
In this post we're exploring the metaphor of a Server as a Factory. It's a pretty minimal metaphor that has a lot of overlap across these domains and thus I believe works well for exploring many different scenarios.
A Server is a Factory
In many ways a server is just a digital factory. We need something done, so we build some infrastructure to do it efficiently.
In its simplest form, a factory simply takes inputs and produces outputs. Servers running software are the same - just the inputs / outputs are usually virtual rather than physical.
- Factory - Takes in raw materials, uses Workers to fulfill orders based on set recipes, and marks the outputs for delivery
- Server - Takes in raw data, uses Threads to fulfill requests based on set business logic, and schedules the outputs for delivery
We most often enlist Factories when we need to do things at scale. Some factories make raw materials, others use those materials to create complex Items, and still others just organize those Items for later distribution.
Servers are similar. If we can do something by hand, we usually don't build software to do that thing. But when we want to scale a process beyond humans, then we may opt for coding it. Some servers just make raw data (a time server for instance), others will fetch data from multiple places and process it into different derived data (most apps are CRUD), and still others are just there to make accessing / processing / sending that data easier and more efficient (think databases, caches, even many CRUD endpoints).
We'll use these similarities and various usecases to great effect for understanding different scenarios.
I'll caveat that this is not a perfect metaphor (we're flattening the 4d world of software into a sparse ~3d metaphor so obvs compression loss) but I think it can take us surprisingly far.
Factory Actors
Okay so with the Factory as our stage, let's take a look at the actors we'll use to simulate the metaphor.
Factory - This is where all of our operations take place
- Factory - It's just a factory. It's got some space, probably contains some stuff, and workers do things inside of it. Crucially, space is finite so we gotta somehow fit all our operations into this space or find other ways of doing things.
- Server - Think of a Server as a Factory. Everything happens inside of it - getting data, processing data, storing data, moving data, etc. We still have space constraints but in different forms - the number of Workers, number of Loading Docks, and amount of space to store things.
Items - These are the things we're processing. Might be one thing, might be many things. These represent the inputs / outputs (and often there are intermediate Items that never leave the Factory).
- Factory - An Item can be anything. Maybe the factory makes nails from metal ore or maybe it's just a warehouse that holds a bunch of goods and packages them for delivery.
- Server - Similarly an Item in software land is usually some package of Data. Think of this like a Type - An IG post and its metadata, an email, a workout you logged in a fitness app, the html for a webpage.
Workers - These are the actors who do the work in the Factory - operating the Loading Docks, loading the Trucks, processing Items, etc. Based on the Factory and configuration, there may be more / less Workers available.
- Factory - In Factory land this is often people but sometimes robots. Crucially we're thinking of Workers as teachable - capable of doing multiple tasks based on instructions. They're not a hammer / sewing machine that can only do one thing, they're like a person / robot that can do many things based on instructions. In this metaphor we'll assume we have instructions for how to handle tasks in the Factory.
- Server - In Server land a Worker is a Thread. A Thread is what picks up work and runs it according to its instructions (the software you wrote).
Trucks - This is the only mode of transportation / information passage. It could carry [0, many] Items and always has some sort of information to identify the Truck, the Items it carries, and its Request (what it wants).
- Factory - In Factory land a Truck may be used to move Items or it could just be used to relay a message. Crucially we don't have alternative means of information relay (like email / text messages) - everything must be delivered by Truck.
- Server - In Server land this is basically a Request. A Request always contains information, may have a payload, and the Server can choose to do things based on the information it contains.
Loading Docks - This is how we connect the Truck and the Factory. There are no doors in our Factory, only Loading Docks. Each Loading Dock must be operated by a Worker for it to operate. If there are no Loading Docks available the Truck must either wait or go away.
- Factory - In Factory land a Truck must use a Loading Dock to connect with the Factory. Regardless of whether it has a lot of Items or no Items it still must use the Loading Dock. A Worker will need to be present to operate the dock and receive the Truck.
- Server - In Server land the Truck is a Request (think HTTP), the Loading Dock is the connection socket, and the Worker is a Thread. There must be an available socket and Thread to receive the Request. This means that our Factory could be constrained by available Loading Docks but also by available Workers to operate them.
Okay so we've talked about a lot of different Actors in our metaphor but where does the software fit in? Well the software isn't really the server so it makes sense it's not one of our Actors - this is why system design / software design are similar but different.
In our case the software we're running on the server is the instructions we give the Actors in our Factory telling them what to do and how to do it. In Factory land you could think of it as the runbook for how each Worker should do a task:
- How to create Item X from Item A
- How to load / unload a Truck
- Given a Truck order, how do you find the appropriate Items and schedule them for delivery
We will explore different cases like these based on this Server as Factory metaphor in the future but for now let's finish defining the Factory.
Handling a Simple Request
With our Server as Factory defined, let's run through a simple Request to see how it works in practice.
For this example, we're going to keep things very simple:
- Input: Item A
- Output: Item B
In Factory land, handling a Request like this is like:
- Truck comes in containing Item A
- Truck attempts to connect to Loading Dock
- A Worker comes to operate Loading Dock
- Worker checks the Infos for the Truck
- Worker unloads Truck
- Based on Infos / Items of Truck, Worker does stuff
- (Here we're assuming Worker knows how to go from Item A -> Item B)
- Worker takes Item B and starts loading Truck
- Truck departs with Item B
In Server land, handling a Request like this is like:
- Request comes to Server containing Item A
- Request attempts to connect to Server
- A Thread comes to handle socket connection
- Thread checks the Request headers / Info
- Thread deserializes the Request Items / payload
- Based on the Info and payload the Thread will do stuff
- Thread returns Item B and serializes it into a return Request
- Request is sent back
That's it - a simple request handled by our Server as Factory.
Next
I've got a lot of ideas for different scenarios to leverage this metaphor in but I wanted to share the metaphor out first to get feedback. Let me know if you like the metaphor / have suggestions for improving it.
If you liked this post, you might also like:
- A mining metaphor - Stop wasting your time on Bad Startup Ideas
- System Design - Software Monoliths for Scale
- Build your own server - Build a simple F# web API with Giraffe
Want more like this?
The best / easiest way to support my work is by subscribing for future updates and sharing with your network.