Skip to content
GitLab
Next
    • GitLab: the DevOps platform
    • Explore GitLab
    • Install GitLab
    • How GitLab compares
    • Get started
    • GitLab docs
    • GitLab Learn
  • Pricing
  • Talk to an expert
  • /
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
    • Contribute to GitLab
    Projects Groups Topics Snippets
  • Register
  • Sign in
  • R RFCs
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributor statistics
    • Graph
    • Compare revisions
    • Locked files
  • Issues 28
    • Issues 28
    • List
    • Boards
    • Service Desk
    • Milestones
    • Iterations
    • Requirements
  • Merge requests 0
    • Merge requests 0
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Artifacts
    • Schedules
    • Test cases
  • Deployments
    • Deployments
    • Environments
    • Releases
  • Packages and registries
    • Packages and 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.orgGitLab.org
  • Frontend
  • RFCs
  • Issues
  • #65
Closed
Open
Issue created May 16, 2020 by Thomas Randolph@thomasrandolph0️⃣Developer

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