Что такое архитектура приложений
В IT-мире существует много разных определений, где каждое по-своему хорошее, но лично мне нравится следующее.
Архитектура приложений — это набор правил и ограничений, которые регулируют взаимодействие модулей приложения друг с другом, а также приложения с внешним миром.
Можно привести простую аналогию: архитектура похожа на правила дорожного движения в реальном мире. Они тоже выставляют свои ограничения, которые регулируют поведение всех участников движения. Если бы не было правил, то на дорогах творился бы хаос. Примерно то же самое и с архитектурой приложений.
Конечно, можно не следовать никаким принципам, делать «костыли», но тогда в программном коде образуется тот самый хаос. И если приложение маленькое, то вам это простят, потому что мало кто переживает из-за этого. Но вот если в нем есть бизнес-логика или микросервисы, то появится куча проблем, которые будут стоить компании больших денег.
Чем архитектура фронтенда отличается от архитектуры бэкенда
Принципов какой-то архитектуры придерживается абсолютно каждый фронтенд-разработчик, который делал проекты чуть сложнее, чем landing page. Но в какой-то момент фронтендеры понимают, что просто разложить всё по папкам не получается.
До 2000-х годов фронтенд-приложения были достаточно простыми и маленькими, а больших и сложных практически не существовало. Всё из-за того, что тогда технологии фронтенда не позволяли удобно разрабатывать крупные проекты. А когда приложение небольшое, то и вопрос об архитектуре не стоит.
Потом появился Фейсбук (запрещен на территории РФ) и другие социальные сети. Бизнес начал диджитализироваться, и росла потребность в масштабировании приложений. Руководители компаний хотели, чтобы сайты были эффективными и гибкими. И тогда начали внедряться первые архитектурные подходы для фронтенда.
В самом начале фронтендеры заимствовали много из бэкенда — например, MVC-паттерн, или Model-View-Controller. Сам по себе он неплохой, но подходит только для небольших приложений. Вскоре MVC стало не хватать, и появилась архитектура Flux. Она не решала все проблемы, но была в чем-то лучше: как пример, при работе с направленностью данных и взаимодействию с ними.
Сложность такого подхода в том, что бэкенд и фронтенд всё-таки разные сущности. Они по-разному работают, неодинаково взаимодействуют с данными на разных уровнях. Поэтому всё, что подходило для бэкенда, не обязательно могло подойти для фронтенда.
Сегодня уже есть готовые архитектурные подходы, которые учитывают множество факторов для фронтендеров. Но их не так много, и некоторые из них достаточно молодые. Можно сказать, что они еще не устоявшиеся, и, скорее всего, будут сильно дорабатываться в ближайшее время.
Какие критерии у хорошей архитектуры для фронтенда
Когда мы только начинаем писать приложение, оно еще маленькое и чистое. Пока у нас нет серьезных проблем. Но со временем приложение будет развиваться, а значит, будет расти кодовая база и связей между модулями будет становиться всё больше. Поэтому если не следить за этим, то однажды эти связи станут настолько твердыми и негибкими, что будет сложно изменить даже пару строчек кода. Это реальная история из практики, правда, не моей. На одном проекте архитектура была очень негибкой, поэтому разработчикам пришлось заменить несколько библиотек и сильно переписать архитектуру только для того, чтобы поменять местами строки и колонки в таблице. В итоге со всеми согласованиями на это ушло больше недели.
Чтобы не допустить хаоса в коде, стоит помнить о трех свойствах хорошей архитектуры:
- Удобство. Разработчики должны понимать, где что лежит и как это взаимосвязано друг с другом. Это сделает работу с проектом комфортнее, а значит, фронтендеры станут более продуктивными.
- Time-to-market. В идеале он должен быть низким. Если бизнес хочет быстро выкатывать обновления, нужно сократить время на эту разработку. Как сокращать — зависит от компании и того, насколько хорошо там выстроены бизнес-процессы.
- Масштабируемость. Если компания хочет развиваться, она будет привлекать больше клиентов и добавлять новые фичи, а значит, нагрузка на приложение будет становиться тоже больше. Поэтому важно помнить про масштабируемость — даже на начальных этапах.
В реальности же на первые два критерия влияет не только архитектура приложения, но и внешние факторы. Если в компании плохо построены процессы, разработчику будет некомфортно работать, даже если архитектура хорошая. И уж точно это не поможет быстрее выпускать обновления и новые фичи.
Могу привести пример из своего опыта. Мы разрабатывали большое приложение по Gitflow. Задачи разбивали на двухнедельные спринты, где за каждый спринт мы вносили доработки и вливали изменения в релизную ветку. А раз в две недели у нас проходил релиз.
С нашей стороны — всё отлично. Разработчикам комфортно, тестировщики тоже рады, да и вообще всем замечательно, никакой спешки. Но бизнесу это не нравится, потому что он хочет видеть некоторые доработки чаще, чем раз в две недели. И тут руководство принимает решение ускорить процесс и добавить локальные релизы: отправлять обновления в продакшен по готовности.
Конечно, time-to-market вырос, а вот комфорт и удобство для разработчиков сильно снизились. Теперь приходилось переделывать все процессы, которые были уже давно налажены в команде. Мы начали делать много «костылей», и вообще переход прошел достаточно болезненно. Так что всё зависит не только от архитектуры, но и от других внешних параметров, которые даже вряд ли относятся к ней.
Как построить хорошую архитектуру
Термин «хорошая архитектура» очень абстрактный, потому что невозможно подобрать архитектуру, которая будет универсальна для всех. Поэтому выбор зависит от многих факторов:
- какая у вас команда: сильные сеньоры или сборная солянка из джунов и мидлов;
- какие сроки: сжатые или свободные;
- сколько есть ресурсов: много или мало;
- насколько хорошо построены процессы в команде;
- есть ли собственные библиотеки, шаблоны и так далее.
Я бы дал такой совет: нужно как можно дальше смотреть в будущее и понимать, что из себя будет представлять приложение в отдаленной перспективе. А потом готовиться к тому результату, который вы увидели.
Подобрать архитектуру сложно еще и потому, что требования к проекту часто меняются.
Возьмем какое-нибудь банковское приложение. Вначале это будет простое приложение, потому что кода немного — раз мы начинаем писать с нуля. Тогда подойдут простые архитектурные подходы, такие как модульная архитектура. Но с ростом компании архитектура приложения должна становиться взрослее: сложнее и насыщеннее. Как пример — переходить в сторону микросервисной.
Предсказать наверняка, каким будет приложение, вряд ли получится, но хотя бы можно знать точно, какой будет уровень нагрузки и оптимизации.
- Если продуктом будут пользоваться с офисных компьютеров или в бюджетных организациях, тогда придется использовать инструменты, которые сочетаются со старыми браузерами.
- А если продуктом будут пользоваться, скажем, геймеры, то оптимизации и совместимости со старыми браузерами можно уделять гораздо меньше внимания. Но в то же время нужно будет больше работать над функционалом приложения.
Лично мне очень нравится подход Feature-Sliced Design, или FSD. Это полноценный архитектурный подход, который создан специально для фронтенда. FSD сразу готов к тому, что у вас возникнут проблемы со связанностью компонентов, сложностью кода и возможностью рефакторинга. Всё уже заложено в архитектуру.
FSD — это молодая архитектура, которую создали в 2021 году. Эта архитектура ставит нам ряд правил и ограничений, которые делят приложение на слои, поэтому и Sliced. У каждого слоя есть свои слайсы, или кусочки. А у каждого слайса — свои сегменты. И такая структура (слои → слайсы → сегменты) помогает разбить приложение по смысловым частям.
Каждый слой — это отдельный модуль приложения, например виджеты или базовые компоненты (кнопки, параграфы). Слайсы — это функциональность конкретного модуля. А сегменты — это всякие api, config, lib и так далее. Такая архитектура позволяет добиться минимальной сцепленности и максимальной связности, или Low Coupling, High Cohesion.
Еще одно главное и не самое очевидное преимущество этого архитектурного подхода в том, что когда мы пытаемся на уровне кода разбить логику по частям, то сразу замечаем недоработки каких-то бизнесовых моментов. Мы как бы пытаемся разделить процесс на подчасти и понимаем, общий это элемент для всего процесса или уникальный случай, а затем кладем его в отдельную папку.
Лучше рассказать на реальном примере. У нас был заказчик, для которого нужно было разработать дашборд для отображения данных: он хотел добавить функциональность словарей в карточку пользователя. Когда мы начали разбивать эту фичу в соответствии с принципами FSD, перед нами встал вопрос: положить ее в слой entities как часть сущности «пользователь» или добавить в общий функционал, который в теории может применяться для таблиц и прочих элементов.
Если бы мы не использовали FSD, то связали бы функционал словарей с сущностью пользователя. И когда бизнес попросил бы внедрить его в другое место, пришлось бы делать дополнительную работу по переносу кода. Поэтому FSD помогает нам лучше продумывать бизнес-логику приложений.
При этом у архитектуры есть и большой недостаток: сложность входа для разработчиков. Но я бы сказал, что он достаточно легко преодолевается. Буквально за пару месяцев разработки можно запомнить все принципы. Это как на велосипеде: сначала сложно, а потом едешь на автомате.
Есть и еще один важный недостаток архитектуры. Так как FSD активно развивается, у него меняются некоторые принципы. Например, с недавнего времени разработчики решили, что им не нужен слой processes, — его сделали deprecated. Всё из-за того, что его можно разбить на более мелкие сущности (entities и features), и вообще им пользовались всего несколько процентов от всех фронтендеров. Поэтому при работе с этой архитектурой есть определенные риски, о которых нужно помнить.
Стоит отметить, что FSD подходит не для всех проектов. Например, делать по нему простой лендинг — это уже слишком. Но если приложение побольше, где есть несколько модулей или вкладок, я бы рекомендовал попробовать эту архитектуру.
Чтобы подтвердить популярность архитектуры, приведу такой пример. Я каждую неделю провожу по 5–7 собеседований фронтендеров уровня Middle и Senior — то есть у меня есть выборка примерно в 50–100 человек. Примерно 80% из них и других разработчиков, с которыми я общаюсь, пишут проекты по принципам FSD либо знают про него и хотят попробовать. Думаю, это внушительные цифры.
Я даже какое-то время помогал FSD развиваться. У них на сайте были слишком простые примеры, которые не раскрывали все преимущества FSD. Это были разные пет-проекты уровня To-Do List или что-то вроде платформы с фильмами. И все они не показывали, какие проблемы архитектура помогает решить. Поэтому сторонние разработчики решили сами создать пару крупных проектов и добавить их на сайт как примеры.
Самые активные участники сообщества FSD разбились на три группы и пошли писать собственные приложения с разным масштабом. Одни использовали React, другие — Vue, а третьи — Effector, это библиотека от создателей архитектуры FSD. И я был в одной из этих групп.
К сожалению, работа над проектами далеко не сдвинулась. У всех разработчиков была основная работа, поэтому времени на сторонние проекты они выделяли не так много, как хотелось бы. Из-за этого возникали проблемы с организацией процессов и разработки приложений. Но сегодня работа всё еще продолжается, и вероятно, что эти приложения всё же доработают.
Я решил пойти немного другим путем, чтобы показать возможности FSD, — создать собственный курс. На нем планирую раскрыть потенциал архитектуры на более сложном проекте с использованием микрофронтендов и Next.js. Хочу разобрать там популярные вопросы и ответить, как правильно использовать FSD в разработке.
Подробнее с архитектурой можно познакомиться на официальном сайте, а пообщаться с другими энтузиастами — в телеграм-канале. Там же можно найти ответы на многие вопросы, достаточно просто вбить в поиске ключевое слово, и велика вероятность, что кто-то уже обсуждал это. Я сам так делал.
Как не допустить серьезных ошибок, когда строишь архитектуру
Я бы дал такой совет: если нет опыта построения архитектуры, лучше активно изучить Feature-Sliced Design и использовать его. Это классный архитектурный подход, который уже из коробки решает основные проблемы фронтенда. Он также хорошо подойдет для сложных приложений, где есть какая-то специфическая логика.
И второе: важно помнить о будущем проекта и представлять, как он будет выглядеть через некоторое время. Пишите код так, чтобы он соответствовал этому видению. Так вы допустите гораздо меньше ошибок и сможете вовремя всё перестроить, если будет нужно.
Построить хорошую архитектуру — это как собрать крутой билд в RPG-игре. Вы его создаете из определенных артефактов, то есть фронтенд-инструментов. Например, если хотите модульность — используете инструменты для модульности, которые помогут внедрить public API и поделить приложение на модули. Если хотите FSD, то используете другой инструмент: начинаете делить всё на слои, слайсы и сегменты. А когда вы дойдете до финального босса и приложение станет слишком сложным, нужно будет переходить к микросервисной архитектуре. Поэтому чем дальше вы продвигаетесь по уровням и локациям, тем сложнее становится играть, а значит, и инструменты нужно подбирать подходящие.