Hacker's Handbook


The Gnome Village

Threads fight. Gnomes cooperate.

Posted: 2025-11-06
Categories: development , Erlang , BEAM

The Gnome Village

The Gnome Village

I see some developers that arrive at the BEAM carrying mental luggage from object-oriented or sequential programming.

They mix code with instance, classes and objects treated as one, and repeat it here by confusing code with processes.

Even I still fall into the trap of equating code (a module) with a process.

To break this thought pattern I have introduced the Gnome Village Metaphor.

Gnomes vs Machines

In OOP you tend to build machines of machine parts and wire them tightly.

The BEAM model is different: code stays in scrolls, state lives inside gnomes, and the only coupling is the message protocol.

You can have thousands of tiny workers that never share anything.

It’s less like a machine built from components and more like a village of independent workers.

Gnomes vs Machines

What a Gnome Is

The gnome is a process. Not an OS thread. Not a fiber with shared state. A real BEAM process. It lives. It works. It dies. Nothing it does can corrupt another gnome's memory. This is the first promise of the village. Local mistakes stay local.

Private and Local Memory

Each gnome carries a backpack. In it, it keeps its personal belongings, data structures, variables, and the current stack of thoughts. No one else can look inside. Not even the supervisor.

This is the BEAM’s per-process heap. Every gnome allocates, grows, and cleans up its own memory. When garbage collection happens, it pauses only that gnome. The rest of the village keeps working, blissfully unaware that one of them is reorganizing its backpack.

You can think of this as enforced politeness. No one borrows another gnome’s tools. If two workers need the same scroll, they each get their own copy. That sounds wasteful until you remember that arguments over shared tools are slower than copying a small one.

When the backpack gets full, the gnome quietly expands it. If it has been hoarding junk, it throws some away. No one else stops to help. That’s why the village scales.

Gnome Backpack

This model feels strange at first, especially to programmers used to shared memory and global variables. But once you stop reaching into other people’s backpacks, your code becomes simpler. You no longer need locks, guards, or faith. Just messages.

Mail, Not Shared Drawers

When gnomes need to cooperate, they don’t shout across the room or share drawers full of half-finished work. They send each other small, clear messages, paper mail.

Each gnome has a mailbox. Messages arrive, stack up, and wait patiently until the gnome decides to read them. This small act of patience is what makes the village stable. No one interrupts anyone else. No one rummages through shared memory “just to check something.”

Gnome Mailboxes

When a message moves from one gnome to another, the BEAM copies it between their heaps. This sounds expensive until you compare it with the cost of arguing over shared state. Copying is linear, but contention is chaos. The BEAM avoids chaos.

Large binaries, like scrolls of long text or files of runes, are handled by reference so they don’t have to be copied every time. Small messages are cheap to copy. Either way, the rules stay consistent, ownership and lifetime are always clear.

The mailbox also tells the truth about your system. If a gnome falls behind, its mailbox grows. You don’t need metrics to know where the bottleneck is; you can see it directly. It’s a polite form of backpressure. Instead of crashing everything, the system simply queues up.

Shared Scrolls

Every gnome reads from the same shelf of scrolls. Code lives there, one copy, many readers. It’s the shared library of behavior that keeps the village running. Each gnome brings its own data, but they all follow the same instructions.

Shelf of scrolls

In object-oriented systems, code and data are fused by design. The class describes both structure and behavior, and when you instantiate it, the two merge into an object, a miniature machine built from its own blueprint. Every instance is a private copy of the same idea, and the boundary between code and state fades away.

That tight coupling shapes how you think. You start assembling systems as machines of machines, each with its own logic and data intertwined. Changing one part often means stopping the whole contraption.

The BEAM model avoids this entirely. Code and state are separate species. Modules define domains of logic, the scrolls on the shelf. Processes are independent actors, the gnomes who read those scrolls. You can have thousands of workers all using the same code without binding their identity to it.

You can start, stop, or upgrade gnomes without touching the scrolls they read. And you can update a scroll without restarting the village. New gnomes pick up the latest version; old ones finish their work with the version they began with, or get the new one as needed.

In the machine world, rewiring is dangerous. In the gnome village, you just swap a scroll on the shelf. The old one stays until no one needs it. The new one takes over quietly. The system keeps humming.

Hiring New Gnomes

When the village grows, you hire new ones. Each gnome starts empty-handed, carrying only its backpack and a reference to the scrolls on the shelf. That’s what spawning a process means.

In most runtimes, starting a new worker is a serious commitment. You create a thread, allocate stacks, and share memory that everyone must coordinate around. On the BEAM, it’s casual.

Because every gnome owns its own memory, you never worry about who cleans up what. Each process manages its own heap, collects its own garbage, and dies without ceremony. The village keeps going. This is why Erlang systems routinely handle millions of concurrent activities, not by being powerful, but by being polite.

The most important part is psychological. When concurrency is cheap, you stop trying to multiplex tasks inside one worker. Instead of building a complex machine that does everything, you build a community of simple ones that each do one thing well.

Fair Turns at the Workbench

Every gnome needs time at the workbench, the place where real work happens. This is where messages are handled, state is updated, and progress is made. The workbench is a shared resource, but it never turns into a battlefield.

Gnomes don’t fight for the bench. They queue. Each gets a short turn, does its work, and steps aside. The rhythm is steady, predictable, and fair.

Queue of gnomes waiting for workbench turns

Each workbench corresponds to a scheduler, one per CPU core. Every gnome waiting in line gets a slice of attention, measured not in time but in reductions. A reduction is roughly one function call or a small operation. After a few thousand of them, the gnome yields. The next one steps forward. This happens in microseconds.

Because of this reduction-based scheduling, no single gnome can monopolize the workbench. Long tasks get paused and resumed without blocking others. Even a slow worker can’t freeze the village. Everyone makes progress.

In the machine world, it’s different. A thread grabs a lock, works for too long, and everyone else waits. Latency spikes. Throughput drops.

Thousands of gnomes can take turns without noticing each other’s existence. This is what makes BEAM suitable for soft real-time systems: predictable responsiveness without explicit scheduling logic.

Failure Is Contained

Gnomes are independent workers. Each one carries its own tools, keeps its own memory, and makes its own mistakes. Even if they die, no other gnomes are affected.

One bench with spilled sandwich, other benches fine

In the machine world, it’s different. Parts are connected through shared cogs and gears. An exception in one component rattles through the entire mechanism. Shared state becomes corrupted, threads that touch it misbehave, and soon everything needs a restart.

You try to protect against it. You validate inputs, wrap code in try-catch blocks, check state, recheck it, and still miss something. Complexity grows. Safety doesn’t.

BEAM systems take a simpler path: let it crash. Bad data? Faulty logic? Let the gnome fall, clean the bench, and start fresh.

Isolation contains damage. Sharing spreads it. The village survives because every gnome stands, and occasionally falls, alone.

Conclusion

The gnome is the unit of work, state, and failure. Keep it small. Give it one job. Let it talk in messages. Supervise it. This is the simplest way I know to build software that stays up when real life happens.

- Happi


Happi Hacking AB
KIVRA: 556912-2707
106 31 Stockholm