Statecharts are a precise, visual way of modeling the behaviour of complex reactive systems. They describe how things work, and can help you get your code doing exactly what you want.


Possible Wish/Idea: XState as Framework Substrate

May 17, 2020 at 5:58pm

Possible Wish/Idea: XState as Framework Substrate

May 17, 2020 at 5:58pm

A Basic Framework Concern

I was recently thinking through the experience of routing in js, in the context of a web framework for Deno. Typically, in JS routing approaches, we have to:
  • declare a big list of repetitive json or json-like objects
  • everything is visually tightly coupled together (chained this().with().that()), OR
  • spread out and composed from a variety of different places, sometimes making it impossible to get a high-level view of the routing in your app
I'm not talking about SSR concerns, client side routing, or any other sort of more specific take (SPA or otherwise). I'm talking about looking at an app written in js or ts, and being able to understand what routes there are, and what code those routes link to.
Contrast this with Ruby on Rails:
  • there's no boilerplate needed
  • you can space out your routing declarations and organize them conceptually in a way that's actually productive (ex below)
  • it produces a "map" that can tell you exactly where what code is, and what that should do, without you ever needing to look
This is all enabled by the constraint of a convention.
Here's an example of a "social-networky" kind of setup:
resources :connections do
scope module: "connections" do
resource :approvals, only: :create
resource :treasures, only: :create
resource :denies, only: :create
It's plainly obvious that people can interact with this idea of a "connection." More than that, there are also these other concepts called "approvals," "treasures," and "denies." You can find all the code that powers this inside dir's named connections.
This list actually serves as an implicit TODO. You define the API surface you're going to implement, in terms of your domain, then go at it. This is, deceptively, an absolutely beautiful developer experience. I hope you've started to notice the parallels between this seemingly unrelated place and statecharts. :)
For this example, the way you'd access this checklist is rake routes | grep connection. However, you have to keep the state of where you're at inside it in your head.


Straight porting Ruby on Rails into JS isn't a good approach. Rails is a great fit for Ruby because of it's deep embrace of the characteristics of the language. I think JS/TS has some different characteristics going for it:
  • runs straight in a browser
  • js is great for prototyping. ts for productionizing
  • component-based views, eliminating the mathematical explosion of endpoints having and belonging to many views
  • XState as a potential technical substrate
How could JS/TS provide a better routing experience for web development... "natively?" What would this look like?
What if you could declare your routes in a similar fashion -
  • different canonical resource concerns (actions) defined as symbols (an action being some representation of list, create, update, destroy, etc)
  • resource-declaration, module namespacing, action-specification
  • slightly less verbose writing experience, still able to safely and deeply configure a complex surface in one place
  • predictive capabilities on where supporting code is for the dev
Declaring the routes could look a little more like this...
/* declared in some prelude */
const index = Symbol("index");
const show = Symbol("show");
const create = Symbol("create");
const update = Symbol("update");
const destroy = Symbol("destroy");
/* all you'd have to write in your actual file */
resources("connections", only: [index, show, create]),
scope(module: "connections")
.resources("approvals", only: [create])
.resources("treasures", only: [create])
.resources("denies", only: [create]),
How do we turn that js object into a productionized set of routes? Compile it into a state chart. What else could we do with this...?
  • Take that implicit "todo" list, and make it explicit
  • Directly and concretely visualize it (or a portion of it)
  • Provide the actual status of the state of the predicted code (since we should theoretically be able to turn this into a list of es module urls)
But more than that... It'd also be possible to
  • Begin generating a testing harness
  • Exposing events to be used in a testing model
  • Provide opportunities for other kinds of control flow and/or safe configuration (think authenticated routes vs nonauthenticated, or that concept abstracted into a notion of "context" entirely)
In fact, this is just the benefits of XState applied to one area of a web framework. I contend there are, pardon the language, a shitload of other concerns XState could materially improve the application of (contract testing, reuse in integration testing, fixture data generation, validations, actual business logic + control flow, and ofc powering components).

Turning Towards Roadmap

Where and how does this magic become genuinely real? . This is the killer app, the meat and potatoes of developer experience. The more ways, places, and varieties this experience can bleed through to the developer or other end users, the higher the value.
For this routing concern: imagine a sheet (or drawer, basically a div that pops out from the side with stuff inside it) containing the map of your routes, and the actual living state of your code!? That would be freakin cool!! (Then stripped out when you go to prod, or not)
I think this idea of XState as a lower-level implementation substrate, which enables strong/clear DSL's and instrumentation, is combined with the other best thing to come out of JS land in recent-memory: strongly typed, declarative graphs recompiled in real time. (This idea was initially tucked away in steps 1-5 here, then ported into webpack) (and graphql has gotten to some pretty nice errors!).

Action Items

This post is quite full enough of ideas. Here are the main points, again:
  • The fundamental expressiveness of web frameworks hasn't materially increased since Rails with the exception of React's component-based views (perhaps an argument could be made for Prisma or Hasura, although I see these as side effects of the "strongly typed and declarative graphs compiled in real time" idea)
  • JS/TS are in a nice spot because it runs in browsers and fits a flow where a prototyping -> productionizing pathway is available
  • Strongly-typed, declarative graphs compiled in real-time are amazing at being simple while able to handle complexity
  • XState (+viz, and +testing) has immense value as a low-level substrate, atop which an application of a concern can be exposed (application meaning the application of declarations into xstate around a specific area, like routing, that produces a usable and productive system) (systems that compile domain-level concerns into statechart implementations)
  • (not discussed prior, but relevant): the browser now implements a lot of what js frameworks traditionally do in the view layer. these other places can now become correspondingly thin (but developer ux of these systems are still currently lacking)
This leads to my wishes/asks.
  • tooling (devtools, vscode extensions, etc), or
  • elements that can be used to build tooling (like router instrumentation in a sheet discussed above), like
  • first-class web components (react is fine - i just mean, able to import and directly use in any modern browser without build step) usable to drive visualization and interaction
Where are these at? Is there any appetite for ideas contained here in the official XState roadmap? In a more community sense, anyone else interested in these ideas? I'm willing to help, and considering ditching my usual nights-and-weekends coding to focus on this.

May 17, 2020 at 6:46pm
This is super interesting. I'll write up my thoughts on this sometime this week - I've been thinking about a lot of these ideas.
  • reply
  • like

June 5, 2020 at 2:20pm
Did you ever write your thoughts up?
  • reply
  • like
More coding than writing - I'm exploring how an Actor-model-based framework would look like in the front-end.
  • reply
  • like
Some prior art by Google folks:
I know they also did a POC in this direction using xstate - not sure where that one is.
Are you considering backend as well?
  • reply
  • like
Yes, backend for sure. Azure Durable Functions/Entities and AWS Step Functions all can act as state machine instances/actors that can communicate with each other, so it fits pretty well.
  • reply
  • like
FYI. Ember.js does this on the client side.
  • reply
  • like

June 20, 2020 at 9:16pm
Do you have any examples of how to use XState with azure durable functions/entities? I'm interested in replicating an academic paper that fictitiously simulates a system and was thinking about doing it with xstate.
  • reply
  • like

June 22, 2020 at 6:42pm
Do you have any examples of how to use XState with azure durable functions/entities? I'm interested in replicating an academic paper that fictitiously simulates a system and was thinking about doing it with xstate.
I'm working at something directly related to that, will share more soon!
  • reply
  • like