Всем привет! Меня зовут Иван Ситкин, я бэкенд-разработчик в Едадиле. Сегодня я хочу поделиться с вами историей написания очередной панели администрирования и как из этого мы собрали подходящие подходы и практики.
Для начала давайте вспомним, что же это за панели. Панель администрирования (или админка) — это приложение, которое используется для управления и настройки приложения. То есть это такой продукт для продукта. Панели администрирования нужны для различных целей, например, для создания и редактирования контента, настройки параметров продукта или управления пользователями.
Но иногда в проектах важна скорость и ресурсов на создание админки с привлечением команды фронтенда откровенно не хватает. И тогда бэкендеру приходится брать процесс в свои руки.
А теперь вы готовы погрузиться в эту кроличью нору.
Внимание!
Эта статья не является призывом отменить существующие методологии разработки приложений на стыке фронтенда и бэкенда. Это статья о том, как мы пришли к нестандартной организации проектов, которая помогает нам быстро создавать и сопровождать наши элементы управления продуктом.
Точка отсчёта
Наша команда в большинстве случаев использует Python, поэтому неудивительно, что в своё время для админок был выбран Flask вместе с Flask-Admin. Это лёгкие и доступные инструменты с достаточно богатым набором примеров, документацией, сообществом, а также с открытым исходным кодом.
Админки в нашем понимании — это набор страниц, которые формируют интерфейс для выполнения типичных операций над объектами, то есть создание, чтение, обновление и удаление (CRUD). Но со временем стало заметно, что такие проекты команде стало дорого сопровождать, так как требовалось прикладывать намного больше усилий для составления логики поведения страницы. Например, добавлять поле с выбором объектов из нового API. Тогда мы решили посмотреть, как такую проблему решают другие команды и комьюнити.
В интернете пишут, что правильно вот так
Вы наверняка знаете, что есть такой подход к проектированию веб-приложений — API First . Если коротко, то это означает, что сначала разработчики формируют набор контрактов, или какую-то спецификацию API, а потом все вместе реализуют её как на бэкенде, так и на фронтенде.
Разумеется, такой подход имеет ряд преимуществ:
Единоразовая разработка бэкенда, которую можно использовать многократно для создания фронтенда на различных платформах, таких как веб-браузер или мобильные приложения.
Возможность предоставить доступ к API третьим лицам. Например, разработчикам сторонних продуктов для интеграции с вашим приложением.
Однако, у этого подхода есть ряд серьёзных ограничений:
Очень сложно менять контракт и спецификацию API.
Если понадобится, придётся поддерживать несколько версий API, чтобы не нарушить существующие интеграции.
Необходимо поддерживать и развивать две отдельные части — бэкенд и фронтенд.
Именно из-за этих ограничений цена разработки сильно возрастает. Ниже попробую показать почему.
Давайте пофантазируем о том, как именно это бывает
Есть две команды: фронтенд и бэкенд. Давайте, для нашего карикатурного примера назовём их «Хищники» и «Травоядные Чужие». Работают они по SCRUM, используют API First. Так как основной продукт — приложение на iOS, Android и Web, этот подход отлично работает. Зачем нам изобретать велосипед — давайте и админки писать точно так же.
Итак, команде «Чужих» ставим задачу на спринт: сделать спецификацию API. В особо удачных случаях команда дизайна успела нарисовать макет и согласовать его у ответственного за UX.
Разработчик целую неделю проектирует на Swagger. Смотрит в СУБД проекта, а там не хватает пару полей. «Чужой» заводит задачу на миграцию в следующий спринт (этот-то уже битком). Потом делает спецификацию API, отдаёт её на ревью своей команде. Разумеется, очень опытный коллега находит, скажем, шесть мест, где могут возникнуть проблемы с безопасностью. После пары часов обсуждений задачу закрывают, но заводят ещё три задачи в бэклог: на починку потенциальных и сугубо теоретических проблем в безопасности ещё нереализованного API и собственно на реализацию самого API.
Прошёл спринт, задачи закрыты, все молодцы. Отдаём Swagger команде «Хищников». Разработчик с их стороны через пару дней закончил писать абстрактный класс клиента и тесты к нему. Наконец, можно открывать макет и начинать верстать!
Не буду тут ударяться в подробности, скажу лишь, что в Swagger-API, например, нет поля, по которому фронтендер будет сортировать результаты. Ну и обязательно найдутся ещё какие-нибудь неочевидные штуки.
И что же мы имеем по истечении двух недель:
задачи на безопасность, миграцию данных, само API и «ещё что-нибудь» в бэклоге «Чужих»;
задачи на сборку фронта и деплой ноды у «Хищников»;
макет от дизайнеров;
пачка задач от главного за UX.
И главное: бэкенд не готов, фронтенд не готов.
Если серьёзно, то пример выдуман для подчёркивания проблем, так что любые совпадения с реальными персонажами — чистая случайность. Но вы можете написать в комментариях, было у вас что-то такое или нет.
Что же тут пошло не так
Всё же требования к основному продукту значительно отличаются от требований к админке, как минимум в таких критериях:
Сроки релиза. Надо сделать админку намного быстрее, чем основной продукт.
Требования по поддержке платформ. Можно забить на IE9, а в особо запущенных случаях вообще сказать всем сотрудникам поставить определённый браузер только для этой админки, или привезти им «правильный браузер» через AD-профиль. На бизнес это никак не повлияет, но мы делать этого, конечно же, не будем.
Требования к качеству. Если не работает кнопка сортировки, клиент не уйдёт к конкурентам (потому что чаще всего это наш сотрудник).
Требования к поддержке. В случае основного продукта /api/v1/ надо поддерживать до тех пор, пока есть хотя бы один клиент, использующий его. Но в случае админок нужен только самый актуальный клиент.
Как исправить ситуацию
Так как мы всё-таки инженеры, давайте сформируем требования и критерии успеха. Да и вообще, что мы будем делать и как оценивать результат.
Выкатывать на прод новую форму админки в среднем за день.
Приложение корректно работает в современных браузерах: Safari, Firefox и весь Chrome-based.
Та часть админки на Python, с которой взаимодействует JS, покрыта тестами.
В JS-части должно быть минимум логики, тесты на JS мы писать не хотим (в идеале, конечно, совсем не писать на JS, но это по ситуации).
Можно быстро ломать API, но при этом не ломать клиент.
Наш идеальный мир — это отдельный микросервис, который раздаёт JS-код, а он, в свою очередь, и является его админкой. То есть первый критерий успеха — когда коды клиента и бэкенда мирно сосуществуют в одном репозитории (это необязательно, но было бы приятным бонусом).
Так как бэкенд у нас на Python, а фронтенд — на JS, то отказ от транспиляции и сборки приложения в бандл, кажется логичным. То есть как в нулевых:
<script src="/static/myframework.js"></script>
<script src="/static/app.js"></script>
При этом, конечно, никакой myframework.js мы писать не хотим. Мы хотим подобрать такой, который может работать без транспиляции. А app.js — это не минифицированный код нашей админки. Таким образом наш бекенд на Python сможет раздавать приложение как обычную статику, а вместо минификации просто будем раздавать gzip-файлы.
Однако есть небольшая проблема: в современной индустрии фронтенда так не принято.
API Last
Поразмыслив над всем этим, мы изобрели (может, и не мы) обратный путь. Встречайте – API Last. Вот что мы вкладываем в этот подход:
Клиент останется только один. Для нас это
Дункан МакКлаудJS-клиент в браузере.Если нам понадобится второй клиент, напишем для него отдельный микросервис. Спойлер: в случае админок такого ещё не случалось.
Мы не публикуем контракт, а пишем UI-часть вместе с бэкенд-частью. В идеале прямо в одном репозитории.
Так как мы не хотим использовать полноценную сборку, значит, фреймворк-дистрибутив должен быть собран под браузер и иметь возможность использовать бо́льшую часть фичей фреймворка в рантайме, например, шаблоны.
На дворе был 2019 год. На тот момент было три популярных фреймворка: React, Angular и Vue.
React можно собрать под браузер, а в коде приложений использовать не JSX, а VDOM API. Но код админки будет выглядеть сложным и трудночитаемым.
В Angular все примеры в документации были на TS, а рантайм интерпретатора нет. Да и через 4 года мало что изменилось.
У Vue есть сборка под браузер. Можно использовать как VDOM API, так и компилировать шаблоны в рантайме. Как раз то, что нам и нужно.
Первый полёт
Для эксперимента собрали тестовый проект. В нашем случае это был простенький веб-сервер на aiohttp, который раздаёт html-страницу и немного статики.
Мы взяли уже подготовленный Vue c unpkg, добавили его в index.html и начали раздавать его бэкендом. Выглядел он примерно вот так:
<head>
<script src="https://unpkg.com/vue@2.7.14/dist/vue.js"></script>
{% for component in components %}
{{ component }}
{% endfor %}
</head>
<body>
<div id="app"></div>
</body>
Как можно заметить, мы вставляли компоненты прямо в index.html, используя Jinja. Но мы быстро поняли, что для компонент нужна топологическая сортировка, так как они могут быть зависимыми друг от друга в неочевидном порядке.
Формировать её на бэкенде, то есть парсить код компонентов и сортировать, очень не хотелось. Поэтому для загрузки компонент мы собрали скрипт, который загружает их в порядке, указанном в index.html. Топологическую сортировку приходилось поддерживать самостоятельно — конечно, это зло, но меньшее.
Затем пришло понимание, что нам мало одного Vue. Не вопрос, добавили ещё один скрипт из unpkg. Но чтобы не тянуть сорок мульёнов зависимостей, пришёл мой коллега @orlovdl и написал скрипт, который качает из unpkg библиотеки и пакует в один жирный vendor.js. А так как набор библиотек меняется не так часто, то и vendor.js (а в последствии vendor.js.gz), мы решили хранить прямо в репозитории.
На этом этапе у нас уже появилась возможность собирать SPA-приложение без сборки, писать код, перезагружать страницу в браузере и видеть результат.
Оригинальные проекты для сравнения, конечно же, растворились в пучине времени. Тем не менее идея была проста: понять, проседаем ли мы по производительности без использования сборки. По ощущениям — да, безусловно, но те же ощущения, подсказывали что на наших небольших приложениях это будет почти незаметно.
Кому интересны детали, милости просим ворваться вот сюда. В этом репозитории представлены аналоги наших первых прототипов.
Затем встал важный вопрос про взаимодействие бэкенда и фронтенда. Нам было важно сделать настолько тонкий клиент, насколько это возможно, так как мы не хотели писать на него тесты. Это значит, что самым простым вариантом будет программировать всю логику на бэкенде, а клиент использовать только для отображения результатов вызова методов. Ой, а ведь это уже очень похоже на какой-нибудь RPC...
Конечно, можно использовать обычный REST API в формате json, а уже на стороне клиента вызывать API, десериализовать json в объекты и обрабатывать ошибки. Но наш подход – если можно не писать JS, то мы и не будем. А для aiohttp есть полноценный пакет, который мы и решили использовать — wsrpc-aiohttp.
Эксперимент посчитали успешным и решили попробовать его на новой админке. Конечно, умение писать, как в нулевых, требует определённой сноровки, но команде такой подход зашёл, ведь у него достаточно низкий порог входа. В дальнейшем мы собрали десяток админок на этих рельсах.
Промежуточные результаты
Теперь можно проверить, каких целей, которые мы обозначили для себя выше, удалось достичь:
Выкатываем на прод новую форму админки буквально за пару часов. Зависит, конечно, от сложности формы, но скорость разработки теперь хотя бы прогнозируемая.
Приложение корректно работает в современных браузерах.
Часть на Python, с которой взаимодействует JS, покрыта тестами, как и любой другой наш API.
В клиенте минимум логики, так как он только и делает, что вызывает RPC и просто мапит полученный результат в поля компонентов.
Можно быстро ломать API и тут же чинить клиент или дописывать новый RPC-вызов, а старый просто убрать. И теперь нет нужды поддерживать устаревший код.
Но, конечно, не всё так радужно. Есть и менее приятные моменты:
Нужно писать компоненты в старом стиле. (такие модули используют особенность языка, где создается замыкание и тут же вызывается для изменения глобальной области видимости)
Нужно поддерживать топологическую сортировку руками.
Не все библиотеки собраны под браузер.
Область видимости модулей доступна прямо из консоли.
Если вам интересно, поднять свою песочницу можно через этот шаблон.
Также, но по-новому
Во второй половине 2020 года вышел Vue3. И, конечно же, мы захотели на него перейти.
В один из дней мозгового штурма пришёл @dizballanze и рассказал про появление нескольких CDN: например, esm.sh, которая предоставляет библиотеки аналогично unpkg, но в формате esm. А его вполне поддерживают современные браузеры. Ко всему прочему, новая версия Vue уже шла со сборкой в этом формате. Нормальные импорты слишком сильно манили нас в очередное подземелье, но не тут-то было...
Мы обнаружили главную проблему – Vue Single-File компоненты требуют определённой предобработки. Фактически нам нужно повторить наш загрузчик, который разбивал SFC на блоки: шаблон, стиль, скрипт. Но, само собой, кастомный fetch браузеры не поддерживают и мы взяли перерыв на очередные исследования.
В качестве решения мы нашли es-module-shims, который расширяет поддержку в браузерах, а также в режиме shim позволяет использовать кастомный fetch. Это дало нам возможность переиспользовать загрузчик и продолжать использовать Single-File компоненты (ну, нравятся они нам).
Теперь дело за малым: собрать vendor в нужном формате, так как тянуть библиотеки с CDN через importmap не даёт нужного управления кэшем и контентом. В очередной раз мы пошли шерстить интернет в поисках подходящего инструмента. Наткнулись на быстрый-модный-молодежный esbuild и решили попробовать на нём.
Теперь сборка зависимостей выглядит следующим образом:
Управляем зависимостями стандартным образом — у нас yarn (но можно, при желании и npm).
Указываем нужные нам объекты в файле vendor.js.
Собираем его через esbuild, сжимаем gzip и так же храним в репозитории.
Повторяем всё с шага 1, когда обновляем зависимости.
Последний пункт на практике нужен довольно редко: разработчик 98% времени пишет саму админку, а не зовёт yarn, npm или webpack, как это было бы при стандартном подходе. Лишь иногда отдельным PR обновляется vendor и коммитится в репозиторий. Более того, у новичков может быть даже не установлен ни npm, ни yarn, ни даже node — просто делаешь:
git clone $projectUrl
и пишешь формы, потому что все зависимости к тебе уже приехали собранными.
В итоге концептуально всё осталось прежним: тонкий клиент, который раздаётся бэкендом напрямую без сборки после каждого Merge Request. Однако есть несколько изменений:
Мы не сильно проиграли в скорости работы на наших небольших SPA. Убедились в этом, измерив в песочнице.
Используем современные модули, которые даже визуально чище старых, а также позволяют управлять областью видимости тех или иных объектов.
Теперь не нужно поддерживать топологическую сортировку, ведь она сама размотается через import или export.
В итоге мы сохранили все плюсы и получили парочку бенефитов.
На текущий момент мы используем именно этот вариант для наших админок. Если вам интересно пощупать это нечто, пример этого монстра в зародыше есть вот тут, а свою песочницу поднять можно через cookiecutter-шаблон. А если вам интересна отдельная статья на тему того, как стартовать проект, используя наш шаблон, не забудьте написать об этом в комментариях.
Само собой, мы регулярно оглядываемся на то, что происходит в индустрии. Мы не отменяем сборку как идею, скорее мы нашли способ организации проекта и взаимодействия между элементами, который позволяет нам быстро и без большой боли собирать инструмент для управления продуктом. Если у вас схожи потребности, то, может быть, такой подход поможет и вам.
Вместо заключения
Так как всё же заставить бэкендера писать фронтенд? Краткий ответ звучит так — никак.
Критически важно избегать ситуации, когда добавление простой формы приводит к панике и необходимости быстро освоить десяток новых инструментов.
Вместо этого необходимо сделать процесс создания админок настолько простым, насколько это вообще возможно. Чтобы человек мог оставаться в своей роли в команде и жил по принципу: «Я так-то бэкендер, а написание формочек это так, для души».
Комментарии (67)
BerdBerd
18.05.2023 10:55Прикол конечно.
Я вот вообще базист + аналитик + дата сайнтист + немного бекендер и девопс (ML модели в продакшн разворачивать)
С нового года React изучаю - очень нравится - очень удобно.
Уже до Next.js дошёл.
cat_chi
18.05.2023 10:55+4Как заставить бэкендера писать фронтенд
Хотел написать "никак", а потом дошёл до заключения... ????
Но всё-таки непонятно, откуда в итоге берётся фронтенд. Много фронтендерских слов и терминов, которые очевидно понятны другим фронтендерам. А вот бэкендеру не помешал бы перевод.
Возможно, у меня неправильное представление о фронтенде в принципе? Вот я вспоминаю требования к фронтам, которые публиковались на одной из моих прошлых работ:
HTML5
CSS (SCSS, SASS или что там ещё)
Кроссбраузерная вёрстка, БЭМ
И т.д. и т.п. ещё куча фронтендерских слов, которые я не знаю. И это из вакансии на джуна. Т.е. жирнющая такая предметная область, где JS/TS и фреймворки конечно есть, но не только и не столько они. Если бы проблема была только в JS, то какая это проблема. Сколько времени нужно сеньор-бэкендеру, чтобы выучить новый язык, минут 15-20?
orlovdl
18.05.2023 10:55+1А если вам интересна отдельная статья на тему того, как стартовать проект, используя наш шаблон, не забудьте написать об этом в комментариях.
Вот тут как-раз про то, будет ли интересна статья, с неким таким hello-world-project, где по шагам можно воспроизвести это.
LordDarklight
18.05.2023 10:55+1Сколько времени нужно сеньор-бэкендеру, чтобы выучить новый язык, минут 15-20?
Ну уровне джуна, включая практику: 15-20 дней! (это был сарказм)
Spaceoddity
18.05.2023 10:55+1Возможно, у меня неправильное представление о фронтенде в принципе?
Да. "Фронтенд" сейчас - это в основном по умолчанию про реактивные фреймворки. HTML/CSS и даже JS - это "вёрстка". Очень много людей сейчас пишет логику на JS, не трогая представление.
Сколько времени нужно сеньор-бэкендеру, чтобы выучить новый язык, минут 15-20?
На каком уровне? Как по мне - годы)) JS (впрочем и CSS) - очень динамично развивающийся язык. Многое из того, для чего 10 лет назад лепили различные костыли, сейчас по умолчанию реализовано на уровне браузерного api. Всё это запомнить нереально. Да что там... На нормальное освоение одного фреймворка месяцы уйдут. Там сейчас такие талмуды документации... Иным ЯПам не уступят.
cat_chi
18.05.2023 10:55Спасибо, познавательно :)
На каком уровне? Как по мне - годы))
Да я вас умоляю. На предметную область, конечно, много времени уходит. Кто ж будет спорить.
А на язык сам по себе – всего ничего. Вот пишу я бэк на... на чём угодно. Сложно ли будет перекотиться на такой же бэк, но с совершенно другим языком? Несколько раз делал. Вообще несложно, и длительность зависит не от языка, а от его экосистемы. Какая-нибудь упоротая система сборки больше времени отнимет, чем изучение самого языка.
А новую область даже на знакомом языке осваивать тяжело и больно.
aborouhin
18.05.2023 10:55Основатели Retool, развив дальше подобные рассуждения, свой бизнес и создали. Для админки, которая может быть неидеальной, но нужна быстро и минимальными усилиями, Low-Code как раз может быть вариантом (при всём моём скептическом отношении к попыткам подобные инструменты применять для других целей).
ftc
18.05.2023 10:55+5Вообще в написании админок (когда из требований - много заковыристой бизнес-логики, зато можно подзабить на расходуемые ресурсы и не сильно заморачиваться на предмет "лишний раз сделать запрос на сервер / перезагрузить страницу") - очень хорошо работает PHP с server-side rendering.
Вот буквально, берём какой-нибудь Yii и на нём очень быстро можно штамповать CRUDы (даже генератор встроенный завезли), а при надобности всегда можно натаскать каких-то виджетов, чтобы логику на клиенте ваять, если нужна. Да, jQuery, да, по фронтенд-меркам технологии прошлого века. Но работает же. И делается быстро.orlovdl
18.05.2023 10:55В яднексе запрещен PHP.
ftc
18.05.2023 10:55+1Ого, не знал. А чем мотивировано? Или просто "исторически так"
orlovdl
18.05.2023 10:55+3Мне кажется, что постоянные секьюрити проблемы, во всем что касалось PHP, 10-15 лет назад тому виной.
И, с моей точки зрения, непонятно почему PHP лучше или хуже чем тот-же Flask-Admin на Python. Принципиально тоже самое.
Мы преследовали цель свести верстку и все что касается фронтенда к минимуму, поэтому просто готовые компоненты на vue https://element.eleme.io/#/en-US/component/form которые просто нужно описать, и все, форма готова.
cat_chi
18.05.2023 10:55+1Может, банально нет опыта работы с ним? Т.е. ни кодовой базы, ни наработанных лучших практик, никакого отлаженного флоу... В таких условиях преимущества языка вообще теряются
bogolt
18.05.2023 10:55+7Так как всё же заставить бэкендера писать фронтенд?
повысить его до фуллстека а потом сказать что мол фронтовых задач навалило. И через полгода бэкенд обнаружит что кроме фронта почти ничего не делает.
Если что такое произошло с моим коллегой, который решил получить зп повыше за плашку "Фуллстек" в названии, а через полгода поменял работу потому что внезапно нанимался бэк писать а не фронт.orlovdl
18.05.2023 10:55Если не вырывать из контекста, то целиком цитата выглядит так:
Так как всё же заставить бэкендера писать фронтенд? Краткий ответ звучит так — никак.
На рынке труда очень много вакансий, если человек занимается тем, что ему не нравится, зачем себя мучать?
В вашей истории про коллегу, я так и не понял, ему нравилось то, чем он занимается, в процессе получения галочки "фуллстек", или нет ? Если и там нет, и он поменял работу потому что не смог договориться с руководителем – это прекрасно, не нужно никого мучать.
orlovdl
18.05.2023 10:55Так-же стоит отметить, что у меня был точно такой-же риск, как у руководителя, когда мы с@Alvinerвнедряля вышеописанное решение, никого не потеряли, к счастью.
И как мне кажется, именно потому, что мы никого не превращали в "фулстек"ов, мы четко ограничили проблемы, и наше видение их решения. И диапазон применимости, нашего решения мы умышленно не распространяли дальше вот этих вот "админок".
Ну а если вдруг найдутся коллеги, кому "зашло" то почему-бы не идти в сторону "фулстек"ов.
Xambey97
18.05.2023 10:55+1Плюсую, я как раз такая жертва. Был себе мидл бекендер. В один момент говорят, а у нас фронтовиков нет, надо кому-то делать, ты молодой, быстро разберешься. Дальше была неделя javascript'а, прохождение через ад, постепенно втянулся и через 5 лет понял, что я безнадежно отстал от актуального стека (привет неимоверно быстро развивающийся net core + другие новые субд и прочее) и сейчас, будучи крепким фронтенд сеньором стал понимать, что я уже не в состоянии быстро включиться в работу с беком. В сфере последних событий с ChatGPT все больше подумываю, а не следует ли мне с даунгрейдом по ЗП вернуться на бек, пока не поздно... А то так лет через 10-15 можно будет и без работы остаться на фронте
mayorovp
18.05.2023 10:55Актуальный стек .net лично я "догнал" за три дня (точнее, я его три раза "догонял" за день). Самое сложное там — убедить в этом HRов, потому что они просто не верят что опыт разработки на .net 5 что-то значит при разработке на .net 6.
uvelichitel
18.05.2023 10:55А зачем вам понадобился Vue?
Я бэкендер. Попадал в такую же ситуацию — я уже своё сделал, а фронт ещё копается, проверить не получается. Да и просто интересно было, как рендерятся json`ы которые я отдаю :-)
Замочил ноги в бескрайнем океане frontend. Напугался :-) Решил что для моих игрушечных кейсов всего и нужно то JS асинхронный запрос сделать. Для этого jquery достаточно, да можно и на plane.
PS. Понравился мне websocket транспорт. Вы не пробовали? Годится интересно для админки :-)orlovdl
18.05.2023 10:55+2Короткий ответ зачем нам понадобился vue:
При этом, конечно, никакой myframework.js мы писать не хотим
В вашем случае, на 40-й формочке, у вас уже будет фреймворк, и вам придется его поддерживать.
Alviner Автор
18.05.2023 10:55+1Имеешь в виду почему фреймворк, а не голый vanila-js+html с jquery? У нас был опыт во времена использования flask-a, но тебе приходится много писать boilerplate кода для клиента, который нужно поддерживать и сопровождать. Eсть всякие select2, которые уменьшают боль, до тех пор пока тебе не понадобится какой-то кастом от чего тебе приходится погружаться в библиотеку эту по самое не могу. Поэтому решили попробовать что-то из готового, а выбор на vue пал, так как он подошел нам по возможностям использования в рантаме прям в браузере с большинством своих фич.
А вот транспорт у нас как раз веб-сокеты) Для наших целей отлично подходят.
Alexsey
18.05.2023 10:55А можно все делать вообще не используя API и опираясь на генераторы и тогда не нужно себе насиловать мозги JS, SPA и прочим, а просто отдавать уже отрендереную страницу с сервера. Да-да, как в далекие нулевые. Не знаю что там в других языках, но на C# visual studio позволяет штамповать круды парой кликов мышью. Поменялась база? Снесли файлы, сгенерировали новые.
Но для Яндекса это видимо слишком просто, понимаю.
LordDarklight
18.05.2023 10:55+1Это уже прошлый век (но для примитивных формочек сгодится).
Сейчас под C# код через Blazor компилируется в WASM и исполняется на клиенте без перезагрузки страницы - никаких проблем (про проблемы это не правда но надо думать о позитиве). На UNO Platform (и в будущем на Alanonia) аналогично можно сверстать формы на XAML - и достаточно легко делать единое кроссплатформенное клиентское приложение вообще в едином API не заворачиваясь об HTML тэгах или каких-либо ещё XML тэгах вёрстки под разные платформы.
Аналогично у Koltin c Compose - но там не XAML - а вся вёрстка через код в, условно функциональном стиле (с блоками императивного кода)! На выходе для WEB будет JS, но о WASM Jetbrains сейчас тоже думает для WEB
dzaytsev91
18.05.2023 10:55+1Я бы кстати не согласился что прям прошлый век, тут скорее нужно отталкиваться от потребностей, если нужен супер кастом, то скорее тот же flask-admin или любой другой фреймворке с серверным рендерингом будет скорее мешать чем помогать, с другой стороны админки это на 90% CRUD и не много логики, в условиях админки где в основной массе можно пренебречь красивым визуалом в угоду скорости разработки я бы скорее выбирал фреймворки с серверным рендерингом, так как в них за 20 строк кода и 15 минут можно получить полноценный CRUD и сортировками и фильтрами, сколько такое же пилить через API+JS даже боюсь гадать.
Новые технологии это здорово, но нужно четко понимать зачем тебе в админке websocket к примеру если у тебя форма с 2 полями? В данном случае как мне кажется чем проще тем надежнее и лучше.LordDarklight
18.05.2023 10:55Технология серверного рендеринга уже устарела - но я не говорил, что ей вообще не стоит пользоваться. Да для админок вообще что угодно сгодится
thesun2003
18.05.2023 10:55+1Увы... Расскажите это разработчикам из Meta, которые придумали серверные компоненты React, чтобы писать бэк на реакте. А по сути они переизобрели PHP наоборот.
dzaytsev91
18.05.2023 10:55А в чем устарелость? Не возможность обновить стейт без перезагрузки страницы? Кажется для админки это вообще не важно. Зато весь код на питоне и его реально любой бекендер без проблем поддерживает, максимум нужно понимать как шаблонизатор типа jinja2 работает.
orlovdl
18.05.2023 10:55Если бы ты не написал бóльшую часть наших админок на фласке, я бы наверное поспорил. Но всякие штуки с реактивностью, с частичной валидацией форм, да даже select2 делается не то чтобы очень гибко и просто.
Вебсокет – это не просто транспорт в этом случае, это еще и контекст который привязан к конкретному процессу конкретного инстанса работы пользователя с бекендом. А инстансов той-же админки, минимум 2-3. То есть пока жив конкретный инстанс веб-сокета, сервер может держать в памяти то, что прислал пользователь, без необходимости шарить состояние между всеми инстансами.
Попробуй как-нибудь на досуге, сделать на фласк-админе форму, куда загружаешь CSVшку и нужно перед сохраниением данных из неё дать пользователю, проверить что все поля нормально помапились.
С flask-admin да и любым CRUD тебе придется все-таки сначала сохранить эту csvшку в базу, потом отрендерить пользователю табличку с мапингом, плюс пагинация плюс фильтры, и плюс много всего еще.
С сокетом просто просишь сервер вот этот блоб провалилировать, потом отдельным rpc вызовом, просишь показать первые 10 строк, к примеру, серверу можно хоть в /tmp/ хранить все время до комита в базу этот файл, и просто ходить по нему вперед-назад.
Когда файл 100мегабайт начинает весить, flask-admin начинает по 60 секунд отвечать на это, так как ему нужно на каждый чих перелопачивать 100 мегабайт в базу и обратно.
eigrad
18.05.2023 10:55select2 во flask-admin не делается гибко и просто? да нормально он делается
пока жив конкретный инстанс веб-сокета, сервер может держать в памяти то, что прислал пользователь, без необходимости шарить состояние между всеми инстансами
ничо вы упоролись, код в студию!
orlovdl
18.05.2023 10:55https://wsrpc.readthedocs.io/en/latest/00-quick-start.html
Пока жив сокет, можешь сохранять все что хочешь, ты же будешь в том-же процессе пока не отключишься
eigrad
18.05.2023 10:55-1пока жив конкретный инстанс веб-сокета, сервер может держать в памяти то, что прислал пользователь, без необходимости шарить состояние между всеми инстансами
Не раскрыто совсем. Вот тут смотри аналогичная фигня для телеграм-ботов - https://github.com/ei-grad/telegram-game/blob/master/examples/guess_a_number.py#L34-L61.
Alviner Автор
18.05.2023 10:55Ага, только ты зовешь синхронно блокирующее IO (поход в редис) при изменении атрибута в асинхронном приложении.
upd: принцип взаимодействия в целом похож, только представь что тебе нужно не один вид взаимодействия описывать, а пару (десятков), Это сразу превращается в шаблонный код, который ты тащишь по всему проекту. В нашем случае тебе нужно просто описать handler (фактически содержимое while), да и нам просто регистрировать новые методы с обоих сторон
eigrad
18.05.2023 10:55+1Без redis'а оно тоже работает). А ты предлагаешь на localhost'е в редис асинхронно ходить?
// btw, мне кажется что про асинхронные походы в redis я знаю всё, в свое время было единственной по-настоящему асинхронной либой - https://github.com/ei-grad/toredis/
Alviner Автор
18.05.2023 10:55Ага) ну не люблю я завязываться в коде на положение инфры, придёт завтра дядя Кирил и утащит мой редис в коммунальный, что для админки вполне себе, и тут питон начнет догадываться)
кажется у редиса уже есть asyncio модуль (даже не в тредах)
eigrad
18.05.2023 10:55куда загружаешь CSVшку и нужно перед сохраниением данных из неё дать пользователю, проверить что все поля нормально помапились
сохраняешь в staging bucket, отображаешь чо надо, пользователь коммитит, пол дня работы, да, можно найти более удобный инструмент чем flask-admin, но у него будут свои минусы
Free_ze
18.05.2023 10:55+1просто отдавать уже отрендереную страницу с сервера
До первых ленивых дропдаунов с поиском, потом придется это обмазывать еще более страшным нативным JS.
на C# visual studio позволяет штамповать круды парой кликов мышью.
Если у сущностей есть связи, то голые круды — это боль и унижения.
mayorovp
18.05.2023 10:55Не таким и страшным, на самом деле: библиотека Unobstusive AJAX неплохо справляется с типичными случаями вида "обнови часть страницы по нажатию на кнопку".
Проблемы начинаются когда хочется избавиться от нажатия на кнопку.
orlovdl
18.05.2023 10:55-1а потом как начинаются пляски с частичной вадидацией формы на 40 полей, ты где будешь хранить то, что запомнил пользователь? В query-string? Или на каждую валидацию POST отправлять? В последем случае пользователь расстроится, если случайно нажмет back в браузере.
mayorovp
18.05.2023 10:55Если я случайно нажму "назад" в браузере, скажем, в процессе написания этого комментария — я тоже расстроюсь, но причём тут вообще валидация?
dzaytsev91
18.05.2023 10:55Но ребята писали что до этого там был flask-admin который как раз рендерит html на сервере, но они нашли в этом подходе свои минусы и решили сделать новое решение
orlovdl
18.05.2023 10:55Ребята писали что сделали по своему, ты писал на flask-admin )))
UPD: И не просто сделали, а провели исследование что не стало хуже, порверили экспериментально что пользователям админок стало удобнее, код лучше, проще разрабатывать, и критерий "выкатываем формочку за день" в медиане сходится, и самое главное теперь админки начали писать все, а ты тогда один отдувался за всех.
dzaytsev91
18.05.2023 10:55Я вроде комментарием тоже самое и написал, изначально был вариант серверного рендеринга, нашли минусы и разработали свое решение.
Насчет того что раньше писал кто-то один, а теперь пишут все довольно спорно, разработчиков можно заставить писать на чем угодно, в Я на С++ rest api пишут и ничего. Тут ведь дело вкуса, но кажется разобраться во flask не сильно сложнее чем в aiohttp + vuejs.
Вообще кажется лучший подход это не замыкаться на каком-то одном языке или фреймворке, нет идеальных, это всего лишь инструменты, где-то лучше одно где-то другое.
orlovdl
18.05.2023 10:55Лучше не замыкаться
Вредный совет, если не конкретизировать, тебе нужно подобрать инструменты так, чтобы примерно всем они подходили, и никого ни к чему принуждать не пришлось бы. А так да, молоток хуже отвертки выкручивает шурупы, но зато "закручивает" – сильно быстрее (перформанс оптимизации с помощью молотка)
zesetup
18.05.2023 10:55+2Vaadin, ZK framework самые не страшные способы писать фронт для бэкендера. но это Java.
newpy
18.05.2023 10:55Clojure + ClojureScript + Reagent. Настаиваю что это самая идеальная связка backend + frontend
orlovdl
18.05.2023 10:55Здорово если есть команда котрая уже это все умеет, но увы в нашей истории все начиналось не так.
newpy
18.05.2023 10:55Почему "увы", это ваш опыт и это здорово. Отлично если все получилось и удовлетворяет потребностям. А мой пример, ну, он практический, но из моего опыта и сильно маргинальный )
orlovdl
18.05.2023 10:55+2"Увы", потому, что в вашем настоятельном примере, по моей догадке, скорее описан ваш идеальный мир (если это был не сарказм, и я его не понял, тогда просто читайте "идеальный мир" с кавычками).
У нас в команде есть строгое правило, перед тем как что-то утверждать, не плохо бы это проверить. Мы в целом с тем заходом и "шли к успеху", который описан в посте. Я считаю что инженеру по другому просто нельзя. Если хочешь убедиться в том, что кому-то подойдет та библиотека/технология/фреймворк (нужное подчеркнуть), просто дай её "пощупать" тем кому "с ней потом жить". Будь готов к критике, проведи опыты, напиши докуметацию, которой будет достаточно, чтобы понять почему все задумано и работает именно так.
А самое прикольное что это работает в две стороны, если я что-то предлагать возьмусь, совершенно справедливо получить вопрос: "Дима, а ты как понял что станет лучше?", классно-же. "Пропихнуть" что-то спорное разумеется можно, но придется спорить :-D.
Мы же не дизайнеры, которых просят "сделать красный чуть краснее", мы инженеры, можем все померять, пожем все проверить, провести эксперимент, тесты написать в конце концов, в общем почти нормальный научный процесс.
Можно удариться в карго-культ, и всего этого не делать, а просто прочитать на условном хабре (желательно прямо в этом коменте), что "Все надо переписать на Go/Erlang/Elixir/Python/NodeJS/Typescript/Rust/Zsh" (нужное подчеркнуть), и все станет сразу как в AANGе – тоже подход, но лично по мне, не надежный просто, может станет а может нет.
Так к чему это я, работать в команде это всегда работа с людьми. И тем проще работать, чем люди больше вовлечены, пытаются улучшать те инструменты которыми пользуются, привносят что-то, что поможет всем.
В статье это описано, в первых прототипах админок, был index.html, который надо было врукопашную сортировать, не большая беда, но вот сели и переделали на ESM.
Случилось бы это если бы все были просто "винтики", которых "заставили писать REST-API на С++"? Сомневаюсь. Да и в том что кого-то прям заставляют этим заниматься, тоже.
Можно ли было переделать что-то во flask-admin, тоже наверное можно, но уровень контроля все-же не тот-же самый, по крайней мере мне приятно думать что я все еще имею мою иллюзию контроля.
LordDarklight
Бакэнд-разработчику лучше писать фронт на ЯП, который он знает (и скорее всего пишет бакэнд, но впрочем хороший бакэнд-разоработчик (я не про джунов) скорее всего неплохо знает более одного ЯП, кроме текущего основного).
Безусловно, некоторые пишут бакэнд на JavaScript (под Node.js) или хотя бы на ЯП, транслируемом в JS. И им не сложно будет писать и фронт на JS (хотя с применением фреймворков уже будет сложнее заниматься трансляцией - вот, кстати, жаль этой теме не уделили внимания - но это скорее на отдельную стать потянет).
Транслируемые в JS (и ещё в другие платформы) языки программирования дают хорошие возможности писать на привычном ЯП как под фронтэнд (с трансляцией в JS), так и в бакэнд (с компиляцией в целевую платформу, например, для JVM или в .NET или даже в LVVM и далее в Native-машинный код).
Но сейчас фронтэнд не обязательно писать на JS - или транслировать его.
Например, для Kotlin есть возможность транслировать в JS и компилировать в JVM или LVVM для Native (немного утрирую - т.к. сейчас Kotlin любую выходную продукцию делает через LVVM IR промежуточный язык); жаль только в .NET не умеет.
И для фронтэнда для ЯП Kotlin уже есть и свой персональный фреймворк Compose для веба, десктопа и мобилок (хотя пока он развит только для мобилок).
Под .NET есть всякие Blazor, AvaloniaUI и UNO Platform, (MAUI пока не может в WEB и в Linux).
А вот, с питоном и гоу всё грустнее... ну не адаптированы эти ЯП к фронтэнду - и дело не в ЯП, а в самих библиотеках и фреймворках.
Но.... есть же LLVM компиляция и WebAssembly - это вообще бомба - можно писать фронтэнд под WEB (под другие платформы проблем куда меньше, WASM не нужен) вообще на куче ЯП, даже изначально Native как С/С++ или Go Lang (но Python пока опять в пролёте, но думаю, для него тоже сделают). Но под WASM пока (кроме Blazor, UNO Platfom и AvaloniaUI / Avalonia XPF - но это всё C#) лично мне не известны готовые фреймворки (да и Avalonia тут пока только в ранней альфа версии). Но уверен, со временем подтянутся. Можно и JS фреймворки подрубить - но, помимо снижения производительности, будут сложности интеграции. Но WASM даёт больше возможностей - можно адаптировать Native-десктопные фреймворки и с применением WEBGL будет вообще бомба!
Есть даже тема писать через WASM не только фронтэнд но и бакэнд (посредством WASI) приложения!
Итого, я подвожу к тому - что писать фронтэнд бакэндщику сейчас не так уж обязательно именно на JavaScript - во многих случаях можно и писать и на, условно, бакэндных ЯП или ЯП широкого профиля (как С++, C# или Rust...), хотя тут с применением сторонних фреймворков будет поболее проблем - вот про этот подход было бы интересно увидеть статью.
А что касательно JS и HTML - то тут бакэндеру скорее было бы проще освоить Electron или PWA, позволяющие писать основной код фронтэнда не на JavaScript (но без JS тут не обойтись - скрипты формы всё-равно придётся писать на JS)
Но автору со змеиным бакэндом тут повезло менее всего :-(
orlovdl
Наша цель, была в том, чтобы разработчику, даже если он не знает JS, но знает Python, нужно было посмотреть JS Quick Start, и просто начать на нем решать задачи, а не заниматься вопросами сборки, транспиляцией, и всем тем что вы описали выше. Да и отлаживать такой код куда проще, просто поставил breakpoint в Developer Tools, и остановился там где надо. В случае с любой транспиляцией – это не так просто.
Как и написано в статье, наша цель была в том, чтобы разработчику потратить минимум усилий для начала, и в нашем случае – получилось, просто делаешь git clone, и запускаешь браузер, все.
LordDarklight
Просто не так много пишут бакэнд на чистом Python (без привлечения других ЯП). С более популярными языками для бакэнда более актуально то, что я написал. Но Ваша статья тоже имеет определённую ценность, но на мой взгляд для читателя, с практической стороны, она уж очень общая получилась... больше хвастовства, чем пользы, уж извините
orlovdl
Вот в вашем утверждении "не так много" я сомневаюсь. Мне, лично, кажется что "очень много", если у вас есть какие-то ссылки на исследования, по этой теме, любопытно было-бы почитать.
LordDarklight
Но я и статью не пишу - я лишь комментирую
Простите, если обидел - не хотел
Free_ze
Yew, например. Его прелесть в том, что за счет отсутствия жирного рантайма, размер его бандла сравним с JS/React.
LordDarklight
А ну хорошо, значит процесс пошёл
whoisking
dash, pyscript
orlovdl
Мы тогда на brython смотрели, было... забавно, но совршенно неясно, зачем какая-то надстройка над ES6 который нативно выполняет браузер.
LordDarklight
Весьма любопытный инструмент и даже не упомянули его. А на вид выглядит очень интересно - но по факту - очень примитивно (всё надо писать вручную фронт скрипт прям на Python, фактически никакой помощи визуализации со стороны фреймворка)
LordDarklight
Я не говорил, что у питона нельзя в WEB. Очень примитивные графические фреймворки для UI форм. Но для админки могут и сойти.
eigrad
streamlit, gradio
SozTr
Для питона конечно сложнее, но для гоу можно запилить версию для .net — сразу получит огромную базу библиотек. Хотя конечно потеряет некоторые перимущества :-)
SozTr
Free_ze
OpenSilver мимикрирует под Silverlight.
SozTr
Там всё равно какая-то миграция требуется, но конечно лучше чем ничего.