Обеспечьте долгосрочную стабильность разработчика при умеренной первоначальной стоимости

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

Цель:

Служить ссылкой для всех, кто пишет новое приложение React и принимает решение о его конфигурации, в частности, включать ли Redux и / или TypeScript.





Вступление:

В феврале 2017 года я написал версию 2048 на React. Игра казалась идеальным способом поэкспериментировать с однонаправленной структурой потока данных React: действие пользователя вызывает изменение внутреннего состояния (то есть нажатие на клавиатуру приводит к изменению игрового поля), а изменения обрабатываются React. Удовлетворенный результатом, я переписал приложение с нуля в апреле, написав на TypeScript и включив хранилище Redux для управления состоянием.

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

Дополнительные подробности, относящиеся к Redux или TS, описаны ниже.

Redux:

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

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

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

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

TypeScript:

Кривая обучения TypeScript более постепенная, поскольку нет строгих правил по его реализации; вы можете использовать столько (или меньше) его функций, сколько необходимо, что означает, что он позволяет постепенно добавлять в свой код по мере того, как ваше понимание TS становится более зрелым.

Более очевидные преимущества TS - это фактор степени объектно-ориентированного программирования, необходимого для приложения. В игре 2048 данные, необходимые для отслеживания состояния игры, хранятся в виде объекта, определенного пользователем. Класс платы в TS имеет структуру, описанную ниже:

Обратите внимание, что многие из используемых здесь конструкций не относятся к конкретному коду TS; class, get и set были добавлены в ES2015 в качестве синтаксического сахара в существующей системе наследования прототипов.

TS позволяет здесь двояко: реализовать дополнительные функции, доступные в других объектно-ориентированных языках, таких как C #, и заблаговременную проверку типов. Этот класс включает инкапсуляцию, которая не является частью стандартного поведения объекта JavaScript; Хотя в JavaScript есть обходные пути для получения аналогичных результатов, он значительно усложняет код. Во многих случаях специфичность типа TS предотвращает ошибочный код: например, в редукторах Redux это может гарантировать, что тип возвращаемого значения редуктора по крайней мере останется того же типа после обработки действия.

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

Менее очевидные преимущества присущи React. Компоненты React используют общие при использовании с TypeScript, что означает, что разработчики должны предоставлять формы свойств.

Это гарантирует, что каждому экземпляру ваших компонентов React предоставлены соответствующие свойства; если чего-то не хватает, приложение не скомпилируется.

Главный недостаток добавления TypeScript в проект React связан с реалиями продукта с открытым исходным кодом. В моем примере я отказался от первоначального плана по реализации React Router, в значительной степени потому, что в последней версии 4 React Router доступные определения типов не полностью функциональны; Поскольку разработчики React Router не заинтересованы в поддержке самих определений типов, сообщество разработчиков ПО с открытым исходным кодом должно поддерживать определения типов, которые неизбежно будут различаться по качеству. Эмпирическое правило кажется, что любой пакет, доступный для разработки JavaScript через NPM, будет иметь аналогичные проблемы, если только пакет не пользуется большим спросом (например, React) или разработчики пакетов сами не используют TypeScript (например, Angular).

Примечания:

  • Метод dispatch хранилища Redux возвращает действие, переданное методу в качестве аргумента. (т.е. dispatch(A) => A) Это означает, что изменение состояния посредством отправки теоретически является побочным эффектом. Это на удивление легко сбить с толку, поскольку обычно dispatch вызывается не с действием, а с возвращаемым значением создателя действия. (т.е. dispatch(creator(B)) => A где creator(B) => A, поэтому наблюдаемый результат A функции диспетчеризации по определению выглядит точно так же, как результат создателя действия.)
  • TypeScript выдает ошибки раньше времени; это означает, что любая ситуация, которая может потребовать обработки ошибок во время выполнения, по-прежнему потребует соответствующего кода, например throw, try, catch и т. Д.
  • Для Redux может быть полезно реализовать различные интерфейсы, унаследованные от интерфейса Action. Если вы это сделаете, вы можете утверждать свои типы в редукторе, используя as.

Заключение:

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

To-Do:

Вы могли заметить, что в этой статье не обсуждается производительность. На момент написания этой статьи я не проводил обширных тестов по аспектам скорости / ресурсов двух приложений. Упущение было в значительной степени из-за маловероятной разницы в производительности, особенно в масштабе и масштабе проекта; обе версии достаточно просты, чтобы работать без дополнительных оптимизаций.

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

Ресурсы: