-
Notifications
You must be signed in to change notification settings - Fork 147
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Handling 'back' events #4
Comments
@burin - My apologies that it has taken me two days to get back to you! Thanks a ton for including such a clean code example as part of your question - it's really helpful (not to mention exciting to see machina being put to good use!). I've wrestled a lot with this same kind of question, but 90% of the time I err on the side of being explicit. So - at the outset - I find your approach expressive, and appreciate the explicit nature of the transitions. I hadn't thought about adding a "previousState" member to the fsm, but I can see how that could be useful. I'm working on finalizing v0.2.0 and can include that as part of it. I'm not sure how useful this style of approach could be to you, but one thing I've found myself doing (though this is focused on linear progression through states) can be seen in the "load" example: my fsm has a "constraints" object I add that looks something like this: constraints: {
waitingOnTemplates: {
nextState: "waitingOnData",
checkList: {
haveMainTemplate: false,
haveItemTemplate: false,
haveErrorTemplate: false
}
},
waitingOnData: {
nextState: "ready",
attempts: 0,
checkList: {
haveItemData: false
}
}
} Each member of constraints is a state name, and contains a "nextState" (for the linear progression) and a checklist of bools that have to be true before the state transition can occur. In handlers for each state, I'll call the checkIfReady: function() {
if(_.all(this.constraints[this.state].checkList, function(constraint) { return constraint; })) {
this.transition(this.constraints[this.state].nextState);
}
} So - to handle non-linear forward-and-back transitions, a couple of options come to mind:
(including this as part of the new FSM options arg, and calling // There are probably better ways to do this, but the gist
// is to iterate through the "conditions" until a state is
// found that matches the current checklist (or the current
// state is used instead....
determineTransition: function() {
return _.reduce(this.transitionFlags, function(memo, v, k) {
if (!memo && _.isEqual(v.conditions, this.checkList)) {
return k;
}
return memo;
}, "", this) || this.state;
},
// Working check list of where things are
checkList: {
constraint1: false,
constraint2: true,
constraint3: false,
},
// the flags that determine when a state
// should be the transition target
transitionFlags: {
stateA: {
conditions: {
constraint1: false,
constraint2: false,
constraint3: false
}
},
stateB: {
conditions: {
constraint1: false,
constraint2: true,
constraint3: false
}
},
stateC: {
conditions: {
constraint1: true,
constraint2: true,
constraint3: false
}
}
}
// based on the "checkList" values above, if determineTransition() was called,
// it would transition the fsm to stateB Of course, that's a bit contrived (and it might be a horrible idea), but it might also spark some ideas. At the end of the day, if you find "DRY" and "SOLID" principles in conflict, my advice would be to err on the side of SOLID. Let me know if you have any thoughts. Thanks! |
@ifandelse Thanks for taking the time to address this question! Your response has definitely sparked some thoughts. I think the In my particular example though, I think changing the Another thing to note is that Your example of the Using the Thanks for the examples! They have helped me understand the possibilities more than anything. Since |
@burin - Sounds great. I'll leave this issue open until I commit v0.2.0 (which will include the previousState member). I think your suggestion to leave the implementation of transitionToPrevious is a wise one (and I'd love to see what you do with that if you do implement it). It's always easier to add those details into machina later, if it seems like the core lib should have it, rather than force one in now and rip it out later. I'm really impressed with how you're using it - keep me posted on thoughts/concerns you have going forward. Glad I was able to help! |
I've released version 0.2.0 - added a |
Thanks for getting this in! This is great work. |
I've been using
machina.js
to model workflows and it's been working great so far. One thing I support is the ability for a user to go back in the workflow.In any given state, a user can "save" their progress, transitioning to the next state, or go "back", which will take them back to the previous state.
Currently, each state has an explicit handler for "back", which calls
transition()
with the appropriate name of the expected action to go back to. Unfortunately, this only allows for "linear" progress, and conditional transitions are a little tricky to deal with.Here is a stripped down example of a workflow I have created for adding a flight to an itinerary.
My question is whether this is a good approach to tackle this problem or if there is some alternative. On one hand, it's good because it's very explicit. On the other, it doesn't seem very DRY and I'm not sure how to go "back" if a particular state has two or more possible entry points (
confirmingFlight
can be transitioned to fromshowingForm
in one case, orselectingOriginDestinationAirports
in another)I tried looking through the
machina.js
code to see if there was a "previous state" of some sort, but I didn't want to dig into something that could possibly change in the future (private API or such).Any tips would be appreciated! And thanks for publishing your blog post about FSMs and creating a super clean library with a nice API!
The text was updated successfully, but these errors were encountered: