Не так давно 12.12.2018 был анонсирован выход новой библиотеки для фанатов phoenix framework под названием Phoenix LiveView. Я бы хотел поделиться с вами впечатлениями от ее использования и phoenix в целом, а в следующей статье попробовать написать простую браузерную игру. Часть статьи с личным мнением не является исключительно правдивой, я попробую объяснить преимущества веб-разработки на примере phoenix против php
Теоретическая часть
Phoenix — это фрэймворк на функциональном языке elixir. Прошу не путать с Phalcon для php.
Phoenix LiveView — это потрясающая новая библиотека, которая позволяет создавать динамические веб-страницы без написания javascript кода посредством двунаправленной связи по вебсокетам и server side rendering. Как мы прекрасно знаем, вебсокеты у phoenix достаточно хорошо реализованы, поэтому производительности хватит для большинства идей, которые вы планируете реализовать.
Существует несколько вариантов использования LiveView:
- Проверка ввода данных в формы (валидация), нажатие кнопок, скрытие и отображение блоков, автозаполнения.
- События от сервера, такие как уведомления, информационные панели, счетчики.
В данный момент с ограничениями доступны и приоритетны в будущем:
- Навигация по страницам и пагинация. Они могут быть построены с помощью LiveView, но в настоящее время вы потеряете функционал перехода «назад / вперед». Поддержка `pushState` включена в план.
- Отображение постоянно растущих данных — чаты, онлайн логи и т.п. можно создавать с помощью LiveView, но в настоящее время вы должны хранить все данные в состоянии приложения на сервере. Поддержка частичного обновления данных состояния находится в разработке.
- Работа с задержками при изменении состояния. LiveView хранит состояние приложения на стороне сервера и это гарантирует правильную работу интерфейса при серьезных задержках.
- Полный набор функций для моделирования этих ситуаций появится в будущих версиях.
В чем плох LiveView:
- Анимации. К примеру отображение меню по клику можно реализовать через LiveView, но плавное появление лучше отдать в css или js.
- Optimistic UI. Приложение рассчитано на постоянную работу с стейтом сервера и этого стейта нет на клиенте. Весь html код на любое событие подготавливается на сервере с новым состоянием и летит по вебсокетам к клиенту, все видимые изменения происходят посредством подмены html кода.
Как работает LiveView?
Изображение взято с elixirschool
LiveView начинается с обычного HTTP-запроса и HTML-ответа, а затем приступает к отслеживанию состояния приложения на сервере через вебсокеты, при этом гарантируя отображение обычной HTML-страницы, даже если JavaScript отключен. Каждый раз, когда состояние приложения меняется, оно автоматически перерисовывает отображение и обновления передаются клиенту. На клиенте при помощи библиотеки morphdom происходит обновление контента. По сути, логика достаточно близкая к современным js фрэймворкам, только без использования virtual DOM.
Чтобы сеанс связи не терялся при повторном подключении, из контроллера инициируется «сессия» пользователя с необходимыми данными и передается клиенту. Только подписанная сессия с первичными данными хранится на клиенте, она отправляется на сервер при подключении, или повторном подключении в случае сбоя, к состоянию приложения.
Впечатление и личное мнение о самом Phoenix
Из личного опыта скажу, что редко встречал понятно написанные приложения в командах от 3х и более человек. Часто встречается мешанина из сервисов на php(сервер) nodejs (websocker) react/vue (фронт) туда еще и go засунут для вещей, которые «медленно» работают на php. Очереди мы в redis засунем, потом подключим rabbitmq, а один из разработчиков не умеет ими пользоваться и реализовал в sql. Кто-то умеет правильно пользоваться кроном через flock и не городит логику защиты повторного запуска в коде, а другие запускают демоны на php, что иногда вставляет палки в колеса при обновлении кода и структуры бд. Состояние приложения начинает хранится везде и всюду, в статике класса, в синглтоне, порой даже в статической переменной метода, начинают множится правила написания кода чтобы бороться с незнанием языка и правильным построением архитектуры, но что если проект начинал программист уровня middle или junior на коленке, не задумываясь что это все вырастет до настоящего бизнеса? Поддерживать такое в одиночку не так просто, часть логики дублируется как на клиенте, так и на сервере (валидация к примеру). В SPA, когда фронт начинает использовать публичное api, мы начинаем задумываться о версионировании. Поддержка усложняется т.к. приходится удовлетворять не только нужды внешних сервисов и клиентов, но и свой часто изменяемый фронт, а дублировать код не хочется. Прикручивам graphql. Со временем зоопарк библиотек разрастается и фирмы начинают нанимать больше разработчиков.
Тут я и вижу превосходство phoenix. Из коробки у нас замена php (elixir + Phoenix), nodejs (вебсокеты на Phoenix.Socket), react/vue (Phoenix.LiveView), redis(ets), rabbitmq (ets), cron (возможно через GenServer), демоны (GenServer), урезанная бд (mnesia). У нас кеширование в самом языке через mnesia или ets, крон или демоны вообще без проблем т.к. многозадачность и работа в фоне годами у «эликсира в крови». Хранение состояния чаще всего в генсервере. Публичное api исключительно для нужд внешних сервисов, spa в скором времени будут писаться на LiveView. Поддержка api станет куда проще. Масштабируемость в любое направление средствами языка, скорость работы ограничена только источником хранения данных, все остальное работает весьма быстро. Достаточно понятная схема работы если один раз узнать как работает plug и что такое conn. Генерация кода, «микросервисная архитектура» — посмотрите в сторону umbrella application. Это все пытаются решить докерами с оркестрацией и т.п. создавая рабочие места для большого количества devops инженеров.
Итог
Попробуйте установить elixir и запустить phoenix. В этой статье я постарался изложить «воду», личное мнение и теоретическую часть, чтобы в следующей ограничится исключительно кодом и логикой. Мы будем писать простую игру на LiveView формата dogeminer но без функциональности кликера. Это моя первая статья, прошу строго не судить и не воспринимать чрезмерно серьезно, я намеренно однобоко показал достоинства Phoenix и упустил его недостатки. Их лучше ощущать на практике чем вот так на мнении чужого человека.
Присоединяйтесь к русскоязычному сообществу elixir разработчиков proelixir или находите в telegram @proelixir. Свежие новости языка собирает бот на канале @proelixir_news.
Комментарии (21)
SbWereWolf
19.05.2019 12:52хранить состояние на сервере это дорогое удовольствие, это постоянная запись нового состояния. Постоянное чтение — это нормально, это быстро, а постоянная запись это просто долго. Состояние клиентского интерфейса надо хранить на клиенте, пусть он у себя перезаписывает и рендерит своё состояние, серверу зачем этим заниматься? Что бы обойтись толко PHP и не искать JS программиста?
Virviil
19.05.2019 13:11При чем тут вообще PHP?
avidcrawler
19.05.2019 15:39+1> Из коробки у нас php (Phoenix)
Видимо, читатели не знакомые близко с предметом статьи, интерпретировали эту фразу буквально :)Virviil
19.05.2019 15:44Возможно, автор написал запутано, но вроде как нигде он не запутался.
Из коробки у нас php (Phoenix), nodejs (вебсокеты на Phoenix.Socket), react/vue (Phoenix.LiveView), redis(ets)
Почему
php(Phoenix)
может запутать, если перечисление продолжается, и из него видно противопоставление? Так можно подумать что разговор идет и про nodejs фреймворк. Или даже одновременно про PHP и Nodejs фреймворк (как бы это парадоксально не звучало)...
Но в принципе, можно было и попонятнее сформулировать, в этом я с вами согласен
barkalov
20.05.2019 03:17так можно подумать что разговор идет и про nodejs фреймворк
Phoenix LiveView: когда вам больше не нужен JavaScript*
Nexon
20.05.2019 01:32-1Спасибо за статью. Как раз хотел освоить что-нибудь новое в отпуске.
Я правильно понимаю, что данная технология применима в Tor/I2P, т.к. способна работать без JS?
AxisPod
Т.е. новый виток в создании более тормозных сервисов?
Slavenin999
На чем основано утверждение? Вы пробовали live view?
AxisPod
Просто все стараются переносить часть обработки на сторону клиента, но никак не на сервер.
dsnipe
При этом необходимо создавать копию состояния и налаживать синхронизацию. К тому же необходим JS программист.
Для стартапа быстрый выход на рынок — это наивысший приоритет. К тому же бюджет не всегда позволяет иметь полноценную команду. Вот тут Phoenix + LiveView будут идеальным вариантом.
В дальнейшем, если база пользователей будет уже серьёзной, то и деньги должны быть и команду можно побольше нанять. Тогда уже вопрос оптимизаций и т.п. будет актуален.
Так что рынок для этого решения огромный.
Но сейчас я столкнулся с тем, что молодые backend программисты не готовы (да и не умеют) верстать HTML и стили :) Вот это уже другая проблема.
JustDont
Нет, это что-то типа «php пытается выглядеть более живым и полезным, чем он есть».
Полный server-side rendering в ряде задач будет вполне уместен. А в ряде других задач — да, будет тормозным и убогим поделием, требующим непрерывной связи с сервером, и желательно, чтоб сервер стоял в соседней комнате (чтоб latency поменьше).
Virviil
При чем тут вообще PHP?
JustDont
Вы на этот Phoenix смотрели, нет? Если смотрели, откуда вопросы?
Virviil
Не только смотрел, но даже писал на нем. И точно уверен, что Phoenix к PHP не имеет никакого отношения. Вы бы что-ли на теги к статье посмотрели, на ссылки пощёлкали...
vril
Вы часом не с Фалконом путаете?
Virviil
Сперва происходит рост уровня взаимодействия за счёт раздувания инфраструктуры — потом схлопывание инфраструктуры без потери уровня взаимодействия.
Так что да, мы вроде как на новом витке)
Ru6aKa
Вообще по сути это третья реализация подходов которые были использованы в nitrogen, старогом erlang фреймворке.
Первая реализация была в виде CMS zotonic, в которой под капотом такой же подход как и в nitrogen.
Вторая реализация в виде n2o erlang фреймворка, по сути это переписанный с нуля nitrogen, с вебсокетами и разными вариантами кодирования сообщений.
Третья реализация и скорее всего не последняя от команды разработчиков Phoenix.
Подход очень простой:
1. Сервер отдает сгенерированный html клиенту. В котором все элементы с которыми взаимодействует пользователь (кнопки, выпадающие списки, поля ввода и т.д.) кроме уникальных id (сгенерированных на стороне сервера), содержат js код для отправки payload(нагрузка с данным или просто событием) на сервер…
2. При получении события на стороне сервера происходит декодирование нагрузки, подготавливается ответ, и отправляется клиенту.
3. При получении клиентом сообщения от сервера происходит выполнение кода, как правило это prepend/append, addClass/removeClass, так же может поменять значение элемента или заменить весь блок.
Плюсы такого подхода:
1. Состояние коннекта храниться на сервере, и поэтому не теряется при перезагрузке, так же отпадает надобность в хранилище состояние для фронтенд фрейморка.
2. Для данных которые постоянно дописываются в конец, нету лишнего преобразования данных, с сервера прилетает уже готовый html (в случае фронтенд фрейморков, сервер отдает данные в json, а фреймворк эти данные добавляет в дерево).
3. Для долгих задач на стороне сервера, не надо писать особую логику. Если пользователь закрыл вкладку, то пришедшие данные просто ничего не поменяют.
4. Для клиентов с выключенных js, отдается уже готовый контент, пускай и с урезанной интерактивностью.
Да есть и минусы:
1. Основной минус, что шаблоны и данные идут в перемешку, можно забыть про MVC и прочие патерны.
2. На каждое действие пользователя летит событие на сервер и ответ обратно, при плохой сети это может вызывать проблемы с интерактивностью приложения.