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

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

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

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

Проверьте, правильно ли структурирован ваш проект с Bit.dev

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

Вы можете использовать Bit.dev, концентратор облачных компонентов, для публикации (и документирования) компонентов Angular (из любой кодовой базы, над которой вы работаете) в общую коллекцию компонентов на Bit.dev. .

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

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

Таким образом вы убьете двух зайцев одним выстрелом:

  1. У вас есть способ проверить, правильно ли структурирован ваш проект
  2. Вы можете публиковать независимые компоненты, чтобы вы и ваша команда могли повторно использовать их в других проектах / репозиториях.

Распространенные ошибки при определении структуры угловых компонентов

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

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

my-app
├── src
│   ├── App
│       ├── shared
│           ├── shared_component_1
│       ├── component_1
│           ├── sub_component_1
│               ├── sub_component_1.html
│               ├── sub_component_1.ts
│               ├── sub_component_1.spec.ts
│               ├── sub_component_1.scss
│           ├── sub_component_2
│               ├── sub_component_2.html
│               ├── sub_component_2.ts
│               ├── sub_component_2.spec.ts
│               ├── sub_component_2.scss
│       ├── component_2
│           ├── component_2.html
│           ├── component_2.ts
│           ├── component_2.spec.ts
│           ├── component_2.scss
│       ├── component_3
│       ├── app.component.html
│       ├── app.component.scss
│       ├── app.component.ts
│       ├── app.module.ts
│   ├── environments
│   ├── assets
│   ├── index.html
│   ├── main.ts
├── package.json
├── node_modules

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

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

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

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

Так что же нам здесь не хватает? Как мы можем предотвратить возникновение проблемы?

Введение в страницы, контейнеры и представления

Чтобы решить проблему, упомянутую выше, нам необходимо определить основную причину проблемы. Мы видим, что не все компоненты одинаковы. Некоторые из них являются родительскими компонентами, некоторые - дочерними, а некоторые - общими.

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

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

my-app
├── src
│   ├── App
│       ├── view_components
│           ├── view_component_1
│           ├── view_component_2
│           ├── view_component_3
│           ├── view_component_4
│           ├── view_component_5
│       ├── container_components
│           ├── container_component_1
│           ├── container_component_2
│           ├── container_component_3
│       ├── page_components
│           ├── page_component_1
│           ├── page_component_2
│       ├── app.component.html
│       ├── app.component.scss
│       ├── app.component.ts
│       ├── app.module.ts
│   ├── environments
│   ├── assets
│   ├── index.html
│   ├── main.ts
├── package.json
├── node_modules

Чтобы дать общее представление, компонент страницы имеет дочерние компоненты контейнера. Затем каждый компонент-контейнер имеет дочерние компоненты View (Страницы - ›Контейнеры -› Представления). Чтобы помочь вам понять структуру, я буду объяснять различные роли каждого типа компонентов, идущих изнутри наружу.

Просмотр компонентов

Компоненты представления - это компоненты пользовательского интерфейса, которые составляют визуальные элементы. Это глупые компоненты, которые принимают данные извне и запускают события для таких действий, как нажатие кнопки. Эти пользовательские компоненты обычно представляют собой композицию элементов пользовательского интерфейса из таких библиотек, как ng-bootstrap или Angular Material, созданных для бизнес-функций.

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

Компоненты контейнера

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

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

Как видите, компоненты контейнера - это центр соединения вещей, работы с бизнес-логикой, делегирования представления компонентам представления.

Компоненты страницы

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

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

Глядя на общую картину

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

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

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

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

Учить больше