А что, так можно было?

707d3f3556672fdd4ede91a0b1599b65.jpg

Привет Хабр!

Меня зовут Алекс, и я автор фронтенд-библиотеки для создания UI-компонентов-агностиков — Symbiote.js. Я не единственный разработчик, но главный контрибьютор и тот, кто отвечает за концепцию, развитие, документацию, деврел, DX все остальное. Мейнтейнер то есть. Всем этим я занимаюсь в свободное от другой работы время, на которой я фуллстек, R&D-инженер и техлид.

Сегодня, я бы хотел рассказать о том, как появился Симбиот, и почему он вообще существует, при наличии огромного зоопарка библиотек и фреймворков для фронтенда, с куда более значительной аудиторией и поддержкой от крупных IT-компаний. Ведь мы, инженеры, очень НЕ любим, когда вокруг нас начинают плодиться лишние сущности, и сразу начинаем угрожающе размахивать бритвой Оккама. Верно? (хитро прищурился)

React

Свое первое приложение на React я делал много лет назад, когда тот еще не имел статуса лидирующего решения в отрасли и либы по дефолту. В те славные времена, я работал в команде стартапа, который создавал приложение для живого общения врачей с пациентами. Я пришел в проект на том этапе, когда базовые архитектурные решения уже были приняты, а технологии окончательно выбраны. Мое погружение в React было в жестком боевом режиме, когда, заодно с кодом, я прорабатывал и UX. Мои коллеги рассказывали мне какой React крутой концептуально, а мне не давала покоя одна мысль (ок, далеко не одна)…

Синтаксис JSX. Ведь это язык разметки. Для этого у нас ведь уже есть HTML. А еще, умные дяди и тети нас учили, что логику хорошо бы отделять от представления. А тут, все в кучу, и еще и с многоуровневыми взаимными вложениями… IDE глючит. Новый формат файлов, пока не очень хорошо поддерживается и подсветка синтаксиса постоянно ломается. Ломается и мозг, в сложных случаях. Да, да, я знаю, декомпозиция, но я-же работаю «в команде», а в команде, на декомпозицию могут быть разные взгляды.

А можно было получить, практически то-же самое, и обойтись простыми и ванильными HTML и JS?

Хорошо, держим этот вопрос в уме и идем дальше.

Virtual DOM. Да, нативный DOM браузера медленный, допустим. Это не совсем так, но допустим. Но разве, на этапе синхронизации виртуального DOM с настоящим браузерным, мы не используем тот-же самый DOM API, который, до этого, назвали медленным? То есть, мы родили новую сущность, которая не заменяет собой то, с чем мы «боролись», но теперь сама жрет память и другие ресурсы?

А можно было написать либу так, чтобы и с DOM работать эффективно, и новый ресурсоемкий огород ради этого не городить?

Это второй вопрос, который мы держим в уме.

Состояние. Есть локальное состояние компонента, с ним, вроде бы, все просто. А есть глобальное состояние приложения. Оно может быть довольно сложным, и само по себе, может быть подвергнуто декомпозиции: разделено на элементы, каждый из которых может иметь свои связи с остальными элементами.

К примеру, в вашем приложении может быть глобальный стейт, один из сегментов которого, будет выделен для хранения данных пользователя, другой — для хранения переменных локализации, третий — для определения текущего состояния UI, и так далее. У каждого виджета или микрофронтенда может быть свой стейт.

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

Но сами данные, при этом, могут иметь совершенно разные источники правды и причины динамических обновлений: что-то прилетает с сервера, что-то зависит от действий пользователя, а что-то получается через какой-нибудь сторонний API. Тотальная асинхронность — одна из основных сложностей фронтенда, всякие там race conditions и прочее такое.

На тот момент, Redux, как частичное решение вышеописанных проблем, уже существовал. А всякие обертки, для уменьшения бойлерплейта — еще нет. Контекстов тоже, как вы понимаете, не было. И мне было больно на это смотреть.

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

Svelte

У Svelte, в свое время, был довольно агрессивный маркетинг. Нам говорили, что это «исчезающий фреймворк». То есть, мы придумали для вас еще один, новый формат файлов, который, при обработке специальным компилятором, превращается в… чистый JavaScript! Фантастика!

А разве нельзя, кхм… ну, сразу писать на чистом JavaScript? Ну чтобы не тащить в проект новый (очередной) компилятор, новый (очередной) тип файлов, новый (очередной) синтаксис? Что, совсем-совсем нельзя без «черных ящиков»?

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

Next.js

Как-то раз, React-разработчики поняли, что полностью динамический SPA-сайт — это не всегда очень хорошо. Проблемы с индексацией, скоростью загрузки ассетов и с первичной отрисовкой UI… Бэкендеры смеются и тычут пальцем. Обидно. И родилась идея:, а давайте притащим React еще и на бэкенд! Будем делать SSR! А для динамической части страницы, будем применять гидрацию. Или даже гидратацию. Вставим в разметку специальные маркеры и плейсхолдеры и оживим их на фронте в самый нужный момент. Красиво?

А у меня, что? Правильно, очередные вопросы.

А зачем, собственно, React на сервере?

Для формирования всего документа и его частей (а для сервера это, тупо, строки), нам достаточно простых советских… шаблонных литералов. А для вызова определенного поведения, определенных участков документа на клиенте, нет ничего лучше стандарта Custom Elements: вставил такой в любое место разметки -, а он сам активировался, посмотрел вокруг через DOM API и реализовал любой интерактив.

И опять вопрос: а можно было решить вопрос на уровне базовых возможностей платформы и самого языка? Зачем городить очередной «черный ящик», которые порождает самые неожиданные сложности в самый неподходящий момент? Зачем, в очередной раз, изобретать то, что есть и так из коробки и бесплатно?

Да, я понимаю, есть еще роутинг, права, кэш, всякие другие ассеты, кроме HTML… Но React то здесь каким боком помогает? Никаким. Просто мы не хотим знать ничего кроме React.

Lit

Выше я упомянул Custom Elements. А где Custom Elements — там и Lit: главная библиотека для работы с веб-компонентами от Гугл. Хорошая штука, которая выросла из проекта Polymer. Когда-то, ребята из Гугл сказали «Use the Platform!», и это был свет. Заодно, они чуть пропатчили саму «Platform», чтобы этот «Use» не вызывал много «Pain». Я искренне благодарен им за это.

Но дальше, они стали сами удаляться от платформы. Даже не удаляться, а отгораживаться абстракциями. Например, для работы с шаблонами, они используют свою магическую функцию html, которая перерабатывает основанный на HTML синтаксис, в специальный объект. И эта функция, накладывает сразу массу ограничений на то, как работает шаблонный литерал. Например, вы становитесь очень зависимы от контекста исполнения этой функции. И теряете возможность делать обычную строковую интерполяцию. Нам говорят: хотите что-то имплантировать в шаблон — создавайте новый экземпляр нашего специального объекта, и уже его, вставляйте в материнский шаблон.

А я хочу спросить: а можно было без этого? Ну чтобы шаблоны формировать и хранить как угодно, включая возможность использовать и оживлять разметку самого материнского документа?

Искусство компромиссов

Инжиниринг — это искусство компромиссов. Грамотное инженерное решение — это взвешивание большого количества «ЗА» и «ПРОТИВ», причем как для общего, так и для частных случаев. Мы все люди, и иногда, склонны переоценивать или недооценивать какие-то «ЗА» и какие-то «ПРОТИВ». Часть факторов может ускользать от нашего взора, по различным причинам. Любую технологию можно критиковать. Любая технология и решение — могут быть хороши в своем контексте, который может быть не всем очевиден и не до конца понятен людям со стороны.

Мы всегда чем-то немного жертвуем: удобством, производительностью, количеством лишних килобайт или концептуальной инженерной красотой. Иногда (часто), мы попадаем в ловушку иллюзий. Иногда, ради иллюзорных целей, мы делаем лишнюю работу и плодим лишние сущности. Как бороться с этим? Мой рецепт — задавать себе вопросы. На примере тех, которые я задавал в этой статье.

Моим ответом на эти вопросы стал Symbiote.js.

И да, так было можно.

P.S. Конечно же, я перечислил далеко не все вопросы и не все популярные технологии, которые эти вопросы вызывают. Надеюсь, у вас тоже есть вопросы, которыми вы поделитесь в комментариях.

© Habrahabr.ru