Here is the case I'm looking at: My SPA can be in one of three state — 
probably more before I'm done but three will be sufficient for this 
discussion — logging in, active, and logged out. So, here's my model:

type Model
  = LoggingIn LoggingIn.Model
  | Active Active.Model
  | LoggedOut LoggedOut.Model

The message handling has appropriate tag messages and the update function 
looks fairly nice by casing on (msg, model). All good so far.

Now, for the question: How best to drive state transitions?

For example, when we finish logging in, we should get back a UserId that we 
can hand to Active.init to get an (Active.Model, Cmd Active.Msg). How 
should this be reported? The cases I've considered include:

1. Add an extra Maybe UserId result to LoggingIn.update.

2. Replace the second result from LoggingIn.update with something that can 
be either a Cmd LoggingIn.Msg or a LoggedIn UserId.

3. Add a loggedInUser : Model -> Maybe UserId function to the LoggingIn 
module and test this after doing the update.

Interesting side question: If we do succeed in logging in, is it ever 
reasonable to be returning commands (effects) from that update to the 
logging in model? The results aren't going to get routed back because that 
model state is going away. On the other hand, if we were just sending off 
some sort of external effect for which the result didn't matter, then maybe 
this could come up.

If the answer to the side question says "yes, it is reasonable to send off 
commands as part of login success", then the second option needs a more 
complicated type since we can return both a command AND a user id. In that 
case, the first case probably wins.

On the other hand, returning triples with what in the general case will be 
arbitrary third parameters feels like the sort of coding pattern that 
decays into returning quads and quints.

The benefit of the third path is that now one could imagine testing the 
logging in module by itself with a view case for when logged in. The state 
machine just drives us from this state to the active state.

The downside to the third path is that now every state implementation needs 
to include a state for while it is doing what it would ordinarily do and a 
state for when it is time to move on and that's more plumbing at those 
levels. For example, the Active module would similarly gain an isLoggedOut 
: Model -> Bool function and the model within the module would need to 
handle the logged out case even though it really has nothing to do in that 
case,

How would more experienced Elm coders handle this? Is there a sense for 
best practice?

My personal inclination is probably to go for the first option even though 
it starts to step out onto the slippery slope. I like the second approach 
because it feels more rigorous but I think that extra rigor just turns into 
extra code in practice. My first implementation today pursued the third 
course and I thought it looked nice in my top-level module until I thought 
about the fact that it would turn everything below it into a state machine 
as well.

Mark

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to