Предисловие
За свою карьеру я встречал достаточно много проектов, крупных и малых, которые страдали от огромной и запутанной кодовой базы с высоким уровнем зацепления и малой связностью, непонятной структурой, в которую весьма сложно погрузиться (на онбродинг нового сотрудника может уходить до трех месяцев) и большим количеством непонятных и громоздких компонентов, которые являются god object'ами. Стоит ли говорить, что у таких проектов имеются большие проблемы с поддержкой и развитием.
Зачастую, в ответ на вопрос "почему так?" можно услышать разнообразные оправдательные ответы, которые, в основном, ссылаются на сжатые сроки, частые продуктовые изменения и первичность продукта перед качеством кодовой базы. И большая доля правды в этом есть, но, что, если я скажу, что можно усидеть сразу на нескольких стульях и от этого выиграют все, от менеджеров до разработки? И это гораздо проще, чем кажется. Естественно, универсального решения нет, но можно существенно облегчить жизнь в будущем себе или своим потомкам.
В данном цикле статей я хочу поделиться своими наблюдениями и дать советы и рекомендации, которые помогли мне и, по моему мнению, могут помочь другим разработчикам. Я не буду сразу разбирать типовые ошибки в коде или микроархитектуре, так как это лишь маленькие точки на радаре. Как говорится, рыба гниет с головы, так что я пойду от глобальных проблем к частным и буду каждый раз подводить итог в виде какого то умозаключения.
Продукт и Дизайн
Для клиент-серверных приложений и уж тем более для фронтенда, дизайн - прямая инструкция, которая диктует итоговый вид и функционал приложения. Это подробное и наглядное отображение требований продукта.
Продукт, в свою очередь, это то, ради чего мы все собрались в компании. Его требования, как пути господни, но мы, как разработчики, должны их реализовывать максимально быстро и качественно. Тут нам и может помочь структурированный дизайн. Дизайнеры первыми могут принять на себя удар очередной волны смены требований и, используя уже готовую компонентную базу, быстро собрать новую фичу, которая также быстро будет реализована разработчиками и уедет в прод.
Если в дизайне есть дизайн-система, согласованная с разработчиками, которой следуют сами дизайнеры, если подробно отрисованы все компоненты и их состояния, то разработка будет идти быстро и качественно (само собой, если разработчки обладают необходимыми компетенциями). Если же дизайн-системы нет, а каждый дизайнер рисует на свое усмотрение, в разработке будет царить хаос и непонимание.
Сколько же нервов тратят разработчики при виде новых, "точно последних", изменений в дизайне, которые разворачивают разработку на 180 градусов. Сколько матерных слов в сторону дизайнера/ов было сказано при очередной бессонной ночи, когда заказчику продукта эти изменения нужны были "еще вчера", а все элементы дизайна не следуют или нарушают дизайн систему, все отступы разные и не совпадают, и не понятно, надо ли использовать старые компоненты, или их функционал надо расширить, или надо делать новые.
Если на вашем проекте присутствуют вышеописанные проблемы, то начинать исправлять проект следует с разговора с дизайн командой и продуктом. Без этого любые попытки хоть как то улучшить и "исцелить" проект сойдут на нет.
Дизайн всегда должен быть структурирован, унифицирован и систематизирован, а также согласован не только с продуктом, но и с разработкой.
Глобальная архитектура
Предположим, что дизайн команда выполняет свои задачи настолько качественно, насколько это возможно. Как тогда выстроить архитектуру? Какой фреймворк выбрать? SPA или SSR? Может FSD? Может атомарную? А может свою придумать, да такую, чтоб всем нравилось и все довольны были?
Единого ответа на эти вопросы нет. Каждая команда и проект индивидуальны. Мое мнение - каждая команда должна сама понять, какая архитектура подходит лучше для нее и конкретного продукта. Но есть вещи, которые я бы хотел подсветить.
Фреймворк. SPA vs SSR
Сейчас существует огромное количество фреймворков и написать плохо и хорошо можно на любом из них, так что это не так важно. Но уже почти каждый из них существует в двух версиях - SPA и SSR. И тут надо быть весьма аккуратным в выборе.
SPA приложения очень удобны, так как работают на клиенте и снимают всю нагрузку с сервера касательно рендеринга. Но мы до сих пор имеем проблему с индексацией страниц приложения поисковыми роботами. Эту проблему, конечно, можно решить с помощью костыльных методов, но все они работают так себе.
SSR в свою очередь решают проблему индексации, но придется заплатить за это определенную цену. В основном, все SSR решения диктуют свою архитектуру, имеют множество подводных камней, а проекты, написанные на них, очень "тяжелые". Если не уделять должного внимания размеру бандла и качеству кода, то в какой-то момент приложение начнет очень медленно грузиться. В лучшем случае оно будет выдерживать нагрузку в 10 rps. Я уже не буду говорить про проблемы кэширования (привет next.js)...
Так что следует очень хорошо подумать, нужен ли SSR на проекте. Если у вас на проекте индексируется только одна страница, то, скорее всего, только она и будет рендериться на сервере. Все остальные же страницы рано или поздно переедут на клиентский рендеринг.
Если на проекте требуется индексация страниц то стоит выбрать SSR, но стоит помнить, что он может создать кучу проблем при разработке и стать бутылочным горлышком в будущем. В противном случае всегда следует использовать SPA.
Насколько большим будет/является приложение
Первое, что следует учесть - любой проект, даже с самой наиболее подходящей для него архитектурой, по ходу разрастания будет тяжело поддерживать. Понятно, что на старте сложно понять, каких размеров будет приложение по итогу. Но если код изначально написан модульно, то не составит особого труда вынести какие либо его части в отдельные библиотеки и расшарить их на будущие микросервисы. И наоборот - если в вашем приложении высокая степень зацепления между модулями, то не важно, будут ли это в будущем микросервисы или монолит, поддерживать и развивать проект будет одинаково сложно.
Структура папок и файлов. FSD? Atomic design? Custom?
Давайте рассмотрим несколько популярных решений и решим, какое лучше использовать.
Feature Sliced Design
Сейчас в РФ большую популярность набирает FSD. Он подается, как универсальное решение, которое можно "натянуть" на любой проект, как сову на глобус. Мне, если честно, не совсем понятно, почему эта система обросла такой большой фан базой, так как решение, на мой взгляд, не только не самое удобное, но и усложняет разработку. Не говоря уже о противоречиях внутри самой системы. Достаточно посмотреть на простые примеры на сайте, чтобы понять, что система не является интуитивно понятной, а следовательно, не является универсальной. Если же данная система применяется на проекте, то она будет изменена до неузнаваемости, так что новопришедшему разработчику все равно придется изучать локальную вариацию FSD на проекте. Тема, конечно, холиварная, но таково мое мнение о данной системе. Адепты FSD, уж извините.
Atomic design
Данная концепция мне нравится больше, так как она проста в понимании, но на больших проектах она перестает работать, так как в конечном итоге у нас появляется две огромные папки atoms
и molecules
, которые разрастаются до огромных размеров. Так что могу порекомендовать ее только на небольших проектах.
Custom design
Тут начинается самое интересное. За все время разработки я перепробовал много различных решений и нашел те, которые удобны как мне, так и остальным членам команды. Также я начал обращать внимание, что в разных независимых командах формируются примерно похожие структуры проектов, что подвело меня к мысли "а что, если самая удобная дизайн система является интуитивной и вытекает из негативного опыта разработчиков и рефлексии над ним?"
Понимаю, что звучит весьма абстрактно, так что постараюсь объяснить на примере. Допустим, у нас есть папка pages
, где хранятся все страницы нашего приложения. Также у нас есть папка components
, которая содержит компоненты общего назначения (Button, Input, Card, etc). И вот стоит задача создать новую, временную промо страницу, которую необходимо будет удалить через несколько месяцев. На самой странице будет находиться несколько уникальных компонентов, которых нет в дизайн системе. Куда их положить положить? Конечно, можно поместить все в папку components
и не париться, ведь там лежат все компоненты. Но страница будет удалена через несколько месяцев, а удалением будет заниматься уже другой разработчик. Скорее всего он просто снесет страницу и все упоминания о ней, а уникальные компоненты останутся в папке components
навсегда. Это один из сценариев накопления тех долга (проще говоря, хлама) на проекте.
Как можно избежать вышеописанной ситуации? Поместить все уникальные элементы в папку с самой страницей, но реализовать данные компоненты модульно, т.е. не обвязывать их намертво бизнес-логикой, а предусмотреть для них качественное api
. Тогда они не останутся в проекте после удаления самой страницы. В тоже время, если компоненты переедут в дизайн систему, то их можно будет легко и безболезненно перенести в components
.Такое решение кажется интуитивным. И на основе таких решений можно разработать структуру, которая будет:
-
подходить вашей команде
-
понятна вновь пришедшим разработчикам
-
не будет накладывать излишние ограничения
Дизайн систему следует выстраивать исходя из best practices, рефлексии над старым опытом и интуитивных решений
В следующей статье я более подробно расскажу про остальные наблюдения касательно структуры проекта, но уже с частными примерами реализации.
Автор: HungryGrizzzly