Эта статья является частью серии:

  1. Архитектура Angular + FLUX - Введение
  2. Angular + FLUX - гибридное приложение
  3. Гибридное приложение Angular - опережающая компиляция

AngularJs давно не считался современным фреймворком. Последняя версия (сейчас 1.6.9) не дает нам существенных улучшений, и даже ее авторы рекомендуют как можно скорее перейти на Angular.

Пока мы разрабатывали Admin - приложение, использующее AngularJs, - наступил момент, когда нам нужно было принять решение о процессе обновления.

Мы рассматривали два варианта:
1. разработать новое приложение с нуля; или
2. выберите более подходящее решение - гибридное приложение

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

Более того, высокие приоритеты бизнеса часто прямо противоречат приоритетам программиста. По этим и многим другим причинам мы в итоге выбрали гибридный подход к приложению.

В гибридном приложении вы одновременно запускаете AngularJs и Angular.

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

Как началось обновление

Мы неоднократно пытались перейти с AngularJs на Angular. Ни один из них не увенчался успехом. В одних попытках это было из-за недостатка знаний, в других - из-за неполной документации со стороны команды Angular. Кроме того, были различные сложности, специфичные для Admin (например, настраиваемая конфигурация Webpack, несколько устаревших поставщиков и т. Д.). Наша команда поняла, что Админ не готов к таким изменениям.

Последняя возможность обновиться появилась, когда мы решили обновить одну из основных функций администратора - модуль EventSettings. Идея заключалась в том, чтобы избавиться от ошибочного кода, хотя нашей основной целью было улучшение UX и UI. Поэтому мы решили полностью переписать этот модуль.

Это была отдельная часть Admin, и при необходимости мы могли достаточно легко протестировать A / B на небольшой выборке пользователей Slido.

Создание корневого модуля

Первым шагом было и всегда должно быть обширное исследование. Список рекомендуемых публикаций включен в конце статьи.

А каков результат нашего исследования? Это было несколько строк кода, которые представляли корневой модуль для нашего гибридного приложения:

Корневой модуль содержит исходный модуль AngularJs (строка 2), новый модуль Angular (строка 10) и бутстрап гибридного приложения (строки 22 и 26). Вот и все. Простой.

Загрузка гибридного приложения подробно описана в руководстве, предоставленном командой Angular.

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

Узнаем о NgRx

В нашей предыдущей статье мы описали проблемы, с которыми мы столкнулись в связи с нашей кастомной реализацией архитектуры FLUX.

В процессе обновления мы подумали о том, чтобы попробовать какого-нибудь поставщика, который уже реализует FLUX или который мог бы нам в этом помочь. Было доступно несколько вариантов, например: Redux, NgRx, RefluxJs и так далее.

В итоге мы выбрали NgRx из-за его полной совместимости с парадигмой реактивного программирования, которая очень популярна в мире Angular.

Изменение схемы архитектуры

Теперь мы объясним, как изменилась исходная диаграмма после использования NgRx. Позже мы перейдем к конкретным изменениям в нашем приложении и сравним его с нашим индивидуальным решением.

В реализации FLUX с использованием NgRx данные передаются напрямую от компонентов через Dispatcher к редукторам. Редукторы изменяют части глобального состояния приложения.

Вместо того, чтобы генерировать событие об изменении состояния из Store, мы реализовали Selectors, на которые мы можем подписаться в контроллере компонентов (мы используем «реактивность» среды).

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

Эффекты прослушивают действия, отправленные из @ ngrx / store. Они изолируют побочные эффекты от компонентов, позволяя создавать более чистые компоненты, которые выбирают состояние и отправляют действия. Они предоставляют новые источники действий для уменьшения состояния на основе внешних взаимодействий, таких как сетевые запросы, сообщения веб-сокетов и события, зависящие от времени.

Эффекты будут реализовывать бизнес-логику, которая раньше была в Действиях.

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

Примеры кода FTW

Обновленная структура папок может быть следующей:

I. View + Controller

Как видим, View практически не изменился:

Возможно, наиболее важное изменение связано с действиями, из которых удаляются привязки для обратных вызовов действий конкретных компонентов. После обновления мы вызываем их прямо из контроллера компонента EventsEventItem. Это изменение было внесено из-за нашего неписаного правила: для каждого модуля должен быть только один файл для действий. То же самое относится к эффектам, редукторам и селекторам.

Контроллер тоже намного проще:

В нашем решении подписки заменили обработчики событий из предыдущего. Мы подписываемся на этапе инициализации компонента в методе конструктора и отказываемся от подписки в методе ngOnDestroy.

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

II. Действия

Действия - это список действий, которые можно использовать в этом модуле:

Главное преимущество такого подхода - строгий контроль типов. Каждый программист, работающий над большим проектом, должен это оценить.

III. Эффекты

Так могут выглядеть так называемые эффекты:

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

Эффекты требуют от программиста максимальных усилий, потому что, поскольку они используют в основном RxJ, они содержат все части парадигмы реактивного программирования. Когда программист преодолевает это «препятствие» - большая АГА! следует момент, после которого все становится кристально чистым.

IV. Редукторы + Селекторы

Последние части нашей головоломки - это редукторы и переключатели:

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

Итак, мы переместили бизнес-логику из Store из предыдущей пользовательской реализации в Reducer, в то время как методы «get» из Store были заменены на Selectors.

V. Модуль

Теперь мы хотим склеить все части вместе, поэтому мы создаем EventsModule. См. ниже.

Помимо общих частей модуля нам необходимо зарегистрировать Сервисы, Компоненты и так далее. Здесь мы зарегистрировали также Эффекты и Редукторы.

Особенности гибридного применения

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

В модифицированный корневой модуль мы добавили инициализацию редукторов и эффектов. Эффекты для отдельных подмодулей в гибридном приложении регистрируются особым образом (строка 40).

И, наконец, последний шаг прост:

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

Какие проблемы решает NgRx?

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

Несколько магазинов: они были заменены одним глобальным магазином, предоставляемым NgRx. Селекторы заботятся об обработке особых случаев, вызванных асинхронной природой приложения. Для каждого подсостояния мы реализовали специальный селектор, и всякий раз, когда нам нужно использовать комбинированные состояния, мы используем комбинированные селекторы.

Они запоминаются, поэтому нет накладных расходов на производительность приложения.

Слишком много написания: это не так сильно изменилось. Мы поддерживаем ясность кода, следуя всем лучшим практикам, рекомендованным авторами NgRx и RxJs. Это легко увидеть в Эффектах, а также в разделении бизнес-логики на Редукторы и Селекторы.

Клонирование данных: проблема с копированием / клонированием ссылок на объекты все еще существует. Но для предотвращения такого рода проблем мы используем отличный инструментарий, поставляемый с NgRx. Одним из таких инструментов является ngrx-store-freeze (метаредуктор), который использует Object.freeze () под капотом и уведомляет нас о неправильном использовании глобального состояния. Также нельзя не упомянуть Redux DevTools.

Подведение итогов

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

Источники