6 концепций, которые нужно освоить архитектору Angular-приложений

в 15:18, , рубрики: angular, javascript, Блог компании RUVDS.com, разработка, Разработка веб-сайтов, Учебный процесс в IT

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

6 концепций, которые нужно освоить архитектору Angular-приложений - 1

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

1. Архитектура, модули и библиотеки

В мире веб-разработки модульная архитектура Angular — это нечто особенное. Вероятно, это одна из таких идей, которые хуже других усваиваются новичками.

Самое сложно здесь заключается в том, что в веб-разработке уже используется модульная архитектура. Я, конечно, говорю об ES6-импортах.

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

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

▍Разные типы Angular-модулей

Существуют различные типы Angular-модулей, о которых нужно знать:

  • Declarations/Widget Module. Модули с объявлениями различных сущностей. В качестве примера подобных модулей можно привести наборы компонентов пользовательского интерфейса, директив, пайпов.
  • Services Module. Модули сервисов. Например — HttpClientModule.
  • Routing Module. Модули маршрутизации.
  • Domain Feature Module. Модули, реализующие ключевые задачи приложения.
  • Core/Shared Module. Core-модуль — это модуль для объявления глобальных сервисов. Shared-модуль — это модуль, в котором объявляют компоненты для совместного использования.

Вот материал, в котором можно найти подробности об Angular-модулях.

▍Библиотека или модуль?

Я сказал бы, что вышеозначенное различие между модулями можно распространить и на библиотеки. При таком подходе окажется, что может существовать библиотека, содержащая только сервисы, библиотека, представляющая маршрут, и так далее.

Но то, создают ли модуль или библиотеку, сильно зависит от типа проекта, и от того, представлен ли проект монорепозиторием или несколькими репозиториями.

▍Вопросы, которые следует задать себе перед созданием модуля

Вот несколько вопросов, которыми стоит задаться перед написанием модуля:

  • К какой именно разновидности модулей относится создаваемый модуль? Если вы не можете ответить на этот вопрос — это значит, что вам нужно поближе познакомиться с вышеперечисленными типами модулей. Весьма вероятно то, что при ответе на этот вопрос придётся упомянуть один или два типа модулей. В частности, речь идёт о модулях маршрутизации и модулях сервисов.
  • Нужно ли оформить этот модуль в виде библиотеки, или он может быть обычным модулем? Ответ на этот вопрос найти немного сложнее. Я полагаю, что если используется монорепозиторий, то имеет смысл ориентироваться на разработку библиотек. Это, в долгосрочной перспективе, себя оправдает.

2. Разделение ответственности между компонентами, сервисами и директивами

Разделение ответственности — это, в теории, просто. А вот на практике это уже сложнее. Разработчики, со времён Angular.js, знали о том, что компоненты надо делать как можно компактнее, а сервисы стоит делать более масштабными. В новых версиях Angular эти идеи не претерпели особых изменений.

И в наши дни важно иметь представление о том, что именно должно входить в состав компонентов, что — в состав сервисов, а также учитывать то, что директивы, возможно, являются весьма сильно недооценённой возможностью Angular.

▍Состояние

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

  • Если компоненты совместно используют состояние, или к состоянию нужно обращаться из сервисов, тогда состояние стоит хранить в сервисе. При этом, если состояние хранится в сервисе, не играет особой роли то, какие именно инструменты управления состоянием используются.
  • Если состояние является локальным (например — речь идёт о форме) и используется только внутри компонента, тогда состояние стоит просто сохранить в компоненте.

▍Работа с DOM

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

Уверен, вы в такой ситуации сможет создать компонент и осуществить привязку соответствующих событий из него, но, если так и сделать, будут смешаны два явления:

  • Описание внешнего вида компонента.
  • Определение поведения компонента.

Директивы — это возможность Angular, позволяющая описывать механизмы, предназначенные для многократного использования. Почти в каждом проекте, над которым мне довелось работать, я замечал недостаточно широкое использование директив. Директивы могут взять на себя немалую долю ответственности компонентов.

Вот вам упражнение: найдите в своём текущем проекте самый большой, по количеству строк кода, компонент. Используется ли в нём Renderer или ElementRef? Соответствующая логика, скорее всего, может быть перенесена в директиву.

3. Обнаружение изменений и рендеринг

Когда речь идёт о повторном рендеринге пользовательского интерфейса, то в Angular всё делается как по волшебству, с использованием внутренних механизмов фреймворка.

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

Архитектору Angular-приложения, вероятно, стоит знать о том, что для оптимизации производительности рендеринга применяется стратегия обнаружения изменений onPush. Но в ходе работы всё не всегда идёт так, как ожидается. Особенно тогда, когда в шаблонах не используют наблюдаемые объекты и асинхронные пайпы.

▍Совершенствование обнаружения изменений

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

  • Нужно рассматривать все данные как иммутабельные. Здесь могут очень пригодиться библиотеки для управления состоянием, основанные на Rx.
  • Для вывода данных в шаблонах стоит использовать только (или преимущественно) наблюдаемые объекты. При использовании локального состояния стоит применять BehaviorSubject.

Если вы стремитесь к разработке высокопроизводительных Angular-приложений — вам просто необходимо очень хорошо разобраться с вопросами обнаружения изменений. Дело в том, что высокая производительность — это даже не «обновление интерфейса тогда, когда это нужно». Это — «обновление интерфейса только тогда, когда это нужно».

▍Преодоление ограничений производительности Angular

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

Если вам и правда надо выжать из Angular абсолютный максимум производительности, это значит, что вам стоит прибегнуть к методике, предусматривающей избавление от Zone.js и точное обновление интерфейса с использованием свежих возможностей Ivy. Вот материал об этом.

4. Маршрутизация

Маршрутизация — это не только представление SPA в виде множества виртуальных страниц. Это ещё и загрузка бандлов приложения по запросу с использованием возможностей по ленивой загрузке материалов подсистемы маршрутизации Angular.

Если вы работаете над большим приложением и размеры бандлов этого приложения превышают 1 Мб, то вы, вероятно, уже знаете о том, почему это важно. И правда, никому не покажется заманчивой перспектива загрузки огромных объёмов данных для того чтобы поработать с неким приложением.

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

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

▍Пример: компонент с вкладками

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

Хотите ещё пример? Как насчёт всплывающих и модальных окон? Их код совершенно не нужно включать в состав материалов, входящих в первоначально загружаемый бандл проекта. Код таких окон есть смысл загружать только тогда, когда они нужны, но не раньше.

Если вам хочется, перед применением подобных идей, чем-то вдохновиться, предлагаю взглянуть на документацию компонента @angular/material/tabs, в котором реализован вышеописанный паттерн.

5. Формы

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

Большинство ваших форм, вероятно, будет использовать модуль ReactiveFormsModule. А если они не состоят из единственного элемента управления, то в них, с использованием ngModel, будет реализована двусторонняя привязка данных.

API Angular, предназначенный для работы с формами, довольно просто освоить. Для того чтобы достичь совершенства в использовании этого API, в общем-то, достаточно как следует изучить документацию и знать о том, какие проблемы могут возникать при работе с формами.

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

6. RxJS

И последней в нашем списке, хотя — не последней по значимости, идёт технология RxJS.

Я убеждён в том, что одной из самых мощных возможностей Angular является глубокая интеграция этого фреймворка с Rx и с функциональным реактивным программированием.

Для того чтобы по-настоящему хорошо освоить Angular, открыв дорогу к проектированию качественных приложений, сначала нужно изучить Rx, или, по меньшей мере, самые важные операторы. Сложно быть по-настоящему продвинутым Angular-разработчиком, не потратив немало часов на то, чтобы понять Rx.

У того факта, что изучение Rx помогает в разработке Angular-приложений, есть две причины: производительность и асинхронная обработка данных.

Асинхронная обработка данных — это особенно сложная задача в современных, высокоинтерактивных приложениях. Поэтому стоит забыть о промисах, о setTimeout и о setInterval, и начать работать в стиле Rx.

Ещё одна серьёзная причина изучения Rx заключается в оптимизации производительности приложений. Конечно, для начала достаточно использовать асинхронные пайпы, но иногда этого недостаточно. Управлять повторным рендерингом компонентов, например, можно, пропуская через пайп только те события, возникновение которых подразумевает необходимость в повторном рендеринге.

Rx даёт разработчику множество операторов, которые способны помочь ему в кэшировании чего-либо, или в сборке чего-либо в пакеты. А это, как результат, ведёт к оптимизации производительности приложений. Вот материал о паттернах RxJS.

Итоги

Я привёл здесь небольшой список тем, которые стоит изучить тому, кто стремится стать высокоэффективным Angular-разработчиком, или тому, кто хочет быть архитектором Angular-приложений.

В этот список можно добавить ещё очень много всего. Но, кроме прочего, предлагаю не забывать о том, что для того чтобы по-настоящему хорошо изучить что-то, относящееся к миру веб-разработки, нужно начинать с основ. Это — JavaScript, CSS, паттерны проектирования, методики написания чистого кода, инструментарий и многое другое.

А что бы вы посоветовали изучить тем, кто хочет научиться проектировать качественные Angular-приложения?

6 концепций, которые нужно освоить архитектору Angular-приложений - 2

Автор: ru_vds

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js