Разработка или Vibe Coding продолжается 3 день. Я все ещё использую Bolt и смог сделать вполне рабочий сервис. Вручную программисту потребовалось бы около 1-2 недель на такой функционал.
Авторизация
Редактор форм
Просмотр ответов форм с фильтрами
Выгрузка ответов в csv
Шаблоны форм
Загрузка файлов в хранилище
Публикация формы для клиента
Все уже работает и связано с БД
Остальные скрины и ДЕМО версию пришлось опубликовать в телеге т.к. тут лимит на 1 картинку.
BSONError: Invalid UTF-8 string in BSON document
BSONError: bad embedded document length in bson
Документы в базе нормальные. Ошибки появлялись только при включённом Xray с WARP (через встроенный WireGuard). Когда VPN отключён — всё читается корректно.
Поначалу думал, что что-то с кодировкой или драйвером, но оказалось, что проблема в том, что Mongo работала через Cloudflare WARP.
Когда запросов было мало — срабатывало нормально.
Когда запускался алгоритм и начинались частые обращения к базе — Mongo валился с ошибками BSON.
Причина — искажение бинарного трафика при передаче через WARP.
Mongo использует бинарный протокол BSON, и даже один сбитый байт ломает парсинг.
Пофиксил так:
добавил в routing.rules Xray правило, чтобы трафик к Mongo шёл мимо WARP:
внезапно пришла идея - кажется витает в воздухе новый путь установки пакетов и вообще библиотек в приложения.
Начну как всегда из далека: В последнее время, так как вместо человека теперь LLM чаще всего обращается к сайтам и приложениям, становится популярно добавлять специально написанные для llm страницы (как раньше sitemap, только теперь md файлы)
Это даже стало правилом для MCP серверов - например Cline добавляет только те MCP сервера, которые LLM может поставить в one shot или имеют llm-install.md файл.
По сути, кажется это становится файлом установки для llm - то есть, llm, следуя инструкциям этого файла ставит и конфигурирует MCP сервер на компьютере (прям как раньше, люди скачивали и устанавливали на windows).
Уязвимостей тут может быть много (потому что промпт может быть corrupt), но если следить за процессом и обязательно проверять команды исполнения - why not?
А теперь - представляете что можно сделать это для любого пакета и любого языка?
То есть, есть библиотека например для интеграции авторизации. Вместо того, чтобы разворачивать её вручную, автор библиотеки может написать llm-install и агент, имея контекст проекта в котором он работает, может целиком его развернуть!🙌 Креды например строго хранить в отдельном фале, не давать доступ (например использовать cursorignore etc..) и такие пакеты можно интегрировать как клиенту и бекенду!
И тоже самое можно применить и для удаления! И таким образом весь процесс интгерации станет больше как лего plug & play 🤩
В каждой компании, где я работал, были свои правила формализации и постановки обнаруженных багов. Чаще всего - никаких правил. Что нашел тестировщик, то отписал в комментарии к задаче (и это еще хорошо!), а иногда просто на созвоне обсудил с разрабом, тот быстро пофиксил и факт найденного бага остался между ними. Для мелких студий так работать, может, и допустимо, но рано или поздно отсутствие элементарного порядка начинает надоедать. И тут появляются вопросы:
Как оформить баг? Комментарий к задаче? Отдельная задача? Чек-лист в описании задачи?
Как отметить баг выполненным? Проверенным? Повторно проявившимся?
Какая система багтрекинга вам показалась наиболее удобной? Jira? Youtrack? Яндекс.Трекер? Битрикс24? Что-то из новомодного импортозамещения?
Какие шаблоны описания бага приняты в вашей компании? Нет правил? Шаг 1 - шаг 2 - шаг 3 - ожидание - реальность? Скриншот со стрелочками? Видеозапись с экрана?
Есть ли какая-то классификация багов? Минор / мажор? Бэк / фронт? Бэклог / критикал?
Очень интересует ваш опыт в данной теме. Буду очень признателен, если поделитесь своими знаниями в комментариях.
🚀 +32 подписчика в наш телеграм канал, это значит вам понравилась моя статья в рамках челленджа 12 проектов за 12 месяцев, которую я вчера опубликовал.
Несмотря на кадровый голод в IT занято огромное количество лишних людей деятельность которых в общем-то бесполезна. А все что бесполезно как известно приносит только вред. Возьмем к примеру новомодную отрасль UI/UX которая по задумке должна улучшать пользовательский опыт - так называемый "экспириенс". На планете существует целый зоопарк разных форматов дат: 1 ноября 2000, 01.11.2000 и т.д и т.п. Это мелочь, но и в мелочах можно тот самый "экспириенс" взять да и улучшить. И он был повсеместно "улучшен" до формата "3 года назад". Как правило без какой либо возможности вернуть нормальную дату.
Теперь просто хочется простереть руки к небу и крикнуть за что это мне?
Самое печальное в этой ситуации, что исправить ничего нельзя. Этот самый "экспириенс" внедряется крупными корпорациями у которых достаточно ресурса чтобы содержать огромное количество людей не занятых ни какой полезной деятельностью и было бы лучше если бы они вообще ничего не делали. Как в нейросетях лишние веса приносят только вред, так и в индустрии, лишние отрасли приносят пользователям только вред.
Я много и часто просматриваю JSON-файлы: от конфигураций сервисов до API ответов и логов. Каждый раз, открывая очередной файл, я форматирую содержимое, чтобы было удобнее читать (ведь JSON не только machine-readable, но и human-readable). И каждый раз я грущу, что все сервисы (онлайн, встроенные средства IDE и даже плагины) предоставляют лишь две крайности: форматировать всё или ничего (минифицировать в одну строку).
Но что, если я хочу отформатировать JSON лишь до определённого уровня? Что, если у меня есть огромный список словарей (возможно, даже глубоких), который при форматировании выглядит как-то так:
Да, многие текстовые редакторы вроде Sublime Text или VS Code дают возможность свернуть контент до определённого уровня. Но что, если я хочу оставить файл в этом промежуточном виде и просматривать его прямо в терминале, подключившись по ssh? Или я хочу посмотреть файл на гитхабе с телефона? Да, возможно, мои вкусы весьма специфичны, но в существующих реалиях я вынужден грустно довольствоваться лишь полностью развёрнутым вариантом (или делать это вручную). Встроенные средства форматирования JSON в JS или Python также не предоставляют простой возможности ограничить глубину (либо я так и не научился их готовить).
Поэтому я собрался с силами и написал свой форматтер с возможностью ограничить глубину. Помимо базового функционала вроде валидации, минификации и настройки количества отступов, в нём есть настройка максимальной глубины (по умолчанию она равна нулю, что соответствует привычному форматированию без ограничений).
Да, он вряд ли подойдёт, чтобы редактировать на лету гигантские JSON файлы. И он уж точно не пытается стать убийцей какого-либо из существующих онлайн сервисов. В первую очередь он призван решить мою проблему: сделать форматирование JSON чуточку более управляемым. А если и вы сталкивались с подобной проблемой, буду рад, если сервис поможет и вам!
Привет, Хабр! Попробуйте решить задачу. Особенно интересно будет бэкенд-разработчикам, которые работают с микросервисной архитектурой и регулярно сталкиваются с неожиданным поведением инфраструктуры.
Условие
В компании «Доки.Онлайн» выкатили обновление: теперь пользователи могут загружать PDF-файлы с отсканированными договорами. Все работало отлично в локальной среде — разработчик протестировал загрузку больших файлов, убедился, что API обрабатывает их корректно, и спокойно отправил изменения в продакшн.
Но радость была недолгой. На боевом сервере при попытке загрузить файл система выдавала ошибку 413 Request Entity Too Large. Причем происходило это до того, как пользователь получал какой-либо отклик от самого приложения.
Разработчик Геннадий Завров начал искать причину. Он проверил логи всех четырех компонентов системы:
фронтенда;
API Gateway (определяет, в какой микросервис послать запрос);
микросервиса загрузки файлов;
микросервиса обработки документов.
Во всех логах пусто, будто никакого запроса и не было. Ни один сервис даже не попытался начать обработку файла.
Геннадий начал подозревать сетевые сбои, перегрузку API Gateway и баг в коде фронтенда. Однако простые тесты с маленькими файлами работали стабильно. Проблема проявлялась только при загрузке чего-то «потяжелее».
В какой-то момент он задал себе вопрос: а точно ли запрос доходит до приложений?
Задача
Почему при загрузке большого файла система возвращает ошибку 413, если сами сервисы даже не видят входящий запрос? Кто может остановить запрос еще до бэкенда?
Делитесь своим ответом в комментариях. А посмотреть полное решение можно в Академии Selectel.
Мы все с вами привыкли, что в питоне можно "зарайзить" исключение в любой момент: raise Exception Но, что если в какой-то момент времени мы не можем вызывать исключение?
Простейший пример: что произойдет при запуске такого скрипта?
# ex.py
class BrokenDel:
def __del__(self):
raise ValueError('del is broken')
obj = BrokenDel()
del obj
print('done!') # будет ли выведено?
Тут может быть два варианта:
Или del вызовет ValueError и программа завершится
Или случится какая-то магия, ошибка будет вызвана, напечатается, но программа продолжится
» python ex.py
Exception ignored while calling deallocator :
Traceback (most recent call last): File "/Users/sobolev/Desktop/cpython/ex.py", line 3, in __del__ raise ValueError('del is broken')
ValueError: del is broken
done!
Знакомьтесь – unraisable exceptions 🤝
Как оно работает?
В некоторых местах C кода у нас есть необходимость вызывать исключения, но нет технической возможности. Пример, как выглядит упрощенный dealloc для list?
static void
list_dealloc(PyListObject *op)
{
Py_ssize_t i;
PyObject_GC_UnTrack(op); // убираем объект из отслеживания gc
if (op->ob_item != NULL) {
i = Py_SIZE(op);
while (--i >= 0) {
// уменьшаем счетчик ссылок каждого объекта в списке
Py_XDECREF(op->ob_item[i]);
}
op->ob_item = NULL;
}
PyObject_GC_Del(op);
}
А, как вы можете знать, чтобы в C коде вызвать ошибку, нужно сделать две вещи:
Взывать специальное АПИ вроде PyErr_SetString(PyExc_ValueError, "some text")
И вернуть NULL как PyObject * из соответствующих АПИ, показывая, что у нас ошибка. Если вернуть NULL нельзя, то мы не можем поставить ошибку в текущий стейт интерпертатора. А тут у нас void и вернуть вообще ничего нельзя. Потому приходится использовать вот такой подход с unraisable exception
Они создают ошибку, но не выкидывают её обычным способом, а сразу отправляют в специальный хук-обработчик. Данный хук не производит классическое "выбрасывание" исключения, а просто его печатает по-умолчанию. Ниже посмотрим, как его можно кастомизировать.
В питоне оно используется где-то 150 раз. То есть – прям часто. Примеры:
Ошибки при завершении интерпретатора, попробуйте сами:
🚀 291 установка за месяц. Как мы запустили браузерное расширение «Rar File Opener»
Расскажу про создание нового продукта — расширения для открытия RAR-архивов прямо в браузере. Простое решение проблемы, когда средствами ОС RAR не открыть.
2️⃣ Проверили запросы в Google и Chrome Store. Люди ищут способы извлечения RAR архивов по запросам "rar extractor", "rar file opener" и т.д. Конкуренция в Chrome Store при этом низкая.
3️⃣ Разработали простое расширение, которое:
- Открывает RAR прямо в браузере (а также ZIP, 7z, TAR, GZ, TAR.GZ и другие форматы)
- Не крадёт данные (работает локально)
- Работает с несколькими архивами
У нас процесс уже отлажен:
✅ Разработали MVP
✅ Сделали иконки, промо картинки и лендинг
✅ Сделали SEO-описание + перевод на 55 языков
✅ Тесты и фикс багов
На все 3-4 недели.
Копаем ил дальше в поисках идеи нового продукта! 😁
Свой класс события для плагинов Joomla. Продолжение.
Продолжение потому, что начало уже было в статье Виталия Некрасова на Хабре.
Кратко.
В Joomla 5+ для событий аргументы упаковываются в собственные классы событий: ContentPrepareEvent, AfterSaveEvent и т.д. Данные из них мы получаем в виде $event->getArgument('argument_name') или [$var, $var2] = array_values($event->getArguments());. Также для разных типов событий могут быть специфичные методы типа $article = $event->getItem(); в ContentPrepareEvent и т.д. И в статье Виталия как раз об этом рассказывается.
А так же рассказывается о методах onGet и onSet. В ядре Joomla в классе \Joomla\CMS\Event\AbstractEvent сказано:
/**
* Add argument to event.
* It will use a pre-processing method if one exists. The method has the signature:
*
* onSet($value): mixed
*
* where:
*
* $value is the value being set by the user
* It returns the value to return to set in the $arguments array of the event.
*
* @param string $name Argument name.
* @param mixed $value Value.
*
* @return $this
*
* @since 4.0.0
*/
Добрался я тоже до своего класса события для плагинов, порылся в ядре и подумал, что onSet... и onGet... методы не обязательно делать (хотя в статье по ссылке об этом не упоминается). Это методы для "предварительных проверок и манипуляций" с данными перед тем, как они будут отданы через getArgument() или get<ArgumentName>. Метод getData() отдаст данные, которые предварительно будут обработаны методом onGetData(). Но обработаны они будут только в том случае, если метод реализован. Если нет, то ничего страшного. Ошибки не будет.😎
Эти методы напоминают своеобразные плагины внутри плагинов. На мой взгляд излишнее усложнение, хотя сеттеры и геттеры должны заниматься по идее только сеттерством и геттерством, а проверку/ приведение типов можно отдать в методы onSet... / onGet....
Новый тайпчекер для Python от авторов ruff и uv, написанный на Rust
Вышло видео про новый тайпчекер и lsp: ty (старое название red-knot) от авторов ruff и uv. Пока по первым впечатлениям – бомба! Не смотря на версию 0.0.0a8 🌚
Из плюсов:
Быстрый
На расте
Куча новых фичей для типов
Полная спецификация
Интеграция с ruff и IDEшками
Из минусов:
Пока есть баги (но их поправят, конечно же)
Нет плагинов (и скорее всего никогда не будет)
Софт от молодой и маленькой компании
Как сделать поддержку ty и mypy вместе? А если использовались ty_extensions?
Последнее время замечаю тенденцию, что многие хостинги и публичные облака вводят платную поддержку.
Позиционируется поддержка как дополнительная опция и гарантия времени ответа. Но на мой взгляд это выглядит как вымогательство денег, когда компания может оказывать качественную поддержку, но если вы их не “подкупите” дополнительно, не будет.
Я основатель облака для простого деплоя проектов через Git push – Amvera Cloud. И вижу, что пользователи пишут нам в поддержку. И говоря честно – люди пишут только тогда, когда другие способы не помогли и они не знают, как решить их насущную проблему. А это значит мы не доработали и сделали что-то непонятно или неудобно. И это наша обязанность постараться им помочь. И я не вижу морального права просить за это с них деньги.
Поддержка может работать не идеально, можно даже разделять клиентов во время высокой нагрузки на постоянных или новых, с высоким или низким чеком или любым другим образом, чтобы кому-то помочь в первую очередь. Но помочь нужно всем.
И главное, я не верю, что на платной поддержке можно сильно заработать. Это просто предлог, чтобы работать хуже, чем может компания.
Поддержка должна быть бесплатной, всегда, и без всяких но!
Недавно ревьюил один интересный PR в CPython: в питон добавили еще один способ форматировать строки. Теперь – со специальным АПИ для внешних интеграций. Расскажу: как и зачем.
Основная причина: использовать f строки удобно, но нет никакого АПИ для перехвата момента "вставки" или интерполяции значений. Например, при форматировании html или sql – требуется специальным образом делать escape для значений. И раньше код вида f"{template}" представлял собой дыру в безопасности и потенциальное место для XSS.
string.templatelib.Template
Новый префикс t не будет создавать объект str, он будет создавать объект класса string.templatelib.Template:
Обратите внимание, что при создании template – у нас не произошло форматирование сразу. Мы создали объект, у которого есть свойства strings и interpolations, из которых можно собрать финальную отформатированную строку.
Давайте посмотрим на примере. Допустим, мы хотим формировать URL из наших данных:
>>> domain = 'example.com'
>>> query = 'python string formatting is too complex'
>>> template = t'https://{domain}?q={query}'
И сам код логики форматирования, где мы будем вставлять значения разным способом. Если у нас шаблон query, то мы будем использовать quote_plus для его форматирования. Остальные значения – будем вставлять как есть:
>>> from string.templatelib import Template, Interpolation
>>> from urllib.parse import quote_plus
>>> def format_url(template: Template) -> str:
... parts = []
... for part in template:
... match part:
... case str() as s: # regular string
... parts.append(s)
... case Interpolation(value, expression='query'):
... parts.append(quote_plus(value))
... case Interpolation(value):
... parts.append(value)
... return ''.join(parts)
Сегодня я расскажу вам о нашем небольшом, но очень ценном управленческом инструменте — мы называем его «техлид продукта». Если вы как-то связаны с созданием цифровых продуктов и заинтересованы в том, чтобы они хорошо работали, вам наверняка пригодится этот подход. Он особенно актуален, когда человеческие ресурсы по каким-то причинам ограничены.
Большинство инженеров любят быть героями. Я — люблю. Представьте себе хайлоад-продукт: куча пользователей, запросов, деньги летят миллионами. Система сложная, размазанная по разным серверам, а, пожалуй, даже по разным дата-центрам. В общем, всё мчится и бибикает. Но вдруг где-то откручивается гайка, труба отпадает, из неё бьёт пар. Экраны мониторов в командной рубке заливаются красным, женский голос повторяет: «Тревога! Прод лежит». Картина маслом.
Вы видите, насколько все серьезно и, не раздумывая, вступаете в неравную схватку с проблемой. Вскоре вы разносите полгорода, находите и перерезаете красный провод. Мир спасен в самую последнюю секунду. Все женщины ваши, мужчины хотят быть как вы. Для вас это чувство — наркотик, и, как любой другой наркотик, он может разрушить вашу управленческую жизнь. Почему?
Потому что вы становитесь не-за-ме-нимы. Представьте себе ситуацию в Готэм-сити, когда Бэтмен уехал в отпуск посерфить на Шри Ланке.
Незаменимых быть не должно. Для решения этой проблемы мы во Флаге придумали дополнительную роль, которая позволяет надевать костюм Бэтмена любому разработчику, начиная с грейда мидл. Мы присвоили этой роли список обязанностей, определили премии, закрепили во внутренних системах.
Обязанности роли «техлид продукта»:
1️⃣ Ответственность за работоспособность продакшена и стейджинга (боевой контур и финальный контур тестирования). Причем, именно работоспособность: создаёт и изменяет эти контуры другая роль.
2️⃣ Управление процессом устранения аварий: координация как внутренних, так и внешних специалистов, информирование заинтересованных лиц о статусе устранения аварии.
3️⃣ Ответственность за анализ аварий: ведение Post Mortem (отчётов об авариях), разбор аварий с командой, постановка организационных и технических задач для предотвращения аварий по итогам анализа.
4️⃣ Ответственность за ключевые технические решения на проекте: библиотеки и фреймворки, архитектура и подходы к разработке.
5️⃣ Ответственность за актуальность документации по разворачиванию сервисов локально у разработчиков.
6️⃣ Ответственность за создание и поддержку тестовых контуров.
7️⃣ Ответственность за актуальность документации по контрактам взаимодействия модулей системы.
🎱 Контроль технического долга на продукте.
9️⃣ Ответственность за информационную безопасность продукта: принятие решений по уровню доступа к системе для участников команды и третьих лиц, актуальность версий ПО и другое.
Для Флага всё это уже давно не теория, а рутина где-то с лета 2023 года. Роль техлида «склеивает» множество узких специализаций, таких как DevOps, Backend, Frontend, Mobile, PM и SA. Сейчас я спокоен, потому что знаю: аварии устраняются быстро, выводы делаются, наши продукты и процессы становятся надёжнее с каждым факапом. Да, факапы всё равно происходят, никуда от них не денешься. Зато узнаю я об этом из отчётов, а не из ночных смс и звонков.
Опубликовано исследование о том что индексирование сайтов поисковиком (Google) не зависит от того, SPA ли это или же он SSR. Также пару лет назад делал аналогичное расследование и пришел к тому же выводу.
Вообще, мы пришли к идеалу достаточно давно - когда сервер занимается своими делами, а клиент статический, минифицирован, и раздается из CDN для быстроты и без траты ресурсов сервера.
ИИ-ассистенты (промпты) - это тоже low-code. Бизнес-аналитики сами разрабатывают ИТ-продукты. Сайт какой сложности можно разработать без знания JavaScript? Кейс app.2lead.ru
Возможности low-code растут. Бизнес-аналитики сами разрабатывают ИТ-продукты, фактически добавляя к своим обязанностям часть функций программистов. При этом эксперты не прогнозируют, что low-code полностью заменит традиционное программирование в ближайшие годы.
ИИ-помощники (промпты) - это тоже low-code
Чаще всего low-code определяют как создание ПО с помощью графических интерфейсов и настроек, а не через традиционное программирование. Мне ближе более широкое определение: low-code – это системы и платформы, которые предполагают изменение, дополнение кода пользователем, в том числе с применением ИИ-помощников (промптов).
ИИ-ассистенты значительно ускорили разработку сервисов app.2lead.ru, созданных мной на JavaScript - без опыта программирования на этом языке. Это подтверждает возможность разработки ПО силами бизнес-аналитиков, продуктовых менеджеров и так далее. Ранее это была прерогатива только профессиональных программистов.
Сервисы app.2lead.ru разработаны в конце 2024 года – начале 2025 года. Вошли в топ-5 Яндекса по запросу «калькулятор инфляции». Уже увеличили органический трафик сайта 2lead.ruболее чемв 5 раз, без расходов на рекламу. // См. также «Нерекламные методы продвижения» https://habr.com/ru/articles/686736/
Что дальше? Массовое применение таких методов разработки ПО, более совершенные low-code системы и программирование голосом? Считаю, что практику low-code нужно расширять, разрабатывать учебные материалы по этому направлению и т.д. В этих инструментах есть большое пространство для развития.