2 ms·
I think understandable can mean different things here. If we're looking at a state dump and your data is in a weird place, I'd want to understand how the data g
by toast0 2y ago
I think understandable can mean different things here. If we're looking at a state dump and your data is in a weird place, I'd want to understand how the data got into that weird place.
In a model with state owned by a process, and changes coming in through the mailbox, I know that all of the state changes happened through processing of incoming messages, one at a time. If I'm lucky, I might have the list of messages that came in, and be able to run them one a time, but if not, I'll just have to kind of guess how it happened, but there's probably only a limited number of message shapes that are processed, so it's not too hard. There's a further question of how those messages came to be in the process's mailbox, of course.
In a model with shared memory mutability, it can be difficult to understand how an object was mutated across the whole program. Especially if you have errors in concurrency handling and updates were only partially applied.
There's certainly a learning curve, but I've found that once you've passed the learning curve, the serialized process mailbox model makes a lot of understanding simpler. Individual actors are often quite straight forward (if the application domain allows!), and then the search for understanding focuses on emergent behavior. There's also a natural push towards organizing state into sensible processes; if you can organize state so there is clear and independent ownership of something by a single actor, it becomes obvious to do so; it's hard to put this into words, but the goal is to have an actor that can process messages on that piece of state without needing to send sub-requests to other actors; that's not always possible, sometimes you really do need sub-requests and the complexity that comes with it.
- gr4vityWall 2y agoThat's an interesting point of view, thanks for taking the time to write that. I wonder how much that learning curve is worth it. It reminds me of the Effect library for TypeScript, in that regard, but Elixir looks more readable to me in comparison.
- toast0 2y ago> I wonder how much that learning curve is worth it. It really depends on how well your application fits the model. If it's a stretch to apply the model and you're already comfortable with something else, it might not be worth it. But if you're building a chat server, or something similar, I think it's very worthwhile. I think it can be pretty useful if you have a lot of complex state per user, in general, as your frontend process could send process inbound requests into messages into a mailbox where each user would only be processed by a single actor (each user doesn't need their own actor, you could hash users in some way to determine which actor handles a given user). Then you have a overall concurrent system, but each user's complex state is managed in a single threaded manner. I think process/actor per connection is a superior mental model to explicit event loops for something like a large HTTP server, but unless the server is performing complex work within it, I would assume without testing that the explicit event loop would win on performance. I think it would be more fun to build a large HTTP server in Erlang than with c and kqueue, but nginx and lighttpd are already written, and quite fast. When I needed to do a TCP proxy for million + connections, I took HAProxy and optimized it for my environment, rather than writing a new one in Erlang; that was still fun, but maybe different fun; and being able to handle tens of thousands of connections with minutes of configuration work was a better organization choice than having fun building a proxy from scratch. :)
- Nevermark 2y agoWell said. The essence: understanding scales better with mutation serialization. Any little bumps of complexity at the beginning, or in local code, pays off for simpler interactions to understand across longer run histories, increased numbers of processes, over larger code bases.