Skip to content

GitLab Next

  • Menu
Projects Groups Snippets
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
  • Sign in / Register
  • R RFCs
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Locked Files
  • Issues 22
    • Issues 22
    • List
    • Boards
    • Service Desk
    • Milestones
    • Iterations
    • Requirements
  • Merge requests 0
    • Merge requests 0
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
    • Test Cases
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Packages & Registries
    • Packages & Registries
    • Package Registry
    • Infrastructure Registry
  • Monitor
    • Monitor
    • Incidents
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Code review
    • Insights
    • Issue
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar

GitLab 15.0 has launched! Please visit Breaking changes in 15.0 and 15.0 Removals to see which breaking changes may impact your workflow.

  • GitLab.org
  • Frontend
  • RFCs
  • Issues
  • #65
Closed
Open
Created May 16, 2020 by Thomas Randolph@thomasrandolphDeveloper

New: Use Finite State Machines

New Pattern Proposal: Use Finite State Machines

Some things - especially components - need to represent state that has no business anywhere outside of the component. We should begin representing this contained state with finite state machines.

Advantages of new pattern

  1. Extremely testable - if code's behavior is fully encapsulated in a finite state machine, we can test that the state updates correctly at every step of any process
  2. Extremely readable - instead of fiddling with a bunch of state booleans, actions that change the state of some code are documented as transition events, like LOAD_SUCCESS. You don't need to know which flags would have been updated there to know what happened.
  3. Extremely declarative - Instead of inferring what state something is in at any moment, there's a single definition of what state is possible - and how to get there and move out of it.
    • State is a single string; it either is something, or it is not. No more checking combinations of flags.

Disadvantages of new pattern

I'm honestly having trouble thinking of a negative, maybe...

  1. There's a bit of extra code - the machine definition is a moderate-sized object
  2. States and Transitions should be extracted to constants, so there will be a bunch of extra constants laying around in modules
  3. It could be confusing to have state (e.g. global state, Vuex) and state machine (e.g. internal state).
    • I must note that these are - obviously - different things. I think most people agree you can and should have both.
  4. Some folks might prefer to deal with clusters of booleans
    • Maybe if( !isLoading && hasError ) is preferable - to some - to if( is( 'errored' ) )
  5. It's an abstraction of something you could do in a few lines of code directly in a component

What is the impact on our existing codebase?

None at all. This is entirely opt-in, and nothing that currently exists has to be touched.

Adding the reference implementation as is will work without modification.
It is 49 lines of code (plus 329 lines of tests).

It's also eminently reversible: since this is entirely self-contained to the (component|module|class) where it's used, you can add or remove it at whim.

Reference implementation

Boy howdy do I have a reference implementation for you!

gitlab-org/gitlab!32365 (merged)

Prior Art

  • "state of the art" @xstate/fsm
  • State machine with additional exit context (properties that are returned after a state finishes transitioning, but as part of the definition of the source state) via @ealcantara: https://gitlab.com/gitlab-org/gitlab/blob/v13.0.0-rc20200506140558-ee/app/assets/javascripts/clusters/services/application_state_machine.js
  • I added a super primitive state machine in a current MR: https://gitlab.com/gitlab-org/gitlab/-/blob/e0483121c4ce89d0c3890d3bcb20bd1c6ef53329/app/assets/javascripts/vue_shared/components/diff_viewer/viewers/renamed.vue#L50-64
  • Backend already uses state_machines for some things.
Edited May 18, 2020 by Thomas Randolph
Assignee
Assign to
Time tracking