lucywang000 / clj-statecharts

State Machine and StateCharts for Clojure(Script)
https://lucywang000.github.io/clj-statecharts/
Eclipse Public License 1.0
231 stars 15 forks source link

Extensibility through data #2

Open ingesolvoll opened 3 years ago

ingesolvoll commented 3 years ago

I have a few suggestions on how to make clj-statecharts even more extensible and data oriented. I mostly work in re-frame, so my requirements comes from that field, but these probably apply to other areas equally well. I'll describe them in re-frame terms here.

Desired outcomes

  1. Ability to use data (keywords, vectors) instead of functions, where applicable and practically possible
  2. Ability to inject additional context into functions on entry, guard, etc.

1. Less functions, more data

In the app I'm working on at my daily job, sending schema and FSMs over the wire to be shared across the stack is very common. Serializing functions is of course possible, malli can do that, but it's easier if we can avoid it. There are several techniques or APIs that could work:

In our malli code, we specifically solved serialization by referring to objects through keywords. Our cljc-implemented registry could then be injected just before you need it, on the server or on the client.

2. Injecting context

It would be very powerful if all functions in the FSM definition could have arbitrary context injected. Imagine the following invocation:

(fsm/transition machine s1 {:type :timer} {:ctx {:db current-re-frame-db})

Which would make a guard fn receive the :ctx value in its args.

You may agree or disagree that this particular thing is a good idea, but it really opens up a lot of possibilities. For example: if the app uses an interceptor to integrate the FSM into re-frame, you could use a guard to make the FSM reactively transition based on client db changes.

lucywang000 commented 2 years ago

Sorry for the late reply.

The first "Less functions, more data" sounds reasonable, but it's already doable since the fsm schema only requires the entry/exit/actions/guards functions to satisfy ifn?, not fn?, which means it could be any keywords. For vectors it would be ambiguous since for now :entry/:exit/:actions values could be a vector of functions. So we need some special handling.

The second, "Injecting context", I think you can simply put the context under some key in the second argument of fsm/transition. fsm/transition is a direct translation of the formula [next-state, actions-to-peform] = F(current-state, input-event) so anything that could affect the transition shall conceptually be part of the state.