Fetch data

πŸ“„

GET api/users

Pending

200 VALE

Fetch data

πŸ“„

GET api/users

Cargando...

200 VALE

Fetch data

πŸ“„

GET api/users

Cargando

πŸ“„

GET api/users

Cargando

πŸ“„

GET api/users

Cargando

πŸ“„

GET api/users

Cargando

πŸ“„

GET api/users

QuΓ© narices

Fetch data

πŸ“„

GET api/users

Cargando

200 VALE

Fetch data

πŸ“„

GET api/users

Cargando

πŸ“„

GET api/users

Cargando

πŸ“„

GET api/users

Cargando

πŸ“„

GET api/users

Cargando

Fetch data

Everyone is
different.

A/B tests

are ineffective.

User flows are
seldom linear.

πŸ“„

πŸ“„

πŸ“„

πŸ“„

Adaptive user interfaces (AUI)

Adapt to people,
not just devices

Delete

Are you sure?

Yes

No

Delete

Undo

Deleted!

Developing AUIs
is challenging.

Model-driven
development

Finite state machines

  • have one initial state

  • a finite number of states

  • a finite number of events

  • a mapping of state transitionsΒ 
    triggered by events

  • a finite number of final states

Sign in

Signing in...

Profile

Home

SUBMIT

SUCCESS

UNAUTHORIZED

PROFILE

Statecharts
(Hierarchical State Machines)

Statecharts

Idle

Searching...

entry / prefetchResources

entry / fetchResults

Search

  • ActionsΒ - onEntry, onExit, transition
  • GuardsΒ - conditional transitions

[query.length > 0]

Statecharts

  • ActionsΒ - onEntry, onExit, transition
  • GuardsΒ - conditional transitions
  • HierarchyΒ - nested states
  • OrthogonalityΒ - parallel states
  • HistoryΒ - remembered states

H

Idle

Searching...

SEARCH

Success

Failure

RESOLVE

REJECT

SEARCH

Searched

Hierarchical states

Idle

Searching...

SEARCH

Success

Failure

RESOLVE

REJECT

SEARCH

Searched

Hierarchical states

const machine = Machine({
  initial: 'idle',
  states: {
    // ...
    searching: {
      on: {
        RESOLVE: 'searched',
        REJECT: 'searched.failure'
      }
    },
    searched: {
      initial: 'success',
      states: {
        success: {},
        failure: {}
      },
      on: { SEARCH: 'searching' }
    }
  }
});

How was your experience?

π˜…

Good

Bad

Tell us why?

π˜…

Submit

Thanks for your feedback.

π˜…

Close

Define transitions between
states & events

function searchReducer(state = 'idle', event) {
  switch (state) {
    case 'idle':
      switch (event.type) {
        case 'SEARCH':
          return 'searching';
        default:
          return state;
      }
    case 'searching':
      switch (event.type) {
        case 'RESOLVE':
          return 'success';
        case 'REJECT':
          return 'failure';
        default:
          return state;
      }
    case 'success':
      switch (event.type) {
        case 'SEARCH':
          return 'searching';
        default:
          return state;
      }
    case 'failure':
      switch (event.type) {
        case 'SEARCH':
          return 'searching';
        default:
          return state;
      }
    default:
      return state;
  }
}

FSMs with switch/case

const machine = {
  id: 'feedback',
  initial: 'question',
  states: {
    question: {
      on: {
        CLICK_GOOD: 'thanks',
        CLICK_BAD: 'form',
        CLOSE: 'closed',
        ESC: 'closed'
      }
    },
    form: {
      on: {
        SUBMIT: 'thanks',
        CLOSE: 'closed',
        ESC: 'closed'
      }
    },
    thanks: {
      on: {
        CLOSE: 'closed',
        ESC: 'closed'
      }
    },
    closed: {
      type: 'final'
    }
  }
};

Define transitions between
states & events

const transition = (state, event) => {
  return machine
    .states[state] // current state
    .on[event]     // next state
    || state;      // or same state
}

FSMs with object mapping

import { Machine } from 'xstate';

const feedbackMachine = Machine({
  id: 'feedback',
  initial: 'question',
  states: {
    question: {
      on: {
        CLICK_GOOD: 'thanks',
        CLICK_BAD: 'form',
        CLOSE: 'closed',
        ESC: 'closed'
      }
    },
    form: {
      on: {
        SUBMIT: 'thanks',
        CLOSE: 'closed',
        ESC: 'closed'
      }
    },
    thanks: {
      on: {
        CLOSE: 'closed',
        ESC: 'closed'
      }
    },
    closed: {
      type: 'final'
    }
  }
});
npm install xstate
import { feedbackMachine } from './feedbackMachine';
import { useMachine } from '@xstate/react';

const App = () => {
  // const [state, dispatch] = useReducer(feedbackReducer, 'question');
  const [current, send] = useMachine(feedbackMachine);

  if (current.matches('question')) {
    return (
      <QuestionScreen
        onClickGood={() => send({ type: 'GOOD' })}
        onClickBad={() => send({ type: 'BAD' })}
        onClose={() => send({ type: 'CLOSE' })}
      />
    );
  } else if (/* ... */) {
    // ...           
  }
}
  1. Abstract model
  2. Transition analytics
  3. Identify adaptive paths
  4. Use analysis for adaptation

Game plan

Photo by NEW DATA SERVICESΒ on Unsplash

Success

Signing in

Error

0.9

0.1

Weighted graphs

How was your experience?

π˜…

Good

Bad

Tell us why?

π˜…

Submit

Thanks for your feedback.

π˜…

Close

Give Feedback

❓

❓

Login

Gallery

Profile

Camera

SUCCESS

TAP PROFILE

TAP CAMERA

BACK

BACK

Scroll

Analysis of transitions

πŸ—Ί Login, Gallery, Gallery

πŸ—Ί Login, Gallery, Camera

πŸ—Ί Login, Gallery, Profile

0.90, 0.31

0.90, 0.57

0.90, 0.12

0.90

0.31

0.57

0.13

UNAUTHORIZED

0.10

SUCCESS

(decide)

TAP AD

Analysis of actions

+10

Gallery

Ads interspersed

Ads shown at top

Ad

Scroll

Scroll

TAP AD

+10

-1

-10

INTERSPERSED > .5

TOP > .5

Decision trees

Contextual data

  • Registration date
  • Number of friends
  • Posting frequency
  • Location
  • ...etc.

New user?

< 30 days

>= 30 days

Show ad at top

Friend count?

< 100

>= 100

Show more ads

Show less ads

All data

Prediction via
shortest paths

A

B

C

D

E

  • Shortest pathΒ algorithms (Dijkstra, Bellman-Ford, A* search, etc.)
  • AnalyticsΒ provides weights
  • Represents happy paths
  • Can be automatically generated

A

B

C

D

E

import { Machine } from 'xstate';

const myMachine = Machine({
  // ...
});

const myService = interpret(myMachine)
  .onTransition(state => {
    analytics.track({
      target: state.value,
      source: state.history
        ? state.history.value
        : undefined,
      event: sanitize(event),
      timestamp: Date.now()
    });
  })
  .start();

A

B

C

D

E

import { Machine } from 'xstate';
import { getShortestPaths } from '@xstate/graph';

const myMachine = Machine({
  // ...
});

const shortestPaths = getShortestPaths(myMachine);
  • A: A
  • B: A -> B
  • C: A -> B -> C
  • D: A -> D
  • E: A -> D -> E

A

B

C

D

E

import { Machine } from 'xstate';
import { getShortestPaths } from '@xstate/graph';

const myMachine = Machine({
  // ...
});

const shortestPaths = getShortestPaths(myMachine);

0.9

1.0

0.4

0.6

0.1

0.4

0.6

  • A: A
  • B: A -> D -> E -> B
  • C: A -> D -> E -> C
  • D: A -> D
  • E: A -> D -> E

A

B

C

0.75

0.25

D

E

(D) 0.95

(D) 0.05

A -> B
A -> C
A -> B
A -> B
E ->
D ->
E ->
F ->

Higher-order Markov models

Agent

Environment

Action

State

Reward

Reinforcement
learning

service.onTransition(state => {
  analytics.track({
    source: state.history.value,
    target: state.value,
    context: state.context,
    event: state.event,
    timestamp: Date.now()
  })
});

Application

Executable Model

Metrics Tracking

Adaptive Transitions

Adaptive UI

Determinism

Visualization

πŸ‘©β€πŸ’» Developer Experience

Communication

Analytics

Simulation

Testability

πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘¦ User Experience

Prevent Information Overload

Provide intuitive guidance

Understand Tasks & Goals

Create Personalized Systems

Adaptive User Interfaces

Micro vs. Macro Adaptivity

Prediction vs. Feedback

Local vs. Global

Data vs. Simulation

Modeling considerations

The future of state

is nothing new.

Advantages

of using statecharts

  • Visualized modeling
  • Precise di​agrams
  • Automatic code generation
  • Comprehensive test coverage
  • Accommodation of late-breaking requirements changes

Disadvantages

of using statecharts

Learning curve

Modeling requires planning ahead

Not everything can be modeled (yet)

Statecharts

FSMs

Bottom-up

Complexity

trade-offs

States & logic

Code Complexity

The world of statecharts

Spectrum community

XState Docs

xstate
@xstate/react
@xstate/graph
@xstate/vue
@xstate/test
@xstate/analytics
@xstate/sim
@xstate/viz

βœ…

βœ…

βœ…

πŸ”œ

πŸ”œ

πŸ•

πŸ•

βœ…

Make your code do more.

Thank you React Alicante πŸ‡ͺπŸ‡Έ