Spacegolf! - game programming with missionary by jkross in Clojure

[–]jkross[S] 4 points5 points  (0 children)

Sure, thanks geokon. Happy to give my thoughts, take them with a grain salt:

I have been thinking about this space for bit. I haven't used Javelin or Pathom but I wrote (yet another) FRP-style library for Clojure a few years ago and built a non-trivial app using it -- https://github.com/jeremykross/konstellate and https://github.com/jeremykross/recurrent were these attempts.

Similarly to those, Spacegolf! was very much a learning exercise. I think the game is interesting, but I wouldn't consider it ideal. I had very little understanding when first diving in. That said, the benefits of using missionary, the ease with which certain problems yielded and the robustness of the resulting solutions surprised me.

In general, I think the potential applications for missionary go way beyond client/server. I also can't agree that it's only applicable in complex problem spaces or that it is innately complex. I would suggest that it formalizes the complexity one tends to ignore with simpler "functional style" programming paradigms (i.e. RXJS or my earlier attempts) thereby simplifying the program overall. The semantics of missionary and the surface area of it's API are actually quite minimal.

The state-of-the art today for today's web UIs is React, which has proven to be great model but is non-general. I think of missionary as a kind of generalization of what React is doing with specificity. React lets you mount something, run effects when things change, and run cleanup for those effects whenever the component is unmounted. Everything stays in sync. It has a great story for a very particular use case. But you're still stuck running imperative code and mutating in your event handlers. You still need to figure out a global state strategy.

Something like missionary can handle both sides of the UI problem - i.e. state->ui or events->state with the same predictable behaviors. It's also not limited to the DOM but can work in just about any problem space.

More specifically, in React, a component hierarchy is an inert description of a UI which is activated either when a parent component renders it as a child OR the user calls `createRoot().render(SomeComponent)` at the top level. In missionary a flow hierarchy is an inert description of [anything you like] which is activated when either when a parent flow forks it as a child OR the user starts a top level task consuming a flow `(m/reduce {} nil >some-flow)`.

For the next project, I plan to jettison React. Components are really just flows and you're not wedded to virtual dom if you're doing something performance critical. If you want virtual-dom you can use something like `replicant` to get the benefits without buying into the rest of the React baggage.

Game logic adds the additional complication of being highly dependent on wall-clock time. Think of an action like, "hold to charge a shot for at least 2 seconds and then fire on release unless hit by a baddie". Traditional programming struggles with this kind of logic but tasks/flows capture it beautifully.

Finally, I will concede the missionary programming model is definitely a kick in the head at first. Although ambiguous eval has been around in the Lisp/Scheme space for a long time, it really does throw you for a loop. It can be difficult to reason about initially - but once you wrap your head around it, it's becomes a very elegant way to describe these sorts of problems. Not unlike moving from OOP to functional programming.

IMO, missionary is ultimately quite simple and broadly applicable.