StateMachine refactoring #141
mattwzawislak
started this conversation in
Ideas
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Problem
The
StateMachine<TState, TTransition>file has gotten a bit gnarly. I was focused on getting a functional model out without fully considering principles like DRY.Now with a better picture of the internal patterns used there could be a refactoring to clean up confusion.
Development
Spikes:
Current State of the Current Machine
The current state machine's internal flow is messy due to one clear issue:
There is a duplication of logic for handling scenarios where the
EnterStateorExitStateis happening duringActivate/TransitionorTransition/Deactivaterespectively. By charting out the flow (I think this is correct?) you can see that there are two types ifEnterState- one where the previous state and parameters are present and one without. Likewise, there is similar duplication withExitState.stateDiagram-v2 Inactive --> InitialStateSet : GetInitialState InitialStateSet --> StateActivated : ActivateInitialState StateActivated --> TriggersActivated : ActivateTriggers TriggersActivated --> EnterInitialState : EnterState EnterInitialState --> Active : No Error InitialStateSet --> Clear : Error StateActivated --> DeactivateInitialState : Error DeactivateInitialState --> Clear TriggersActivated --> DeactivateInitialTriggers : Error DeactivateInitialTriggers --> DeactivateInitialState EnterInitialState --> Active : Action threw EnterInitialState --> DeactivateInitialTriggers : Enter threw Active --> ExitStateDeactivate: Deactivate ExitStateDeactivate --> DeactivateFinalTriggers: Stop Triggers ExitStateDeactivate --> ExitRecovery: Error DeactivateFinalTriggers --> DeactivateFinalState: Deactivate DeactivateFinalTriggers --> ExitRecovery: Error DeactivateFinalState --> Clear DeactivateFinalState --> ExitRecovery: Error Active --> ExitStateTransition: Transition ExitStateTransition --> ExitRecovery: Error ExitStateTransition --> Transition: Transition Transition --> EnterMiddleState: Enter Transition --> ExitRecovery: Error EnterMiddleState --> Active : No Error EnterMiddleState --> Active : Action threw EnterMiddleState --> EnterRecovery : Enter threw ExitRecovery --> ExitStateTransition: Transition ExitRecovery --> ExitStateDeactivate: Deactivate EnterRecovery --> EnterMiddleState: Retry Enter EnterRecovery --> DeactivateFinalTriggers: Deactivate Inactive: Inactive <br/>none/none/none InitialStateSet: Initial state set <br/>none/none/set StateActivated: Calling OnActivated <br/>none/none/set TriggersActivated: Starting Triggers <br/>none/none/set EnterInitialState: Entering State <br/>none/none/set EnterMiddleState: Entering State <br/>set/none/set Active: Active <br/>none/set/none DeactivateInitialTriggers: Stopping Triggers <br/>none/none/set DeactivateFinalTriggers: Stopping Triggers <br/>set/none/none DeactivateInitialState: Calling OnDeactivated on Next <br/>none/none/set DeactivateFinalState: Calling OnDeactivated on Previous <br/>set/none/none Clear: Clear <br/>none/none/none ExitStateTransition: Exiting State <br/>set/none/set ExitStateDeactivate: Exiting State <br/>set/none/none ExitRecovery: Recovering failed exit <br/>none/set/none EnterRecovery: Recovering failed enter <br/>set/none/set Transition: Transitioning <br/>set/none/setSimplification
The first proposal is to avoid this duplication by changing when parameters and states shift.
By moving when the parameters and states shuffle (next -> current -> previous) we can avoid some duplication immediately. This would avoid having custom error handling in the
Activate/Deactivatemethods which is meant to function similarly to the wayTransitionhandles errors:stateDiagram-v2 Inactive --> InitialStateSet : GetInitialState InitialStateSet --> StateActivated : ActivateState StateActivated --> TriggersActivated : ActivateTriggers TriggersActivated --> EnterState : EnterState EnterState --> Active : No Error InitialStateSet --> Clear : Error StateActivated --> DeactivateState : Error DeactivateState --> Clear TriggersActivated --> DeactivateTriggers : Error DeactivateTriggers --> DeactivateState EnterState --> Active : Action threw EnterState --> DeactivateTriggers : Deactivate EnterState --> EnterRecovery: Transition Active --> ExitState: Deactivate Active --> ExitState: Transition ExitState --> DeactivateTriggers: Deactivate ExitState --> ExitRecovery: Error ExitState --> Transition: Transition DeactivateTriggers --> DeactivateState: Deactivate DeactivateTriggers --> ExitRecovery: Error DeactivateState --> Clear DeactivateState --> ExitRecovery: Error Transition --> EnterState: Enter Transition --> ExitRecovery: Error ExitRecovery --> ExitState: Transition ExitRecovery --> ExitState: Deactivate EnterRecovery --> EnterState: Retry Enter EnterRecovery --> DeactivateState: Deactivate Inactive: Inactive <br/>none/none/none InitialStateSet: Initial state set <br/>none/none/set StateActivated: Calling OnActivated <br/>none/none/set TriggersActivated: Starting Triggers <br/>none/set/none EnterState: Entering State <br/>none/set/none Active: Active <br/>none/set/none DeactivateTriggers: Stopping Triggers <br/>none/set/none DeactivateState: Calling OnDeactivated on Next <br/>none/set/none Clear: Clear <br/>none/none/none ExitState: Exiting State <br/>none/set/none ExitRecovery: Recovering failed exit <br/>none/set/none EnterRecovery: Recovering failed enter <br/>set/none/set Transition: Transitioning <br/>set/none/setWhile not largely different, this does simplify the internal state machine just enough to fully extract out an internal state machine for handling this flow. The proposal here is to remove a lot of the repetitive code into chainable methods on an internal state machine. Since the state machine isn't truly accessible to public consumers this is a good time to make such a drastic shift, as the nuance of "when
CurrentStateis set" isn't yet a concern.All reactions