Пейджер

Предисловие:

TL;DR
  • FSM — фиксированный набор состояний и разрешенных переходов между ними
  • Решает комбинаторный взрыв флагов (isTouched, isError, isSuccess, isPending)
  • Полезен для многоступенчатых процессов с зависимыми шагами
  • Переход происходит по событиям, только в разрешенные состояния
Предисловие:
Я думал, что пост будет короче раза в два, но получилось, как получилось. Надеюсь, осилите

Есть подход к проектированию, полезный на разных уровнях приложения, и который почему-то не очень распространен во фронте, несмотря на то, что периодически о нем рассказывают на докладах. Имя этому паттерну

Конечный автомат / Finite State Machine

Заранее скажу, что я постарался все максимально упростить, поэтому, если кто-то заметит грубые неточности, сообщайте, я тогда или исправлю пост, или выложу дополнение с правками

Теперь же, прежде чем переходить к что это и как, отвечу на вопрос зачем это. Обычно, когда говорят о стейт машинах, говорят, что они подходят для моделирования процессов, но если уйти от формального "зачем", то есть две основные категории задач, в которых полезен конечный автомат. Первая, когда у вас множество связанных единой логикой и периодически взаимоисключающих (как бы тавтологично не звучало) флагов состояний, в которых может прибывать система. Так называемый комбинаторный взрыв. Например, инпут в форме, который может иметь такие флаги как: isTouched, isError, isSuccess, isPending. Большое количество флагов может приводить к наличию невалидных состояний системы. Конечный автомат же заменят набор флагов на единое состояние исключая невозможные комбинации. Вторая группа — это многоступенчатые процессы, где следующий шаг зависит от предыдущего и/или переходы асинхронны. Примером может быть любой многостраничный пользовательский путь, где вы вводите какие либо данные, а при переходах данные улетают куда-нибудь на бэк и на основе ответа вы видите следующий экран. Помимо этого за счет конечного автомата можно разделить логику и реагирование на ее этапы, например отправка логов, изменение юрл при перехоже в состояние ошибки. Я, если что, не предлагаю использовать fsm на каждый чих, но если стало сложно (или понятно что будет сложно в будущем) менеджерить флаги или какой-то код процесса, то я бы присмотрелся

Теперь, когда определились с зачем, перейдем к тому, а что это вообще такое. Основная идея в том, что есть фиксированный набор состояний и разрешенных переходов между ними, т.е по сути направленный граф, где узлы - состояния, ребра - разрешенные переходы, и для каждого состояния есть правила того, каким образом происходит переход в следующие. Состояние - это некоторый этап в работе автомата, но если сильно утрировать, то это некоторый именованный ключ в конфигурации fsm, у которого есть соответствующие ему правила перехода и контекст. Под правилами перехода обычно подразумевается набор доступных для состояния ивентов, по вызову которых машина запускает функцию перехода, которая проверяет возможность перехода и следующее состояние. Т.е еще раз кратко fsm - механизм, который может пребывать в фиксированном количестве состояний и переход происходит по событиям и не из любого состояния в любое, а по заданным правилам и только в разрешенные

Далее будут различные упрощенные примеры, с инлайн реализацией в объекте. Важно понимать, что реализовать конечный автомат можно разными способами, через класс, компонент, стор, главное тут сама концепция

Простой демонстрационный пример стейт машины:

const stateMachine = {
  currentState: 'untouched',

  run(eventName) {
    const nextState = this[this.currentState][eventName];

    if (!nextState) throw new Error();

    this.currentState = nextState;
  },

  untouched: { focus: 'focused', error: 'error' },
  focused: { error: 'error', valid: 'valid' },
  error: { clear: 'focused' },
  valid: { submit: 'submitted', clear: 'focused' },
};

stateMachine.run('focus');
console.log(stateMachine.currentState); // focused
stateMachine.run('valid');
console.log(stateMachine.currentState); // valid


Максимально упрощенный пример, в котором у объекта есть текущее состояние, конфиги переходов для состояний и метод, который обрабатывает события, проверяя корректность перехода и обновляя состояние. Т.е для данной стейт машины правилом перехода является мапа из события в состояние
Хотите больше таких постов?
Подпишитесь на канал и читайте продолжение в Telegram.
Подписаться на @typescript_bowl Открыть пост в Telegram