- PVSM.RU - https://www.pvsm.ru -
TL;DR: Тропа SPA темна и полна ужасов. Ты можешь бесстрашно сражаться с ними… или выбрать другой путь, который приведёт тебя к нужному месту: современный Rails.
Я вспоминаю, как думал, что Rails фокусируется на неправильной цели, когда DHH анонсировали Turbolinks в 2012 году. Тогда я был убеждён в том, что мгновенное время ответа во время взаимодействия с пользователем — это ключ к превосходному UX. Из-за возникающих задержек сети, такая интерактивность возможна, только если вы минимизируете зависимость от сети и вместо сетевых обращений поддерживаете большую часть состояния на клиенте.
Я думал, что это необходимо для приложений, над которыми я работал. И с таким мнением я перепробовал множество подходов и фреймворков для реализации одного и того же шаблона: Single-page applications (SPA). Я верил, что SPA — это будущее. Несколько лет спустя, я не уверен в том, каково же будущее, но я точно хочу найти альтернативу.
Одностраничное приложение — JavaScript приложение, которое, единожды загруженное, получает полный контроль без необходимости перезагружать страницу: рендеринг, получение данных с сервера, обработка взаимодействия с пользователем, обновление экрана…
Такие приложения выглядят более нативно чем традиционные веб-страницы, где приложение зависит от сервера. Например, если вы используете Trello, вы можете заметить насколько быстро создаются карточки.
Конечно же, с большой силой приходит большая ответственность. В традиционных веб-приложениях ваше серверное приложение включает доменную модель и бизнес-правила, технологию доступа к данным для работы с базой данных и слой контроллеров для управления тем, как HTML страницы собираются в ответ на HTTP запросы.
C SPA всё несколько сложнее. Вам всё ещё нужно серверное приложение, включающую вашу доменную модель и правила, веб-сервер, база данных и какая-то технология доступа к данным… и ещё куча дополнительных штук сверху:
Для сервера:
Для нового JavaScript клиента:
Суммируя, с SPA у вас будет ещё одно приложение для поддержки. И новый набор проблем для решения. И заметьте, вы не можете заменить одно приложение другим. Вам всё ещё нужно серверное приложение (теперь оно будет рендерить JSON вместо HTML).
Если вы никогда не работали с SPA, вы можете недооценивать сложности, с которыми вы столкнётесь. Я знаю это, потому что я допустил те же ошибки в прошлом. Отрендерить JSON? Я могу с этим справиться. Богатая модель доменных объектов в JavaScript? Звучит забавно. И, знаешь, этот фреймворк решит все эти проблемы. Отличный пирог!
Неверно.
Обмен данными между вашим новым приложением и сервером — сложная проблема.
Есть две противоположных силы:
Кроме этого, вам нужно подумать о том, что загружать, и когда это делать для каждого их экранов. Я имею в виду, что вам нужен баланс между начальной загрузкой, тем, что нужно сразу, и тем, что может быть загружено лениво, и разработать API, который позволяет это делать.
Некоторые стандарты могут тут помочь. JSON API, чтобы стандартизировать JSON формат; или GraphQL, для выборки только нужных данных, таких сложных как потребуется, одним запросом. Но ни один из них не спасёт вас от:
И оба эти аспекта представляют собой достаточный объём дополнительной работы.
Люди привыкли ассоциировать SPA со скоростью, но правда такова, что заставить их загружаться быстро не так-то уж и просто. Этому есть множество причин:
Это не значит, что невозможно заставить SPA загружаться быстро. Я просто говорю, что это сложно и вам стоит позаботиться об этом, поскольку это не придёт само вместе с архитектурой SPA.
Например, Discourse, SPA на базе Ember, имеет фантастическое время загрузки, но помимо всего прочего, они предзагружают большой объём JSON данных в виде части начального HTML, чтобы не делать дополнительные запросы. И отмечу, что команда Discourse помешаны в хорошем смысле на скорости и их навыки сильно выше среднего. Подумайте об этом перед тем, как с лёгкостью воспроизводить то же самое в вашем SPA.
Амбициозное решение этой проблемы — изоморфный JavaScript: отрендерите вашу начальную страницу на сервере и быстро отдайте клиенту, пока в фоне SPA загружается и получает полный контроль, когда готово.
Этот подход требует исполнения JavaScript рантайма на сервере, и он тоже не без технических проблем. Например, разработчики должны учитывать события загрузки SPA, поскольку процесс загрузки меняется.
Мне нравится возможность переиспользования кода в этой идее, но я не видел реализации, позволившей бы мне идти в противоположном направлении. Кроме того, мне кажется очень забавным такой процесс рендеринга страниц:
— Server: запрос к серверному API
— Server: запрос к базе данных
— Server: сгенерировать JSON
— Server: преобразовать JSON в HTML
— Client: отобразить начальный HTML
— Client: загрузить SPA
— Client: распарсить начальный HTML и подписаться на события DOM
Не могли бы вы просто запросить данные из БД, сгенерировать HTML и начать работать?
Это не совсем честно, потому что вы будете не SPA и потому что большая часть этой магии спрятана за фреймворком, но это всё ещё кажется мне неправильным.
Разрабатывать приложения с богатым пользовательским интерфейсом сложно. Это всё потому, что это одна из проблем, которая вдохновила появление объектно-ориентированного подхода и многих шаблонов проектирования.
Управлять состоянием на клиенте сложно. Традиционные веб-сайты обычно фокусируются на экранах с одной ответственностью, которые теряют состояние, когда перезагружаются. В SPA же приложение отвечает за то, чтобы всё состояние и обновления экрана во время использования были консистентными и проходили гладко.
На практике, если вы начинали писать JavaScript небольшими порциями, чтобы улучшить взаимодействие, то в SPA вам придётся писать тонны дополнительного JavaScript кода. Тут вам стоит убедиться, что вы делаете всё правильно.
Существует столько же разных архитектур, сколько SPA-фреймворков:
Из всех фреймворков, что я видел, Ember — мой любимый. Я обожаю его согласованность и то, что он довольно упрямый. Мне также нравится его модель программирования в последних версиях, сочетающая традиционный MVC, компоненты и роутинг.
С другой стороны, я сильно против Flux/Redux лагеря. Я видел так много умных людей, применяющих их, что приложил все усилия к его изучению и пониманию и ни один раз. Я не могу не трясти головой от разочарования, когда я вижу код. Я не вижу себя счастливым во время написания такого кода.
Наконец, Я не могу смириться со смешением HTML и CSS в компонентах, полных JavaScript логики. Я понимаю какую проблему это решает, но проблемы, которые привносит этот подход, не делают его стоящим этого.
Оставим личные предпочтения, суть в том, что если вы выберете путь SPA, то у вас появится очень сложная проблема: создать архитектуру вашего нового приложения правильно. И индустрия довольно далеко от того, чтобы прийти к согласию по вопросу — как это делать. Каждый год появляются новые фреймворки, шаблоны и версии фреймворков, что слегка меняет модель программирования. Вам потребуется писать и поддерживать тонну кода, основываясь на вашем архитектурном выборе, так что подумайте об этом как следует.
При работе с SPA вероятно вы встретитесь с дублированием кода.
Для вашей SPA логики, вы захотите создать богатую модель объектов, представляющих вашу доменную область, и бизнес логику. И вам все ещё нужно всё то же самое для серверной логики. И это вопрос времени, когда вы начнёте копировать код.
Например, представим, что вы работаете с инвойсами. Вы возможно имеете класс Invoice в JavaScript, который содержит метод total, который суммирует цену всех элементов, чтобы вы могли отрендерить стоимость. На сервере, вам также понадобится класс Invoice с методом total для вычисления этой стоимости, чтобы отправить её по e-mail. Видишь? Клиентский и серверный класс Invoice реализуют одинаковую логику. Дублирование кода.
Как сказано выше, изоморфный JavaScript мог бы нивелировать эту проблему, позволяя проще переиспользовать код. И я говорю нивелировать, потому что соответствие между клиентом и сервером не всегда 1-к-1. Вы захотите быть уверены, что некоторый код никогда не покидает сервер. Большое количество кода имеет смысл только для клиента. А также, некоторые аспекты просто отличаются (например, серверный элемент может сохранять данные в БД, а клиент может использовать удалённый API). Переиспользование кода, даже если это возможно, — это сложная проблема.
Вы можете поспорить, что вам не нужна богатая модель в вашем SPA и что вы вместо этого будете работать с JSON/JavaScript объектами напрямую, распределяя логику по компонентам UI. Теперь у вас есть то же самое дублирование кода, перемешанное с вашим кодом UI, удачи с этим.
И то же самое случится если вы захотите шаблоны для рендеринга HTML между сервером и клиентом. Например, для SEO, как насчёт сгенерировать страницы на сервере для поисковых роботов? Вам потребуется заново написать ваши шаблоны на сервере и убедится, что они синхронизированы с клиентскими. Опять дублирование кода.
Необходимость воспроизводить логику шаблонов на сервере и клиенте, по моему опыту, — источник возрастающего несчастья программистов. Сделать это один раз — это нормально. Когда вы сделаете это в 20ый раз, вы схватитесь за голову. Сделав это в 50ый раз, вы задумаетесь, нужны ли все эти SPA штуки.
По моему опыту, разрабатывать хорошие SPA — это намного более сложная задача, чем написание веб-приложений с генерацией на сервере.
Во-первых, неважно насколько вы осторожны, неважно как много тестов вы пишете. Чем больше кода вы пишете, больше багов у вас будет. И SPA представляет (извините, если я сильно давлю) огромную кучу кода для написания и поддержки.
Во-вторых, как упоминалось выше, разработка богатого GUI это сложно и выливается в сложные системы, состоящие из множества элементов, взаимодействующих друг с другом. Чем более сложную систему вы создаёте, тем больше у вас багов. И по сравнению с традиционными веб-приложениями, использующими MVC, сложность SPA просто безумная.
Например, для сохранения консистетности на сервере вы можете использовать ограничения в БД, валидации модели и транзакции. Если что-то пойдёт не так, вы отвечаете с сообщением об ошибке. В клиенте, всё слегка сложнее. Очень многое может пойти не так просто потому, что слишком много всего происходит. Может быть так, что какая-то запись сохраняется удачно, а какая-то другая запись нет. Возможно, вы перешли в оффлайн посередине какой-то операции. Вы должны убедиться, что UI остаётся консистентным, и что приложение восстанавливается после ошибки. Всё это возможно, конечно, только намного сложнее.
Это звучит глупо, но для разработки SPA, вам нужны разработчики, которые знают, что с этим делать. В то же время, вам не стоит недооценивать сложность SPA, вам не стоит думать, что любой опытный веб-разработчик с правильной мотивацией и пониманием может написать отличное SPA с нуля. Вам нужны правильные навыки и опыт или ожидайте, что важные ошибки будут сделаны. Я знаю это, потому что это в точности мой случай.
Это возможно более важный вызов для вашей компании, чем вы думаете. Подход SPA поощряет команды узкой специализации вместо команд из специалистов общего профиля:
Шансы таковы, что вы окажетесь с людьми, которые не могут работать с SPA, и которые не могут работать на серверной стороне, просто потому что они не знают как.
Эта специализация может идеально подходить для Facebook или Google и их команд, состоящих из нескольких слоев инженерных войск. Но будет ли это хорошо для вашей команды из 6 человек?
Есть 3 вещи, входящих в современный Rails, которые могут изменить ваше мнение о разработке современных веб-приложений:
Трудно понять, какого это применять какой-то подход, не поиграв с ним. Поэтому я сделаю несколько отсылок на Basecamp в следующих разделах. Я не имею никакого отношения к Basecamp, кроме как счастливый пользователь. Что касается этой статьи, это просто хороший живой пример современного Rails, который вы можете попробовать бесплатно.
Идея Turbolinks проста: ускорьте ваше приложение, полностью заменив перезагрузку страниц на AJAX запросы, которые заменяют `` элемент. Внутреннее колдовство, выполняющее эту работу, скрыто. Как разработчик, вы можете сосредоточиться на традиционном серверном программировании.
Turbolinks вдохновлён pjax и прошёл через несколько ревизий.
Раньше я беспокоился о его производительности. Я был неправ. Ускорение огромно. То, что меня убедило, это то, как я использовал его в проекте, но вы можете просто попробовать пробную версию в Basecamp и поиграться с ней. Попробуйте создать проект с некоторыми элементами, а затем перемещайтесь по ним, щелкая по разделам. Это даст вам хорошее представление о том, как выглядит Turbolinks.
Я не думаю, что Turbolinks просто потрясает своей новизной (pjax — 8 лет). Или своей технической утонченностью. Меня поражает то, как простая идея может повысить вашу производительность на порядок по сравнению с альтернативой SPA.
Позвольте мне выделить некоторые проблемы, которые он устраняет:
MVC на сервере, в варианте, используемом Rails и многими другими фреймворками, намного проще, чем любой из шаблонов, используемых для архитектуры богатых графических интерфейсов: получить запрос, поработать с БД для его удовлетворения и отобразить страницу HTML в качестве ответа.
Наконец, ограничение, что всегда заменяется имеет замечательный эффект: вы можете сосредоточиться на первоначальном рендеринге страниц вместо того, чтобы обновлять определенные разделы (или обновлять некоторые состояния в мире SPA). В общем случае он просто все делает.
Заметьте, я говорю не об обозначении проблем, а об их устранении. Например, GraphQL или SPA-регидратация — это суперумные решения для очень сложных проблем. Но что, если вместо того, чтобы пытаться найти решение, вы ставите себя в ситуацию, когда эти проблемы не существуют? Это изменение подхода к проблеме. И мне потребовались годы, чтобы в полной мере оценить способность этого подхода решать проблемы.
Разумеется, Turbolinks не является беспроблемной серебряной пулей. Самая большая проблема заключается в том, что он может сломать существующий JavaScript код:
Помните, когда рендеринг HTML через Ajax был в тренде 15 лет назад? Угадай, что? Это все еще замечательный инструмент, который есть в вашем арсенале:
Вы можете видеть, как этот подход ощущается в Basecamp, открыв меню вашего профиля, нажав на верхнюю правую кнопку:
Открывается мгновенно. Со стороны разработки вам не нужно заботиться о сериализации JSON и клиентской стороне. Вы можете просто отобразить этот фрагмент на сервере, используя все возможности Rails.
Похожий инструмент, который Rails включает в себя в течение многих лет, — это серверные ответы JavaScript (SJR). Они позволяют вам отвечать на запросы Ajax (обычно формировать представления) с JavaScript, который исполняется клиентом. Он дает те же преимущества, что AJAX-рендеринг HTML-фрагментов: исполняется очень быстро, вы можете повторно использовать код на стороне сервера, и вы можете напрямую обращаться к базе данных для создания ответа.
Вы можете увидеть, как это происходит, если вы зайдёте в Basecamp и пытаетесь создать новый todo. После того, как вы нажмете «Добавить todo», сервер сохранит todo и ответит фрагментом JavaScript, который добавляет новый todo в DOM.
Я думаю, что многие разработчики сегодня смотрят на AJAX-рендеринг и SJR-ответы с презрением. Я тоже это помню. Они являются инструментом и, как таковые, могут подвергаться злоупотреблениям. Но при правильном использовании это потрясающее решение. Позвольте вам предложить отличный UX и интерактивность по очень низкой цене. К сожалению, как и Turbolinks, их сложно оценить, если вы ещё не сражались с SPA.
Stimulus — это JavaScript фреймворк, опубликованный несколько месяцев назад. Он не заботится о рендеринге или об управлении состоянием на основе JavaScript. Вместо этого, это просто хороший, современный способ организации JavaScript, который вы используете для добавления HTML:
Если вы примете Rails-путь, ваш JavaScript будет сосредоточен на изменении HTML-кода, созданного на стороне сервера, и улучшении взаимодействия (c небольшим количеством JavaScript). Stimulus предназначен для организации такого кода. Это не система SPA и не претендует на то, чтобы быть таковой.
Я использовал Stimulus в нескольких проектах, и мне это очень нравится. Он избавляет от кучи шаблонного кода, он построен на последних веб-стандартах и читается очень красиво. И что-то, что я люблю особенно: теперь это стандартный способ сделать что-то, что до сих пор приходилось решать в каждом приложении.
Turbolinks обычно продается как «Получите все преимущества SPA без каких-либо неудобств». Я не думаю, что это полностью верно:
Теперь разработка — это игра компромиссов. И в этой игре:
Я считаю, что с Rails вы можете получить 90% того, что предлагает SPA с 10% усилий. Что касается производительности, Rails убивает SPA. Что касается UX, я думаю, что многие разработчики делают ту же ошибку, что и я, предполагая, что SPA UX является непревзойденным. Это не так. Фактически, как обсуждалось выше, вам лучше знать, что вы делаете при создании своего SPA, или UX будет на самом деле хуже.
Я наблюдаю за тем, как компании массово принимают SPA фреймворки, и вижу бесчисленные статьи о том, как делать причудливые вещи в стиле SPA. Я думаю, что существует много «использований неправильного инструмента для работы», поскольку я твердо верю, что типы приложений, которые оправдывают использование SPA, ограничены.
И я говорю, что оправдывают, потому что SPA сложны. Во всяком случае, я надеюсь, что убедил вас в этом. Я не говорю, что невозможно создать великолепные SPA-приложения, или что современные Rails-приложения великолепны по определению, просто один подход суперсложный, а другой намного проще.
Готовя эту статью, я наткнулся на этот твит:
Это заставило меня посмеяться, потому что я выберу первые варианты, если альтернатива не будет оправдана. Он также является представителем своего рода
По прошествии многих лет я понял, что сложность часто является выбором. Но в мире программирования на удивление сложно выбрать простоту. Мы так высоко ценим сложность, что принятие простоты часто заставляет мыслить по-другому, что по определению — трудно.
Помните, что вы можете избавиться от неприятностей. Если вы выберете путь SPA, убедитесь, что он оправдан и вы понимаете проблемы. Если вы не уверены, экспериментируйте с разными подходами и убедитесь сами. Возможно, Facebook или Google, в их масштабе, не имеют роскоши принимать такие решения, но вы, вероятно, можете.
И если вы разработчик Rails, который покинул Rails много лет назад, я рекомендую вам вернуться к нему. Я думаю, вы будете в восторге.
Автор: Юрий Артамонов
Источник [2]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/javascript/286812
Ссылки в тексте:
[1] мозга: http://www.braintools.ru
[2] Источник: https://habr.com/post/417875/?utm_source=habrahabr&utm_medium=rss&utm_campaign=417875
Нажмите здесь для печати.