The actor model of computation was first proposed in the 70's as a nicer way to deal with concurrency. Nowadays it's built into our everyday tools and we don't think about it as much. Understanding how it works helps you write less bugs.
43 years of actors: A taxonomy of actor models and their key properties is a 2016 paper by Koster et al that provides a readable overview of the actor model and why it's good. You can read the paper with my annotations, here.
The paper identifies common concepts, classifies implementations into 4 types, and defines the Isolated Turn Principle as a key component. The authors stress that specifics are implementation dependent.
Meaning that the actor model of computation is more what you'd call guidelines than actual rules.
The basic idea
The basic idea of an actor model is that you have actors doing work based on a combination of internal state and commands/messages/events from outside. The actors do not directly share state. This makes them concurrency safe.
Common concepts
Your tools will have different names for these concepts, but they all use the same conceptual building blocks.
- message or event is a unit of communication between actors. Each contains a name and a payload.
- inbox or message queue is an ordered set of messages that the actor will process. The queue is in order but the processing need not be.
- turn or step is the processing of 1 message from start to finish.
- interface defines the list of messages an actor understands
- state is the actor's internal state. Anything it can access without concurrency counts.
- behavior is the combination of an actor's state and interface
- actor is the combination of execution context, inbox, interface, and state
- actor system is a language or library that implements the actor model
Your React components are actors that communicate by passing events through a shared event mechanism. In a distributed backend system this maps nicely to message queues and lambda functions or servers that process events.
4 types of implementations
The paper classifies implementations into 4 types and finds no difference in the power of these different implementations as long as the Isolated Turn Principle is observed. Use whatever works for you.
- The classic actor model uses
create
,send
, andbecome
primitives to implement the model in a functional paradigm. To change state, actorsbecome
a new actor with different behavior. - The active objects approach uses objects that hold internal state and use a single entry point to process events
- The processes approach leverages processes to process an event from start to finish based on a single entry point. The process is killed when its turn finishes.
- The communicating event-loops approach uses promises to wait for processing to be ready. It's the only paradigm that supports multiple entry/exit points for an actor.
You see active objects a lot in object oriented languages, I don't have much direct experience.
Processes are common in distributed backend systems where a new Lambda boots up to process each event on a queue. Apache of ye olde LAMP stack uses this approach to start a new PHP process for every HTTP request.
A note on why event-loops are good
Also everyone saying JS isn't good for backend work is forgetting an important detail:
— Swizec Teller (@Swizec) April 18, 2024
JavaScript is uniquely suited for IO-bound code. Most backend code is IO-bound. Compute-bound is rare.
Event-loops are the core primitive in JavaScript. Every async
function is an actor. This makes JavaScript uniquely well-suited for IO-bound code because the single-threaded promise-based approach makes it easy to coordinate lots of waiting around for input/output.
But event-loops are bad for compute-bound code because of their single-threaded nature. If you lock up the CPU with your actor (function), it blocks all other in-progress actors from proceeding.
The paper does not talk about this and doesn't mention JavaScript. I assume for two reasons:
- the paper is from 2016 and JS was not yet so popular for server-side code
- JS fails the isolated turn principle criterria, you have to enforce it manually
The Isolated Turn Principle
The isolated turn principle is key to making the actor model useful. Best when your language can guarantee this, but you can use it as a set of principles for your own code. Follow these rules and you'll rarely have bugs due to concurrency.
A single turn must be processed as 1 isolated step
To satisfy this rule you need:
- Safety meaning that an actor's state is fully isolated and cannot be modified by another actor or another instance of the same actor during processing
- Liveness meaning that an actor must process a message start to finish without blocking operations
In JavaScript terms this translates to keeping your functions idempotent and avoiding unmanaged mutable state.
Cheers,
~Swizec
Continue reading about 43 years of the actor model
Semantically similar articles hand-picked by GPT-4
- The problem with threads
- Smart core, thin interfaces
- Do you really need immutable data?
- Finding modules in a big ball of mud
- A new VSCode extension makes state machines shine on a team
Learned something new?
Read more Software Engineering Lessons from Production
I write articles with real insight into the career and skills of a modern software engineer. "Raw and honest from the heart!" as one reader described them. Fueled by lessons learned over 20 years of building production code for side-projects, small businesses, and hyper growth startups. Both successful and not.
Subscribe below 👇
Software Engineering Lessons from Production
Join Swizec's Newsletter and get insightful emails 💌 on mindsets, tactics, and technical skills for your career. Real lessons from building production software. No bullshit.
"Man, love your simple writing! Yours is the only newsletter I open and only blog that I give a fuck to read & scroll till the end. And wow always take away lessons with me. Inspiring! And very relatable. 👌"
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 ❤️