Внедрение архитектуры: от хаоса к порядку
Всем привет! Меня зовут Анатолий, я представляю команду Front-End разработки компании DD Planet. В этой статье расскажу о том, как наш проект завершил этап разработки и трансформировался в стабильный рабочий продукт.
Рождение
Проект стартовал в условиях сжатых сроков. Параллельно с этим возникла другая проблема - постоянное изменение требований. Каждый день приносил новые идеи и корректировки, которые приходилось срочно внедрять в уже существующий код. Это создало дополнительную нагрузку на команду и усложнило написание кода. В процессе интенсивной разработки команда сосредоточилась на бизнес-задачах и почти не уделяла внимания стратегическому развитию. Из-за высокой загруженности контроль над процессом существенно ослаб, что привело к негативным последствиям.
Проблемы
Из-за быстрой разработки сразу появились сложности:
- Хаотичная структура проекта - файлы и компоненты разбросаны случайным образом, отсутствует единый подход к организации кода, сложно добавлять фичи, так как непонятно, где их правильно разместить, отсутствие единого стиля написания;
- Высокая связность - правка в одном модуле неожиданно ломает другой, компоненты тесно переплетены между собой и не могут функционировать изолированно;
- Проблемы с переиспользованием кода - похожие компоненты дублируются, а не выносятся в общие модули, одни и те же кнопки, формы и стили ведут себя по-разному в разных частях приложения;
- Трудности масштабирования - внедрение нового функционала занимает больше времени, так как разработчик вынужден разбираться в имеющемся хаотичном коде;
- Сложности при интеграции новых сотрудников - отсутствие четких правил, каждый пишет код так, как считает нужным, новичкам нужно долгое время, чтобы начать эффективно работать.
Подготовка
В первую очередь было решено актуализировать основные библиотеки. Так как в процессе разработки проекта они успели обзавестись новыми версиями. В качестве библиотеки компонентов мы использовали Mantine, обновление которой до 7 версии потребовало много усилий по поддержанию несовместимых изменений. В качестве фреймворка используется Next.js, в процессе обновления которого мы поддержали новую систему маршрутизации - App Router. После реализации этих обновлений пришло время определиться с архитектурой проекта.
Выбор архитектуры
Мы определили для себя ряд критериев, которым должна соответствовать новая архитектура:
- Простота - понятные и однозначные правила организации кода;
- Масштабируемость - возможность быстро добавлять новый функционал;
- Командная работа - возможность параллельной разработки разными специалистами, быстрая интеграция нового сотрудника;
- Навигация - удобная система поиска компонентов и функциональности.
- Мы стали рассматривать популярные подходы к организации архитектуры проекта
Components/Containers
Проект делится на презентационные компоненты и контейнеры. Компоненты служат только для отображения данных, а контейнеры для хранения состояний и управления логикой работы приложения.

Минусы подхода:
- Сложность масштабирования - компоненты часто становятся монолитами, которые сложно комбинировать и переиспользовать. Вместо композиции небольших, компонентов, разработчики создают крупные, многофункциональные контейнеры;
- Дублирование логики между контейнерами - поскольку каждый контейнер инкапсулирует свою логику, часто возникает ситуация, когда одинаковый или очень похожий код появляется в нескольких контейнерах.
Atomic Design
Основан на аналогии с химией и представляет интерфейс как иерархию компонентов. Методология включает пять уровней иерархии:
- Атомы - базовые строительные блоки интерфейса (кнопки, шрифты, цвета, иконки, поля ввода). Это неделимые элементы, которые формируют основу системы;
- Молекулы - комбинации атомов, работающие как единое целое (форма поиска, поле ввода с кнопкой);
- Организмы - сложные блоки, состоящие из молекул и атомов (хедер, футер, карточки товаров);
- Шаблоны - каркасы страниц с определенным расположением организмов;
- Страницы - финальные версии с реальным контентом.

Минусы подхода:
- Несоответствие реальным бизнес-требованиям - бизнес-логика часто не укладывается в чистую иерархию;
- Проблемы с переиспользованием - компоненты становятся слишком абстрактными и обрастают десятками параметров для всех случаев.
Feature Sliced Design (FSD)
Feature-Sliced Design - это архитектурная методология для фронтенд-приложений, созданная сообществом разработчиков. Она фокусируется на бизнес-логике и обеспечивает масштабируемость, поддерживаемость. Ссылка на проект здесь.
Слои стандартизированы во всех проектах FSD:
- App - все, благодаря чему приложение запускается - роутинг, точки входа, глобальные стили, провайдеры и т. д.;
- Pages (страницы) - полные страницы или большие части страницы при вложенном роутинге;
- Widgets (виджеты) - большие самодостаточные куски функциональности или интерфейса, обычно реализующие целый пользовательский сценарий;
- Features (фичи) - повторно используемые реализации целых фич продукта, то есть действий, приносящих бизнес-ценность пользователю;
- Entities (сущности) - бизнес-сущности, с которыми работает проект, например user или product;
- Shared - переиспользуемый код, отделенный от специфики проекта/бизнеса, хотя это не обязательно.

Минусы подхода:
- Высокий порог входа и сложность обучения - FSD требует значительного времени на освоение всеми членами команды;
- Субъективность и споры о принадлежности - разные интерпретации правил разными членами командами, споры о принадлежности компонента к тому или иному слою.
Внедрение
Ни одна из описанных архитектур в полной мере не удовлетворяла всем критериям, поэтому нам пришлось пойти своим путем. В качестве основы была выбрана методология Feature-Sliced Design (FSD) с ее идеей разбиения компонентов на слои и наличием подробной документации. При этом мы отказались от жесткой структуры чтобы получить возможность более гибкой настройки импортов.

Каждый из этих слоев, кроме shared, может в свою очередь тоже делиться на слои по необходимости. Здесь нами использовалась уже привычная структура из FSD, однако мы заменили features и entities на common, так как они и порождали больше всего споров, стали отталкиваться в первую очередь от структуры самих страниц. Фактически Feature-Sliced Design (FSD) превратился в Page-Sliced Design (PSD).

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

Чтобы минимизировать споры о принадлежности к тому или иному слою, было решено применять принцип local first. Таким образом компоненты находятся максимально близко к месту использования и перемещаются на базовый уровень только в том случае, если начинают использоваться на нескольких слоях. Для организации самих компонентов была выбрана упрощенная структура, состоящая из components, shared и файла самого компонента. В случае с модальниками, или чем-то подобным, в корень добавляется еще и функция для взаимодействия.


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

Зоны вычисляются на основе иерархии

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