Как управлять интерфейсным одностраничным приложением со 100 000 строк кода

Архитектура JavaScript ORM внешний фреймворк

Об авторе Директор Ant Financial Data Experience Техническая группа

Группа внешнего интерфейса платформы данных Ant Financial в основном отвечает за несколько одностраничных веб-приложений для ПК, связанных с данными. Бизнес-сложность аналогична сложности настольных приложений, таких как Excel. Объем внешнего бизнес-кода варьируется от десятков от тысяч до сотен тысяч строк.С постоянным улучшением продуктов, разбить миллион не за горами. Управление интерфейсными приложениями со 100 000 или даже миллионами строк кода — одна из основных задач нашей команды.

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

  • Интерфейсная архитектура
  • Гарантия качества
  • оптимизация производительности
  • Процесс фронтенд-разработки в команде
  • Качество персонала

Интерфейсная архитектура

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

Функции

Во-первых, давайте представим особенности продукта нашей команды:

  • Продукты ToB имеют высокую сложность бизнеса и высокий порог понимания бизнеса;
  • Объем внешнего кода огромен (продукт анализа данных прошел 8 месяцев итерации с нуля с 80 000 строк бизнес-кода, и только 20% требований долгосрочного планирования продукта были реализованы)

Схема архитектуры

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

1. Сначала вырезайте функциональные модули с детализацией «на уровне страниц» посредством маршрутизации.

Детализация «на уровне страницы» здесь относится к компоненту с отображением маршрута.

router

2. Разделение модулей на одной «странице»

Принцип деления:

  • портрет: Разделено по бизнес-функциям (о которых можно судить по модулю просмотра)
  • горизонтальный: разделен на три разные функции Model-View-Controller

module

3. Объединяйте похожие элементы

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

3.1 Модель данных

Модели данных делятся на две категории в зависимости от обязанностей:

  1. Модель предметной области Модель предметной области
  2. Модальная модель состояния приложения
3.1.1 Модель предметной области

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

  • Информация о пользователях
  • Наборы данных Информация о наборе данных
  • Отчеты сообщают информацию

В качестве общедоступных данных модель предметной области рекомендуется хранить в единомDomain Model LayerАрхитектура является независимой многоуровневой (отрасль фронтенда обычно называет этот уровень уровнем ORM).

Погружение в уровень модели предметной области имеет много преимуществ:

  • Проблема межмодульной синхронизации данных больше не существует, например: Ранее объект «Пользователи» хранился отдельно в двух бизнес-модулях A и B. После изменения объекта «Пользователь» в модуле A изменение «Пользователи» необходимо синхронизировать с модулем B. Если оно не синхронизировано, информация о пользователе, представленная модулями A и B на интерфейсе, несовместима, после перехода на уровень модели предметной области для унифицированного управления проблема больше не существует;
  • Помимо повторного использования модели предметной области, также можно повторно использовать редукторы CRUD, связанные с моделями предметной области., например: предыдущий метод Create Read Update Delete, соответствующий объекту Users, может поддерживать по одному набору в каждом из двух бизнес-модулей A и B, а после перехода на уровень модели предметной области для унифицированного управления проблема дублирования кода уменьшается ;
  • Естественно, взял на себя некоторые обязанности по обмену данными между модулями.код межмодульной связи, ранее связанный с синхронизацией данных, больше не нужен;
3.1.2 Модель состояния приложения

Модель состояния приложения — это данные состояния, связанные с представлением, такие как:

  • Текущая страница выбирает n-ю строку списка currentSelectedRow: someId
  • Открыто ли окно isModalShow: false
  • Перетаскивается ли определенный элемент представления isDragging: true

Эти данные тесно связаны с конкретными модулями представления или бизнес-функциями, и их рекомендуется хранить в модели бизнес-модуля.

3.2 Просмотр компонентов слоя

Компоненты делятся на две категории в соответствии с их обязанностями:

  1. Компонент контейнера
  2. Презентационный компонент
3.2.1 Компоненты контейнера

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

3.2.2 Компоненты дисплея

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

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

3.3 Государственные услуги

  • Все HTTP-запросы объединяются для унифицированного управления;
  • Служба журнала, служба локального хранилища, мониторинг ошибок, фиктивная служба и т. д. единообразно хранятся на уровне общедоступных служб;

После объединения схожих элементов в соответствии с тремя вышеуказанными пунктами диаграмма бизнес-архитектуры изменяется на

api

4. Межмодульное взаимодействие

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

  • Не допускается прямой вызов метода Dispatch других модулей внутри модуля (операции записи, изменение состояния других модулей)
  • Не допускается прямое чтение метода состояния других модулей внутри модуля (операция чтения).

Мы рекомендуем размещать логический код для межмодульной связи в родительском модуле или вMediatorОтдельно хранится слоями.

Наконец, мы получаем полную диаграмму архитектуры бизнес-логики нашей команды:

Architecture

управление потоком данных

Я только что говорил о схеме управления архитектурой из пространственного измерения, а теперь я говорю о потоке данных приложения из временного измерения — одностороннем потоке данных Redux.

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

redux

1. Action

  • Поведение пользователя: нажмите и перетащите ввод...
  • Сервер возвращает последующее поведение данных

2. Reducer

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

Характеристика чистых функций заключается в том, что при одинаковых входных параметрах возвращаемое значение одинаково, например:

Чистая функция:

function add(a, b) {
	return a + b;
}

Нечистая функция:

function now() {
	let now = new Date();
	return now;
}

Если функция содержитMath.random,new Date(), асинхронные запросы и т.п., и влияют на возврат конечного результата, то есть нечистой функции.

3. Store

Хранилище — это место, где хранятся данные. В хранилище хранится состояние данных (состояние), созданное всеми операциями Action с момента входа на страницу. Каждое изменение данных, вызванное действием, должно генерировать новый объект состояния и гарантировать, что старый объект состояния не модифицированный. Это гарантирует Предсказуемое и отслеживаемое состояние приложения также облегчает разработку функций Redo/Undo.

Наша команда использует легкое неизменное решениеimmutability-helper, который имеет лучшую производительность и более высокий уровень использования дискового пространства, чем полная копия (глубокое клонирование).

immutability-helper

immutability-helperAPI недостаточно дружелюбный, мы написали библиотекуimmutability-helper-xповысить удобство его использования.

Стиль API-помощника неизменности:

import update from 'immutability-helper';

const newData = update(myData, {
  x: {
  	y: {
			z: { $set: 7 }
		}
	},
});

Стиль API immutability-helper-x:

import update from 'immutability-helper-x';

const newData = update.$set(myData, 'x.y.z', 7);

4. Единый вид рендеринга

React/Redux — это типичная среда разработки, управляемая данными (Data-Driven-Development).В процессе разработки мы можем больше сосредоточиться на работе и потоке данных (модель предметной области + модель состояния) и больше не беспокоиться о различные громоздкие коды манипулирования DOM, когда хранилище изменится, платформа React/Redux поможет нам автоматически и единообразно отобразить представление.

Функция прослушивания изменений Store для обновления представления выполняется react-redux:

  • компонент черезcontextАтрибут предоставляет объект хранилища потомкам компонентов ;
  • — это высокоуровневый компонент, который используется для подключения компонентов хранилища и уровня представления (это повторяется здесь, redux официально определяет компонент, напрямую подключенный через , как компонент-контейнер), а — открыто для разработчиков.Хук функции обратного вызова (mapStateToProps, mapDispatchToProps...) используется для настройки положения реквизита, введенного в компонент-контейнер;
  • react-redux прослушивает изменения в хранилище избыточности. После изменения хранилища он уведомляет каждый компонент подключения о необходимости обновить себя и его дочерние компоненты. Чтобы уменьшить количество ненужных обновлений и повысить производительность, подключение реализует метод shouldComponentUpdate. Если реквизиты остаются неизменными , контейнер пакета подключения не будет обновляться.

Суммировать

Строгое следование спецификации архитектуры и спецификации одностороннего потока данных может обеспечить ремонтопригодность и масштабируемость наших клиентских приложений с относительно грубой детализацией.Для более мелкозернистого кода мы организуем детскую обувь, чтобы учиться и делиться ею."Шаблоны проектирования"а также«Рефакторинг — улучшение дизайна существующего кода», продолжать полировать и оптимизировать собственный код, и в будущем команда продолжит выпуск серии статей по этому поводу.

В этой статье сначала рассказывается об общей архитектуре интерфейса, а бизнес-архитектура конкретных модулей, принципы, которым следует архитектура, а также процесс обзора архитектуры группой по архитектуре команды будут описаны в следующей серии статей. Заинтересованные студенты могут следить за колонкой или отправлять свои резюме на tao.qit####alibaba-inc.com'.replace('####', '@'). Приглашаются люди с высокими идеалами~

Оригинальный адрес:GitHub.com/proto team/no…