Тонкий и толстый. Каким должен быть Frontend?

Архитектура

Есть два полярных подхода к разработке: «толстый» клиент, который тащит на себе всю логику приложения, и «тонкий» клиент, который лишь красиво показывает ту информацию, которую ему выдал сервер.

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

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

Толстый клиент — бэкенд в браузере

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

Признаки толстого клиента

  • На сервере минимум логики: авторизация, базовые SELECT/INSERT запросы
  • Большой упор на работу со стейт-менеджером на фронте
  • Валидация форм, сложные вычисления, фильтрация больших массивов данных происходят в браузере

Когда это оправдано?

Толстый клиент обеспечивает наилучшую интерактивность и плавность. Загрузив и закешировав бандл, браузер даст пользователю лучший UX. Если ваш проект — это скорее инструмент, а не сайт, присмотритесь к такому подходу.

Также такой выбор оправдан, если вы делаете PWA или приложение где важна скорость взаимодействий (Figma, Notion).

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

Подводные камни «толстого» подхода

Главная проблема — это чувствительность к изменениям. В толстом клиенте фронтендер отвечает за логику. Если в бизнес-правилах меняется формула расчета скидки, вы не можете просто обновить ее на сервере. Вам нужно доставить эти изменения до пользователя и убедиться, что у него не закешировалась старая версия.

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

Тонкий клиент — просто рендер

Тонкий клиент — это возврат к корням, но на новом технологическом уровне. Сервер контролирует все данные, логику, иногда — маршрутизацию. Фронтенд получает готовые данные и просто их отображает. В современных реалиях речь чаще идет про SSR или архитектуру, построенную вокруг шаблонизаторов. Так или иначе, в браузер пользователя прогружается минимальное количество JS.

Признаки тонкого клиента

  • Минимум или полное отсутствие состояния на клиенте
  • Логика расположена на сервере (в монолите или BFF)
  • Обновление данных происходит через перезагрузку страницы или замену DOM-элементов по ответу сервера
  • Отсутствие сложного стейт-менеджера

Когда это оправдано?

Тонкий клиент идеален для контентных проектов и приложений, где критична скорость первой загрузки и SEO. Это могут быть корпоративные сайты, интернет-магазины, новостные ресурсы.

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

Подводные камни «тонкого» подхода

Главная проблема — скорость взаимодействия. Каждое действие пользователя превращается в HTTP-запрос. Это создает нагрузку на сервер и делает интерфейс менее отзывчивым.

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

Золотая середина — компромиссный подход

На практике редко встречаются проекты, которые являются строго «толстыми» или «тонкими». Обычно мы говорим о степени жирности. Вот три принципа, которые помогут вам найти баланс.

1. Разделяй по доменам

Никто не заставляет одну архитектуру для всего приложения. Страница документации может быть статическим HTML (тонкий клиент), а личный кабинет с графиками — тяжелым SPA (толстый клиент).

На главной странице интернет-магазина не нужно тянуть бандл с React и Redux, если там просто слайдер. Загружайте тяжелую логику только тогда, когда пользователь дошел до корзины или авторизовался. Используйте микрофронтенды или просто разные entry в сборщике.

2. Не храни на клиенте то, что принадлежит серверу

Одна из главных ошибок в толстых клиентах — кеширование данных на клиенте без инвалидации. Если список товаров принадлежит серверу, отдайте задачу его хранения на сервер.

Библиотеки вроде TanStack Query или RTK Query учат нас добру: данные на клиенте — это всего лишь копия серверного состояния, а не единственный источник истины.

3. Backend for Frontend (BFF) для контроля

Если вокруг проекта существует много разных бэкендерских микросервисов, на толстом клиенте придется собирать данные из нескольких разных API, склеивать их и обрабатывать ошибки. И для этого на клиент придется доставить внушительный кусок логики.

Решение — прослойка в виде BFF. Это своего «тонкий» слой на сервере, который написан специально для конкретного фронтенда. В описанном выше случае он возьмет на себя задачу сбора данные с микросервисов, применения бизнес-логики, а клиенту отдаст уже готовый, собранный JSON.

Каким же должен быть идеальный фронтенд?

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

1. Предсказуемым

Разработчик (и особенно новый разработчик) должен понимать, где расположена логика. В толстом клиенте для этого понадобится четкое разделение на слои, какая-никакая внутренняя архитектура. В тонком — понятный роутинг и описание взаимодействия с API.

2. Отказоустойчивым

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

3. Производительным по ощущениям

Тема производительности заслуживает отдельного обсуждения. Но если кратко, пользователь простит вам 2 секунды загрузки, если после этого интерфейс будет летать. И наоборот, быстрая загрузка, но тормозящий скролл — это фиаско.

4. Безопасным

Пожалуй именно эта характеристика делает тонкий клиент таким популярным выбором. Если чувствительная информация обрабатывается и, не дай Боже, хранится в браузере пользователя, у приложения есть явные уязвимые места. Да, мы валидируем формы. Но делаем это скорее для удобства пользователя. Фронтенд — всего лишь интерфейс для реализованной на бэке безопасности.

Итого

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

И до тех пор пока он выполняет эту задачу, он может быть каким угодно. К тому же, единственно правильного ответа на вопрос «Тонкий или толстый?» просто не существует. Это всегда компромисс между скоростью разработки, скоростью работы приложения, сложностью поддержки и безопасности.

Если вы делаете лендинг — будьте тонким. Если делаете CRM — можно и поднабрать жирка, но с умом. В одном проекте могут существовать модули обоих типов.

Ваша задача как разработчика — не навесить на фронтенд как можно больше ответственности. Напротив — оставьте на нем только то, что действительно должно быть там для комфортной работы пользователя. Всё остальное — на сервер или в пайплайн.

Симо Мофин
Симо Мофин

Senior Frontend Developer
Главный по блогу