Все статьи | Разработка

Идиоматический Redux: Redux Toolkit 1.0

Идиоматический Redux: Redux Toolkit 1.0 главное изображение

В конце октября 2019 года вышел Redux Toolkit 1.0. Один из авторов проекта проекта и автор оригинальной публикации Марк Эриксон (Mark Erikson) рассказывает, как появился этот инструмент, делится целями создания Redux Starter Kit и объясняет, как удалось выполнить задуманное.

Краткая информация о Redux Toolkit:

  • помогает быстро начать использовать Redux;
  • упрощает работу с типичными задачами и кодом Redux;
  • позволяет использовать лучшие практики Redux по умолчанию;
  • предлагает решения, которые уменьшают недоверие к бойлерплейтам.

Истоки

Появление Redux

Redux появился летом 2015 года. Он стал логическим завершением споров и войн вокруг Flux. В течение года с момента появления он обошёл другие имплементации Flux и де-факто стал стандартным инструментом для управления состояниями в React-приложениях.

Redux намеренно разрабатывался как расширяемый инструмент, и он стал именно таким инструментом. Вокруг проекта появилась целая экосистема аддонов: от Action/Reducer Generators до Store Persistence или десятков утилит для работы с неизменяемостью. Например, поскольку в Redux нет нативных инструментов для управления асинхронным поведением и побочными эффектами, появились десятки аддонов для работы с побочными эффектами.

Одним словом, если вам нужно что-то сделать с помощью Redux, с высокой долей вероятности уже есть аддон, который позволяет решить вашу задачу. В противном случае вы можете создать его самостоятельно.

Цикл хайпа

Практически все инструменты и технологии проходят через цикл хайпа. Когда появляется новый продукт, первые пользователи в него влюбляются и считают его серебряной пулей. Потом с новым продуктом знакомится больше людей. Они замечают ограничения и недостатки. Появляются негативные отзывы. Наконец, большинство пользователей находит лучшие способы применения технологии. Инструмент получает репутацию рабочего решения со своими преимуществами и недостатками.

Redux тоже прошёл через цикл хайпа. Разработчики быстро стали ассоциировать его с React. Появилась если не догма, то устойчивое мнение об обязательном использовании Redux там, где используется React. Некоторые senior-разработчики стали говорить новичкам, что они должны использовать Redux, если используют React.

В результате многие люди стали изучать Redux без осознания контекста. Новички часто не понимали, почему появился Redux, какие проблемы решает этот инструмент. Слепое использование любого инструмента — прямой путь к большим проблемам.

Слепое использование любого инструмента — прямой путь к большим проблемам.

Некоторые люди успешно использовали Redux и были довольны его возможностями. Другие заметили недостатки, причём не только реальные, но и придуманные.

Проблема сложности

Есть несколько факторов, которые в сумме делают использование Redux довольно сложным по сравнению с другими инструментами. Вот эти факторы:

  • Redux намеренно добавляет уровень косвенности в идею управления состояниями. Как отмечает Дэн Абрамов, Redux не создавался в качестве самого производительного или самого простого инструмента управления мутациями. Он фокусируется на предсказуемости кода.
  • Общепринятые практики в Redux предполагают дополнительный уровень косвенности и использование «кода, который должен быть написан»: это создатели действий, константы типов действий, thunk’и, switch-выражения, неизменяемые обновления.
  • Также для Redux написано много «правил», которые, впрочем, не соблюдаются самим Redux. Например, речь идёт о неизменяемости, сериализации, избегании побочных эффектов.
  • JavaScript — мутабельный язык программирования, поэтому писать корректный иммутабельный код на нём сложно. Это связано как с необходимостью избегать случайных мутаций, так и с большим количеством кода, который нужно написать, чтобы управлять обновлениями без изменяемости.
  • Redux всегда был инструментом с небольшим ядром, вокруг которого сформирована большая экосистема аддонов. Это позволяет пользователю выбирать настройки контейнера самостоятельно. С одной стороны, такой подход обеспечивает гибкость. С другой, даже простые задачи требуют от разработчика достаточно сложных действий, например, добавления мидлваров в асинхронную логику или настройку инструментов разработчика. Также это значит, что пользователь должен осознанно выбирать аддоны на ранних стадиях разработки, даже если приложение простое.
  • Концепции функционального программирования сложны и незнакомы большинству пользователей, особенно людям с бэкграундом в ООП.

Как большинство ранних пользователей, первые пользователи Redux относились к категории продвинутых. Конфигурация, настройка и «ручная имплементация, которая позволяет контролировать все нюансы» были ключевыми преимуществами, с помощью которых инструмент привлекал новых пользователей. Тем не менее эти преимущества стали недостатками, когда в Redux пришло много новых пользователей с разным опытом и уровнем подготовки. Многие новички рассматривали паттерны и практики просто как бойлерплейт, с которым сложно работать. Поэтому они искали другие решения.

В дополнение к минимально необходимым, но сложным редьюсерам и диспетчеризации действий проблемой стала случайная сложность. Например, документация Redux рекомендует организовывать код в файлы и директории по действиям, константам, редьюсерам и контейнерам. Есть веские причины распределять код в файлы по типам. В то же время нет обязательных требований писать действия, редьюсеры и константы в отдельных файлах или директориях. Большинство пользователей читали документацию и выполняли рекомендации, поэтому организация кода по действиям, константам, редьюсерам и контейнером стала стандартным паттерном.

Похожий пример: написание типов действий как констант ( const ADD_TODO = "ADD_TODO" ) или наличие функций, создающих действие для каждого типа, также не требуется в обязательном порядке. Но эти подходы вошли в рекомендованные паттерны, а пользователи активно следуют этим рекомендациям.

Необходимость выбирать аддоны часто вызывала сложности у пользователей. Болевой точкой стало большое количество библиотек с побочными эффектами, в каждой из которых используется своя терминология. Уже через год после появления Redux стало понятно, что побочные эффекты — большая проблема.

Экосистема держалась на thunk, сагах и наблюдаемых объектах. Одним из самых распространённых вопросов у пользователей стал «как мне выбрать мидлвар для работы с побочными эффектами». Кстати, thunk изначально были в ядре Redux, но их убрали из него ради дополнительной гибкости. Очевидно, что пользователи нуждались в «официальных» инструментах для работы с побочными эффектами.

В поисках решения

Автор оригинальной публикации погрузился в работу над Redux в 2016 году, когда в качестве волонтёра писал раздел FAQ на официальном сайте проекта. Дэн Абрамов выдал автору и Тиму Дорру карт-бланш, и автор начал отвечать на вопросы пользователей на разных сайтах и форумах.

К весне 2017 года автор заметил изменения в сообществе: большинство пользователей не понимали, для чего создавался Redux, а также почему существуют типичные паттерны применения этого инструмента. Автор попытался исправить это с помощью нескольких подробных публикаций: «Дао Redux, часть 1: реализация и намерение» и «Дао Redux, часть 2: практика и философия». Эти статьи рассказывают, для чего создан Redux и как его планировалось использовать.

Примерно в то же время автор открыл issue в репозитории Redux. В нём поднимались такие вопросы:

  • Каким должно быть идиоматическое использование Redux с условием ухода от бойлерплейта? Как мы можем реагировать на подобные жалобы?
  • Какие абстракции можно создать, чтобы упростить изучение и использование Redux без необходимости прятать этот инструмент?

В первом ответе Джастин Фалькон (Justin Falcone) предположил следующее:

  • Нужен официальный пакет redux-preset с redux, react-redux, redux-thunk.
  • Нужны создатели редьюсеров, например, createReducer({[actionType]: (state, payload) => state}, initState).

Эти предположения стали основой будущего Redux Toolkit.

В треде появилось более сотни комментариев. В итоге некоторые пользователи просто рекламировали свои библиотеки для работы с абстракциями. В середине треда Дэн Абрамов оставил свои пожелания:

  • Подмножество Flow/TypeScript, с которым проще работать, чем с чистым Redux.
  • Уход от выделения констант, просто сделайте строковые литералы более безопасными.
  • Сохранение независимости от React и других библиотек, но с упрощением использования существующих зависимостей, например, можно предоставить реализации mapStateToProps.
  • Сохранение принципов Redux: сериализуемые действия, путешествия во времени и горячая перезагрузка должны работать, журнал действий должен иметь смысл.
  • Разделение кода простым способом из коробки.
  • Поддержка использования редьюсеров с селекторами, а также создание условий, в которых они не будут казаться ужасными вместе (подумайте о парах редьюсер-селектор, которые легко писать).
  • Вместо совмещения создателей действий с редьюсерами, стоит полностью уйти от создателей действий.
  • Принять разумные значения производительности по умолчанию, чтобы мемоизация через Reselect просто работала без необходимости самостоятельно писать код.
  • Создание встроенных помощников для индексации, нормализации, коллекций.
  • Поддержка встроенного тестируемого асинхронного потока.
  • Инструмент должен быть брендированным и позиционироваться в качестве официального.

Начало процесса

В феврале 2018 Ник Маккерди (Nick McCurdy) открыл issue, в котором предложил внедрить заморозку состояния на стадии разработки. Автор оригинальной публикации написал в треде такой комментарий:

«Я уже писал, что хочу создать стартовый пакет, в котором будет официально рекомендованный командой Redux и простой набор инструментов. Я посмотрел десятки вариантов, включая вариант Create React App + Redux, но пока мы ничего не одобрили.

Настоящая проблема в том, что ядро Redux из коробки вообще не имеет установленных конфигураций. Мы не предполагаем, какой мидлвар будет использовать разработчик, и будет ли он вообще его использовать. Поэтому мы не можем просто добавить мидлвар в ядро, потому что в ядре из коробки нет установленных конфигураций».

В ответ Тим Дорр открыл issue и написал следующее:

«Похоже, для успешного начала работы с библиотекой было бы полезно сделать стартеркит с ядром Redux, в которым также должны быть несколько общих мидлваров, несколько расширителей (enhancers).

В моём представлении в стартовом пакете должна быть одна из библиотек редьюсеров, популярные мидлвары, например, thunk’и и саги, полезные инструменты разработки. Можно сделать подмножество пакетов для тех, кто использует React.

Не думаю, что нужно делать что-то похожее на Create React App. Но нам нужно что-то, что из коробки даёт все инструменты, нужные для начала работы».

После этого на Reactiflux началась продуктивная дискуссия с участием автора оригинальной публикации, Ника Маккерди и Гарри Волфа (Harry Wolff). По её итогам Гарри Волф написал, что могло бы быть в стартовом пакете Redux:

  • обёртка для createStore с хорошим набором дефолтных инструментов, например, простой способ добавления мидлваров, инструменты разработчика Redux;
  • встроенный хелпер для работы с неизменяемостью (Immer?);
  • встроенный createReducer;
  • создатель действий, который совместим с FSA;
  • поддержка асинхронных действий, поддержка побочных эффектов — Flux, сага, что-то ещё?

На следующий день автор этой статьи опубликовал пример реализации configureStore и createReducer. Ещё через два дня автор опубликовал Redux Starter Kit как экспериментальный пакет.

Проектирование инструментов

Первые имплементации и нейминг

Работа над Redux Toolkit продолжалась в течение нескольких следующих месяцев. Ник добавил первые юнит-тесты, интеграцию с CI, включил инструменты разработчика Redux в configureStore. Автор статьи добавил реэкспорт из Redux и библиотеку selectorator, а также улучшил настройки мидлваров. После высокой активности с марта по май 2018 наступил период затишья, который продолжался несколько месяцев.

Автор публикации ощутил выгорание летом 2018 года из-за высокой нагрузки. После обдумывания ситуации он решил сосредоточиться на обязанностях мейнтейнера проекта. Это предполагало в числе других активностей популяризацию Redux Starter Kit.

Выбранное название казалось отвлечённым. Именно поэтому автор статьи опубликовал инструмент как личный пакет. В августе 2018 года он открыл issue, в котором начал дискуссию о финальном названии инструмента. В числе прочего предлагалось использовать префикс @redux.

Дискуссия продолжалась до середины октября 2018 года. Один из участников предложил вернуться к простому варианту redux-starter-kit. Проблема была в том, что кто-то уже опубликовал пакет с названием redux-toolkit на npm. Автор статьи на всякий случай обратился к владельцу пакета с ником @shotak и спросил, не может ли он подарить имя redux-toolkit. К удивлению автора, человек ответил в течение нескольких часов и согласился подарить имя. После этого автор опубликовал первую официальную версию инструмента.

Работа над функциональностью

Функции createReducer и createAction уже были полезными. Но автор статьи хотел найти более простые инструменты.

Команда обсуждала использование хелперов из пакетов типа redux-utilities.

Автор публикации видел десятки подобных библиотек. Одна из библиотек, которая привлекла внимание автора — autodux Эрика Эллиотта. Она позволяет пользователям автоматически генерировать создателей действий и типы действий на основе объекта с редьюсерами и префикса с именем.

Шон Ванг (Shawn Wang) оценил autodux и несколько других пакетов. Вот выдержка:

«Использование autodux даёт мощный набор создателей, селекторов и редьюсеров из коробки. Поэтому вы можете писать действия для бизнес-логики без дополнительных усилий. Мне нравится autodux».

В конце концов autodux стал источником вдохновения при создании самой полезной части Redux Toolkit: функции createSlice.

Эрик Боуэр (Eric Bower) попробовал портировать autodaz в createSlice. Пулреквест застопорился. Автор статьи узнал о библиотеке robodux, в которой используется Immer. Он понял, что Эрик Боуэр решил сделать собственную версию библиотеки на TypeScript.

После обсуждения Боуэр согласился вернуть код в Redux Toolkit. Автор скомпилировал код библиотеки в чистый JavaScript и включил его в стартеркит.

Создание дорожной карты

В начале декабря 2018 года с помощью Docusaurus была опубликована документация Redux Toolkit.

Автор статьи добавил в стартеркит дефолтные мидлвары для определения мутаций и несериализируемых значений, а также возможность трассировки стека.

В конце января 2019 года автор статьи открыл issue, в котором предложил обсудить дорожную карту к выпуску redux Starter Kit 1.0, а также начал работать над способностью слайсов слушать другие действия. Дэнис Вашингтон (Denis Washington) прокомментировал этот пулреквест. Он предложил обсудить целесообразность использования createSlice.

В ответ автор публикации написал большой комментарий. Вот выдержки:

Цели

Согласно README, в числе прочих источниками вдохновения для создателей Redux Toolkit являются Create-React-App и Apollo-Boost. Это пакеты, в которых есть дефолтные инструменты и абстракции над более сложными настраиваемыми инструментами. Цель существования этих пакетов — обеспечить быстрый старт при работе с библиотекой без необходимости погружаться в детали и принимать сложные решения. В то же время эти пакеты не привязывают разработчика к дефолтным инструментам и настройкам. Они очень полезны для новичков, которые не знают о всех доступных вариантах и о «правильных» выборах. Также пакеты полезны для опытных разработчиков, которым нужен простой инструмент, не требующий настройки окружения.

Я хочу, чтобы Redux Toolkit стал таким же инструментом для Redux.

Быстрый старт

Я хочу, чтобы люди начинали работать с Redux как можно быстрее.

Упрощение основных способов применения и уход от бойлерплейтов

Я хочу убрать острые углы:

  • сократить код где это возможно;
  • предложить функции, которые выполняют очевидные действия, которые пользователи привыкли делать руками;
  • посмотреть, как люди используют Redux и как они хотят его использовать, и предложить «официальное» решение на основе предпочтений пользователей.

Redux Toolkit должен вести пользователя к правильным настройкам, а также автоматически защищать от распространённых ошибок или предупреждать о них.

Отсутствие блокировки

Когда кто-то начинает делать приложение на базе Redux Toolkit, я не хочу забирать у него возможность сделать что-то вручную в начале или в процессе работы.

С другой стороны, люди должны иметь возможность добавлять Redux Toolkit в существующие приложения. В таких случаях у разработчиков должна быть возможность внедрять стартеркит постепенно без необходимости переписывать код с нуля.

Стать очевидным дефолтным способом использования Redux

В долгосрочной перспективе автор видит Redux Toolkit очевидным дефолтным способом использования Redux для большинства разработчиков. В качестве примера можно посмотреть на Create React App, который стал дефолтным очевидным способом использования React.

Отказ от попыток охватить все способы использования Redux, фокусировка на типичных подходах

Есть много способов использования Redux. А в ядре Redux есть минимальный набор инструментов. Именно поэтому существуют тысячи библиотек и аддонов, который охватывают разные кейсы применения Redux. Стартеркит не может и не собирается охватывать все способы применения Redux.

Разумная поддержка TypeScript

Автор хочет поддерживать специалистов, которые пишут на TypeScript, как и других специалистов, которые используют Redux специфическим способом. Поэтому в Redux Toolkit должна быть хорошая типизация. В то же время автор не хочет, чтобы «лучшая типизация» стала врагом «хорошей функциональности».

Работа с API

Параллельно с этой дискуссией Дэнис Вашингтон конвертировал базу Redux Toolkit в TypeScript.

Автор публикации потратил несколько месяцев на работу с дорожной картой React-Redux 7. Потом он работал с дизайном хуков API.

Одновременно команда обсуждала разные вопросы, включая расширение возможностей createSlice. Рассматривалась функция combineSlices, а также автогенерируемый селектор функциональности.

К лету 2019 года автор завершил работу над React-Redux и начал писать документацию Redux Toolkit. В начале сентября она была готова.

Тем временем Ленц Вебер (Lenz Weber) предложил несколько улучшений, включая внедрение колбэка prepare в createAction, а также улучшение читабельности определений типов.

С этого момента автор начал «допиливать» API Redux Toolkit. Появилась возможность кастомизации дефолтных мидлваров, а также включение редьюсеров в createSlice.

Было ещё много идей, но автор решил, что их можно реализовать после релиза. После этого официально вышел Redux Toolkit 1.0.

Будущее Redux Toolkit

Обзор

Оглядываясь на проделанную работу, можно сказать, что создателям удалось выполнить основные запланированные задачи. Redux Toolkit стал инструментом с такими характеристиками и возможностями:

  • официальный пакет, в котором реализованы лучшие практики;
  • значительно упрощает работу с Redux;
  • сохраняет основные принципы Redux;
  • стартеркит можно добавить в проект на любой стадии реализации;
  • полезный инструмент как для новичков, так и для опытных разработчиков;
  • поддерживает TypeScript без увеличения сложности разработки.

Автор активно рекламировал Redux Toolkit целый год. Ссылка на этот инструмент появилась на главной странице документации Redux. Также инструмент рекомендуется в разделе документации Configuring Your Store.

Судя по статистике загрузки пакета, Redux Toolkit оказался востребованным инструментом. Его устанавливают более 100 тыс. раз в месяц, и график количества загрузок показывает рост. Автор получил много положительных откликов о Redux Toolkit.

Следующие шаги

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

Адаптированный перевод статьи Idiomatic Redux: Redux Toolkit 1.0 by Mark Erikson. Мнение администрации «Хекслета» может не совпадать с мнением автора оригинальной публикации.

Аватар пользователя Дмитрий Дементий
Дмитрий Дементий 12 ноября 2019
Рекомендуемые программы

С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.

Иконка программы Фронтенд-разработчик
Профессия
Разработка фронтенд-компонентов веб-приложений
19 января 8 месяцев
Иконка программы Python-разработчик
Профессия
Разработка веб-приложений на Django
19 января 8 месяцев
Иконка программы PHP-разработчик
Профессия
Разработка веб-приложений на Laravel
19 января 8 месяцев
Иконка программы Node.js-разработчик
Профессия
Разработка бэкенд-компонентов веб-приложений
19 января 8 месяцев
Иконка программы Верстальщик
Профессия
Вёрстка с использованием последних стандартов CSS
в любое время 5 месяцев
Иконка программы Java-разработчик
Профессия
Разработка приложений на языке Java
19 января 10 месяцев
Иконка программы Разработчик на Ruby on Rails
Профессия
Новый
Создает веб-приложения со скоростью света
19 января 5 месяцев