Functional state systems like Redux have made web development easier to reason about -- how can we apply these techniques to complex distributed systems? And what lessons from the distributed world can we bring back to web development? This talk explores concurrency models through the lens of a virtual guinea pig colony, and covers topics including actors, sagas, emergent behavior, and the unexpected virtue of object-oriented programming.
In 2012, Gary Bernhardt was giving a talk called Boundaries, which explored a programming model he refers to as "functional core, imperative shell." Like many design patterns, this has been independently discovered again and again: this pattern is now becoming mainstream in the JavaScript world, particularly in the React ecosystem, and yet it bears a very strong resemblance to the actor model that Erlang has been using for 30 years.
However, a lot of the contemporary discussion around this pattern have focused on the functional core part while trying to minimize the role of the imperative shell; JavaScript's OOP features are something to be avoided or even exorcised, not just used judiciously. Functional ideological purity can be equally as counterproductive as "everything-is-an-object" dogma, and there are useful patterns & lessons in the previous decades of OOP that we ignore at our peril. Functional and imperative models are complements, not competitors, and both have their place in software.
You are probably wondering now: What does this have to do with guinea pigs? Well, both the actor model and Smalltalk-flavored OOP are rooted in the same modeling approach used in bottom-up artificial intelligence, and the paradigms that work for distributed systems map surprisingly well to naïve implementations of artificial life. Also, its much funnier to explain the implications of the dining philosophers problem with rodents crowding around a food dish than with processes deadlocking a database connection pool.
Shared-nothing/message-passing concurrency models are nothing new, but JS developers are more frequently encountering scenarios that these models fit well. For example:
- "traditional" complex systems, e.g. client-server-cache-database relationships
- multi-process node apps, e.g. with PM2
- client-side concurrency with workers
- local distributed systems, e.g. inter-device communication with wearables/IoT
Though I do have some experience with these scenarios, this talk isn't structured as a How-To, nor am I pushing any particular library or framework. Rather, this is a Big Ideas talk -- the purpose is to illustrate how disparate problem sets (i.e. the list above) can be understood using the same conceptual model, and how this relates to the familiar (and, frankly, unfashionable) concepts in OOP.