Те из вас, кто использует Redux Toolkit, должны быть знакомы с огромным количеством шаблонного кода, который создается в результате. Наша команда (axmit) пробовала разные обходные пути, немного надеясь, что когда-нибудь мы найдем стандартное решение. Но этого не произошло, и мы решили решить проблему на своей стороне. Мы работали над этим больше года, и окончательный результат описан в этой статье.
История
Наши ключевые клиенты - стартапы со всего мира. Одно из главных преимуществ этих ребят - время выхода на рынок. Чем раньше товар попадает на рынок, тем больше у него шансов выжить. Поэтому одна из наших основных целей - оптимизировать время разработки без потери качества и уменьшить количество дефектов, вызванных человеческим фактором. В основном мы выбираем стандартные и более-менее стабильные решения. Но в случае с Redux поиск не увенчался успехом, и мы начали искать способы его оптимизации.
Вопрос мудрого человека содержит половину ответа, поэтому мы начали с определения проблем:
- Каждый разработчик обладает уникальным стилем кода, и достичь «обезличенного кода» сложно;
- Использование Redux приводит к появлению большого количества шаблонного кода / копипаста и связанных с ним проблем (более 100+ строк кода для CRUD);
- На разработку даже базовых задач уходит много времени, ведь нужно соблюдать множество правил: создать загрузку, настроить работу с ошибками и т. Д .;
- Структура различается между разными проектами и даже между разными проектными модулями.
Немного подумав, был разработан регламент создания магазина и описание его структуры. После этого мы решили провести рефакторинг кода, чтобы сделать его более читабельным. Несмотря на то, что наша кодовая база была не слишком большой, мы все же столкнулись с большим объемом кода, который следовало изменить.
Пока руководители проектов изо всех сил пытались найти пару часов в день, чтобы своевременно предоставлять результаты, пара разработчиков воплотила в жизнь простейшую идею. Да, великие идеи всегда кажутся простыми, как только они появляются. Идея заключалась в том, чтобы начать генерировать определенные части кода вместо того, чтобы писать их вручную. Мы не хотели использовать фрагменты, поскольку это привело бы к большому количеству кода (поскольку практически любые изменения в нем привели бы к рефакторингу и многочисленным ошибкам). Вместо этого мы создали функцию, которая будет принимать определенные параметры, и строили на их основе редуктор, действия и сагу. Это была первая версия наших коммуникаций (@ axmit / redux-communications). Название коммуникации появилось несколько естественно, поскольку эта библиотека связывает магазин, саги и компоненты.
Сразу после этого жизнь стала намного проще. Ну почти после этого. Время, необходимое для разработки, сократилось на 20 процентов (как мы посчитали, это тема для другой статьи). Это было достигнуто в основном за счет резкого уменьшения количества ошибок. Другая причина заключалась в том, что разработчики стали меньше ошибаться.
Покажи мне код
Разговоры дешевы. Покажите мне код , как однажды сказал Линус Торвальдс, и я полностью с ним согласен. Не переписывая документацию и не создавая страниц кода, приведу небольшой пример. Если вам интересно узнать все подробности о библиотеке и примере использования - вы можете найти ссылки в конце этой статьи.
Возьмем основную проблему - нам нужно создать CRUD для некоторой сущности. Например - задачи. Я не буду описывать здесь стандартную схему, поскольку любой, кто имел опыт работы с Redux, должен иметь некоторое представление о том, как она будет выглядеть. Нам нужно пройти следующие шаги, чтобы создать сообщение:
- Определить транспорт
2. Определите пространство имен
const namespace = ‘task’;
3. Разработайте стратегию общения
const strategy = new CRUDStrategy({ namespace, transport: taskTransport });
4. Создавайте общение
const taskCommunication = buildCommunication(strategy);
5. Настройте редукторы и коммуникационные саги.
taskCommunication.reducers taskCommunication.sagas
6. Осталось только подключить магазин к компоненту
taskCommunication.injector(MyComponent)
7. Коммуникация готова к использованию!
componentDidMount() { const { getTaskCollection } = this.props; getTaskCollection(); } render() { const { taskCollection } = this.props; return taskCollection.data.map(item => <span>{item.title}</span> ) }
В принципе, транспорт и компонент надо создавать в любом случае. Полный код для общения выглядит так:
Это все, что вам нужно знать для создания полнофункционального CRUD. Если вам нужно что-то более сложное, связь CRUD может быть расширена или может использоваться BaseCommunication. В худшем случае - старый добрый Redux со всеми функциями все еще остается на крючке. Гибкость по-прежнему сохраняется.
Транспорт вынесен на отдельный уровень и может быть реализован любым способом. Мы используем GraphQL и простые запросы с использованием аксиомов в нашем проекте, и у нас не было никаких проблем с этим.
Внимательные читатели могли заметить, что библиотека экспортирует саги. Это одно из ключевых ограничений. Если по каким-то причинам нельзя использовать саги - эта библиотека не подходит.
Почему сейчас?
Я решил поделиться нашим решением после прочтения нескольких статей и документации redux-toolkit. Опробовав этот инструмент, я понял, что общение стало намного проще, и в конечном результате структура магазина стала лучше (хотя и по-прежнему гибкой). После того, как я некоторое время возился с исходным кодом из примера redux-toolkit, я переписал его на сообщения. Я попытался внести минимальные изменения, чтобы вы могли увидеть разницу, хотя все же считаю, что структура исходного кода слишком сложна. Я оставил несколько комментариев, чтобы было легче отслеживать изменения. Обратите внимание на файлы * .communication.ts и фрагменты, которые они заменяют.
То, что количество строк уменьшилось, а код выглядит лучше (субъективный фактор), не так уж и важен, так как у нас довольно тяжелые коммуникации в продакшене. Есть еще одно ключевое отличие. Код декларативный. Мы просто объявляем что хотим получить и что делать с данными; нас совершенно не интересует, как это будет сделано. Подводя итог: redux-toolkit можно использовать для настройки, для всего остального вы можете использовать @ axmit / redux-communications.
Подводить итоги
Преимущества:
- Код стал стандартизированным во всех проектах и для всех разработчиков. Подобные проблемы имеют аналогичные решения, и обычно они переносятся в отдельные пакеты, которые могут быть повторно использованы в будущем. Количество кода сильно уменьшилось.
- Младшие разработчики получили четкое представление.
- Старшим разработчикам не нужно писать тонны стандартного кода, и они работают над улучшением коммуникаций.
- Отладка и структура магазина стали проще и прозрачнее для всех разработчиков.
- Переключение между проектами (или модулями проекта) не так болезненно, как раньше.
- Руководители проектов и клиенты довольны уменьшением количества ошибок. Разработчики тоже довольны - им нужно писать меньше кода.
- Вы можете переключаться на коммуникации итеративно или даже использовать гибридный подход (коммуникации + срезы).
- Покупатели получают товары примерно на 20% быстрее.
Конечно, у библиотеки есть и недостатки:
- Его сложно начать без изучения примеров кода и документации.
- Настроить структуру магазина невозможно, от этого зависит вся автоматизация. Однако у нас никогда не было проблем из-за этого ограничения.
- Можно работать только с сагами. Мы всегда ими пользуемся, и Thunk нам не подходил - так что для нас это никогда не было проблемой. Но если саги вам не подходят, пользоваться библиотекой будет невозможно.
Надеюсь, кто-то сочтет эту библиотеку полезной, несмотря на существующие ограничения. Если у вас есть предложения или вопросы - буду рад их обсудить. Или, если вы знаете какие-либо аналогичные (и лучшие) решения этой проблемы, мы также будем рады узнать о них.
Полное описание библиотеки можно найти здесь, а протестировать онлайн здесь.
Полный пример кода, переписанный на сообщение из документации ReduxToolkit, находится здесь и может быть протестирован здесь.