Чистая архитектура фронтенда

В этой статье речь пойдет об архитектуре фронтенда, проектирование которой подчиняется множеству принципов, в том числе SOLID, KISS, DRY и DDD.

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

В чем важность архитектуры фронтенда?

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

 Что представляет собой архитектура фронтенда?

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

Ниже представлен простой проект TripAgency.

Уровневая архитектура фронтенда

Какие уровни используются?

  • API: DTO (data transfer objects, объекты переноса данных) и сервисы, генерируемые Open-API Generator.
  • Service: включает в себя мапперы (DTO во фронтенд-модель и наоборот) и сервисы, которые взаимодействуют с API через конечные точки REST.
  • Store: глобальное хранилище, содержащее все данные, получаемые из уровня Service.
  • Booking: домен, включающий модели и компоненты. Smart-компоненты (интеллектуальные) взаимодействуют непосредственно с хранилищем, а dumb-компоненты (неинтеллектуальные) могут применяться более чем в одном контексте, поскольку они гораздо примитивнее.

Что может пойти не так при такой архитектуре?

Если правила не определены, то разработчики могут напрямую использовать DTO в своих компонентах или контактировать с уровнем Service, минуя уровень Store. Или, что еще хуже, dumb-компоненты могут контактировать с уровнем Service.

Что нужно сделать для предотвращения этих ошибок?

Просто определить правила, которые не допустят подобного. Одним из наиболее распространенных подходов является введение в проект Bit или Nx.

Bit и Nx  —  это мощные системы сборки с открытым исходным кодом, предоставляющие инструменты и методики для повышения производительности разработчиков, оптимизации работы CI и поддержания качества кода.

Как в Bit, так и в Nx можно применять правила зависимостей. Поэтому разработчик получит ошибку, если будет использован не тот уровень.

Это правильный подход, но как убедиться в том, что сам домен (в приведенном примере домен Booking) остается поддерживаемым?

Применим некоторые концепции DDD (Domain Driven Design) к домену Booking. Для этого разобьем домен Booking на несколько поддоменов. Каждый поддомен имеет собственный ограниченный контекст и единый язык. Это может выглядеть так, как показано на рисунке ниже.

Применение концепций DDD

Каждый поддомен использует уровневую архитектуру, взаимодействуя с другими поддоменами через API. Feature (уровень функций) включает в себя smart-компоненты и сервисы, UI (уровень пользовательского интерфейса)  —  dumb-компоненты, Domain (уровень домена)  —  модели, а Util (уровень служебных функций)  —  все функции, используемые в данном ограниченном контексте.

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

Какие принципы следует применять к компонентам?

Во-первых, следуйте принципам SOLID. Для каждого компонента определите единственное назначение (Single Responsibility Principle, принцип единой ответственности). Используйте композицию, а не наследование (Open-Closed Principle, принцип открытости/закрытости). Не заставляйте компоненты реализовывать неподходящие интерфейсы, поскольку не все методы имеют смысл (Interface Segregation Principle, принцип разделения интерфейсов). И помните, что компоненты не должны напрямую зависеть от низкоуровневых сервисов (Dependency Inversion Principle, принцип инверсии зависимостей).

Во-вторых, при применении бизнес-логики к компоненту, сервису или служебной функции нельзя забывать о принципе KISS (Keep it short and simple  —  делайте код как можно короче и проще). Почему это важно? Потому что более простой код легче поддерживать.

В-третьих, старайтесь придерживаться принципа DRY (Don’t repeat yourself  —  не повторяйся). Переносите общую логику в служебные функции или сервисы.

Как понять, чего следует избегать? Иными словами, что такое антишаблоны?

Антишаблоны

Со временем я столкнулся с некоторыми ошибками. Вот самые распространенные из них.

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

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

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

Да, это очень распространенная проблема. Справиться с ней помогут простые рекомендации.

  • Определите ESLint-правила.
  • Используйте stylelint.
  • Тестируйте бизнес-логику.
  • Создавайте небольшие многократно используемые компоненты.
  • Применяйте ES6— и Typescript-функции.

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

Мы рассмотрели пример чистой архитектуры и принципы, которым она подчиняется. Более того, мы убедились в применяемости DDD (Domain-Driven-Design, предметно-ориентированного проектирования) к архитектуре фронтенда. И, наконец, ознакомились с правилами создания компонентов с учетом развития бизнес-логики, которые позволяют коду оставаться ожидаемо поддерживаемым.

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

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи Robert Maier-Silldorff: What is a Clean Frontend Architecture?

Предыдущая статьяDALL·E 3  —  генератор изображений для продуктовых дизайнеров
Следующая статьяОсновные принципы сборки мусора в Java