TGViewer
S0ER S0ER @softwareengineervlog · 10.4K subscribers
Post #2191 9.12K
Решение проблемы избыточных состояний через конечные автоматы

Часто замечаю в коде у фронтенд-разработчиков такой паттерн, как выражение одного логического состояния через несколько состояний в коде. Рассмотрим, например, такой код на React, который описывает состояние некоторой формы:

const [error, setError] = useState<string | undefined>(); // в форме есть ошибки
const [loading, setLoading] = useState<boolean>(false); // форма загружается на сервер
const [isSuccessful, setIsSuccessful] = useState<boolean>(false); // форма успешно отправлена


Здесь разработчик создает целых три разных независимых состояний в коде (состояние ошибки, состояние загрузки, состояние успеха), но логически весь этот код отвечает за состояние формы - то есть за одно и то же состояние. Это одна форма, которая может либо находиться в одном из четырех состояний:

1. в состоянии загрузки
2. в состоянии ошибки
3. в состоянии успеха
4. в состоянии готовности к редактированию.

Несложно посчитать, что код выше сгенерирует нам целых восемь различных состояний вместо четырех необходимых. Помимо запутанности и сложночитаемости, такой код плох тем, что мы генерируем недостижимые состояния, которые непонятно, как обрабатывать. Например, что делать, если у нас одновременно есть ошибка и переменная isSuccessful равна true? Скорее всего, программист выберет какое-то одно состояние как приоритетное, но так или иначе, такой код будет порождать запутанность и баги.

Выход из этой ситуации - это использование конечных автоматов. Конечный автомат - это математическая модель, описывающая конечный набор возможных состояний и определяющая, что автомат может находится только в одном из этих состояний в конкретный момент времени. Также автомат может переходить из одного состояния в другое. В коде на React конечный автомат можно довольно создать, используя редюсер, а возможные состояния удобно описываются через тип-сумму:

type FormState = {
state: 'loading';
} | {
state: 'error';
message: string;
} | {
state: 'ready';
} | {
state: 'successful';
}

type FormAction = {
type: 'set_loading'
} | {
type: 'set_error',
payload: {
error_message: string;
}
} | {
type: 'set_ready',
} | {
type: 'set_successful'
}

const initialState: FormState = { state: 'ready' };

const formReducer = (state: FormState, action: FormAction):FormState => {
// ...
}


Созданные formReducer и initialState мы можем использовать в нашем компоненте через useReducer. Таким образом, мы получили удобное декларативное описание возможных состояний нашей системы, а также совокупность переходов из одного состояния в другое.
  • 👍 108
  • ❤ 6
  • 🤔 3
  • 🤡 2
  • 👎 1
  • 🔥 1
  • 😢 1
  • 💩 1
  • 💯 1
More from @softwareengineervlog
  1. Sep 3, 2026Google выпустила Gemini 3.8 Flash — новая быстрая модель уже обходит гигантов в кодинге. П…
  2. Sep 3, 2026Сейчас использую DeesSeek v4 Flash, на готовой кодовой базе решать стандартные таски из тр…
  3. Aug 6, 2026Полезное: разраб сделал интерактивный мануал, который по шагам показывает, что происходит…
  4. Aug 5, 2026Ты ненастоящий программист! Это происходит снова и снова, и каждый раз одинаково. Я начал…
  5. Jul 27, 2026Внимание, скам! Появился бот который выдает себя за бота моего канала. Я НИЧЕГО ЧЕРЕЗ БОТО…
  6. Jul 25, 2026У Сбера есть интересный whitepaper где он описывает технологию разработки продукта с помощ…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →