Как стать автором
Обновить
323.29

Веб-разработка *

Делаем веб лучше

Сначала показывать
Порог рейтинга

Мега Bolt или как неройнка заменяет кучу разрабов

Разработка или Vibe Coding продолжается 3 день. Я все ещё использую Bolt и смог сделать вполне рабочий сервис. Вручную программисту потребовалось бы около 1-2 недель на такой функционал.

  • Авторизация

  • Редактор форм

  • Просмотр ответов форм с фильтрами

  • Выгрузка ответов в csv

  • Шаблоны форм

  • Загрузка файлов в хранилище

  • Публикация формы для клиента

Все уже работает и связано с БД

Остальные скрины и ДЕМО версию пришлось опубликовать в телеге т.к. тут лимит на 1 картинку.

Теги:
-1
Комментарии4

Я попробовал Bolt. Мои первые шаги в Вайб-кодинге.

На связи Антон 👨‍💻

Мы выбрали идею нового продукта - Form builder. Простой и минималистичный конструктор форм на замену Google Forms.

Для разработки я пробую сервис Bolt.new. Я пишу в промтах ТЗ, нейросеть генерит код за меня.

За 5 запросов я получил функционал, который писал бы пару дней. Конечно с кучей багов и недоработок. Они и в ручной разработке тоже бывают.

Сейчас прошу Bolt поправить свои же баги и сделать правильную анимацию при перетаскивании элементов формы. Посмотрим, что из этого выйдет.

А у вас какой опыт с вайб-кодингом? Писать про наш опыт с нейросетями в разработке?

Теги:
+1
Комментарии8

MongoDB + WARP + Xray = 💥 BSONError

У меня MongoDB начала выдавать ошибки:

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:

{

  "type": "field",

  "ip": ["<IP MongoDB>"],

  "outboundTag": "direct"

}
Теги:
+11
Комментарии1

внезапно пришла идея - кажется витает в воздухе новый путь установки пакетов и вообще библиотек в приложения.

Начну как всегда из далека:
В последнее время, так как вместо человека теперь 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 🤩

Game changer?:)

Теги:
+1
Комментарии0

Как вы оформляете баги?

В каждой компании, где я работал, были свои правила формализации и постановки обнаруженных багов. Чаще всего - никаких правил. Что нашел тестировщик, то отписал в комментарии к задаче (и это еще хорошо!), а иногда просто на созвоне обсудил с разрабом, тот быстро пофиксил и факт найденного бага остался между ними. Для мелких студий так работать, может, и допустимо, но рано или поздно отсутствие элементарного порядка начинает надоедать. И тут появляются вопросы:

  1. Как оформить баг? Комментарий к задаче? Отдельная задача? Чек-лист в описании задачи?

  2. Как отметить баг выполненным? Проверенным? Повторно проявившимся?

  3. Какая система багтрекинга вам показалась наиболее удобной? Jira? Youtrack? Яндекс.Трекер? Битрикс24? Что-то из новомодного импортозамещения?

  4. Какие шаблоны описания бага приняты в вашей компании? Нет правил? Шаг 1 - шаг 2 - шаг 3 - ожидание - реальность? Скриншот со стрелочками? Видеозапись с экрана?

  5. Есть ли какая-то классификация багов? Минор / мажор? Бэк / фронт? Бэклог / критикал?

Очень интересует ваш опыт в данной теме. Буду очень признателен, если поделитесь своими знаниями в комментариях.

Теги:
0
Комментарии0

Спасибо друзья!

🚀 +32 подписчика в наш телеграм канал, это значит вам понравилась моя статья в рамках челленджа 12 проектов за 12 месяцев, которую я вчера опубликовал.

Кто еще не видел - оцените

Теги:
0
Комментарии0

Несмотря на кадровый голод в IT занято огромное количество лишних людей деятельность которых в общем-то бесполезна. А все что бесполезно как известно приносит только вред. Возьмем к примеру новомодную отрасль UI/UX которая по задумке должна улучшать пользовательский опыт - так называемый "экспириенс". На планете существует целый зоопарк разных форматов дат: 1 ноября 2000, 01.11.2000 и т.д и т.п. Это мелочь, но и в мелочах можно тот самый "экспириенс" взять да и улучшить. И он был повсеместно "улучшен" до формата "3 года назад". Как правило без какой либо возможности вернуть нормальную дату.

Теперь просто хочется простереть руки к небу и крикнуть за что это мне?

Самое печальное в этой ситуации, что исправить ничего нельзя. Этот самый "экспириенс" внедряется крупными корпорациями у которых достаточно ресурса чтобы содержать огромное количество людей не занятых ни какой полезной деятельностью и было бы лучше если бы они вообще ничего не делали. Как в нейросетях лишние веса приносят только вред, так и в индустрии, лишние отрасли приносят пользователям только вред.

Теги:
+5
Комментарии10

Я устал от форматирования JSON файлов

Я много и часто просматриваю JSON-файлы: от конфигураций сервисов до API ответов и логов. Каждый раз, открывая очередной файл, я форматирую содержимое, чтобы было удобнее читать (ведь JSON не только machine-readable, но и human-readable). И каждый раз я грущу, что все сервисы (онлайн, встроенные средства IDE и даже плагины) предоставляют лишь две крайности: форматировать всё или ничего (минифицировать в одну строку).

Но что, если я хочу отформатировать JSON лишь до определённого уровня? Что, если у меня есть огромный список словарей (возможно, даже глубоких), который при форматировании выглядит как-то так:

[
    {
        "id": 1,
        "name": "Alice",
        "birthday": {
            "day": 5,
            "month": 4,
            "year": 1983
        }
    },
    {
        "id": 2,
        "name": "Bob",
        "birthday": {
            "day": 6,
            "month": 2,
            "year": 1945
        }
    },
    {
        "id": 3,
        "name": "Eve",
        "birthday": {
            "day": 10,
            "month": 11,
            "year": 1978
        }
    }
]

Что, если я хочу оставить каждый словарь в более компактном (не совсем минифицированном) виде? Например, таком:

[
    {"id": 1, "name": "Alice", "birthday": {"day": 5, "month": 4, "year": 1983}},
    {"id": 2, "name": "Bob", "birthday": {"day": 6, "month": 2, "year": 1945}},
    {"id": 3, "name": "Eve", "birthday": {"day": 10, "month": 11, "year": 1978}}
]

Или я хочу, чтобы в каждом словаре развёрнуты были только внешние ключи?

[
    {
        "id": 1,
        "name": "Alice",
        "birthday": {"day": 5, "month": 4, "year": 1983}
    },
    {
        "id": 2,
        "name": "Bob",
        "birthday": {"day": 6, "month": 2, "year": 1945}
    },
    {
        "id": 3,
        "name": "Eve",
        "birthday": {"day": 10, "month": 11, "year": 1978}
    }
]

Да, многие текстовые редакторы вроде Sublime Text или VS Code дают возможность свернуть контент до определённого уровня. Но что, если я хочу оставить файл в этом промежуточном виде и просматривать его прямо в терминале, подключившись по ssh? Или я хочу посмотреть файл на гитхабе с телефона? Да, возможно, мои вкусы весьма специфичны, но в существующих реалиях я вынужден грустно довольствоваться лишь полностью развёрнутым вариантом (или делать это вручную). Встроенные средства форматирования JSON в JS или Python также не предоставляют простой возможности ограничить глубину (либо я так и не научился их готовить).

Поэтому я собрался с силами и написал свой форматтер с возможностью ограничить глубину. Помимо базового функционала вроде валидации, минификации и настройки количества отступов, в нём есть настройка максимальной глубины (по умолчанию она равна нулю, что соответствует привычному форматированию без ограничений).

Да, он вряд ли подойдёт, чтобы редактировать на лету гигантские JSON файлы. И он уж точно не пытается стать убийцей какого-либо из существующих онлайн сервисов. В первую очередь он призван решить мою проблему: сделать форматирование JSON чуточку более управляемым. А если и вы сталкивались с подобной проблемой, буду рад, если сервис поможет и вам!

Теги:
+7
Комментарии0

Задача о габаритном файле и ошибке

Привет, Хабр! Попробуйте решить задачу. Особенно интересно будет бэкенд-разработчикам, которые работают с микросервисной архитектурой и регулярно сталкиваются с неожиданным поведением инфраструктуры.

Условие

В компании «Доки.Онлайн» выкатили обновление: теперь пользователи могут загружать PDF-файлы с отсканированными договорами. Все работало отлично в локальной среде — разработчик протестировал загрузку больших файлов, убедился, что API обрабатывает их корректно, и спокойно отправил изменения в продакшн.

Но радость была недолгой. На боевом сервере при попытке загрузить файл система выдавала ошибку 413 Request Entity Too Large. Причем происходило это до того, как пользователь получал какой-либо отклик от самого приложения.

Разработчик Геннадий Завров начал искать причину. Он проверил логи всех четырех компонентов системы:

  • фронтенда;

  • API Gateway (определяет, в какой микросервис послать запрос);

  • микросервиса загрузки файлов;

  • микросервиса обработки документов.

Во всех логах пусто, будто никакого запроса и не было. Ни один сервис даже не попытался начать обработку файла.

Геннадий начал подозревать сетевые сбои, перегрузку API Gateway и баг в коде фронтенда. Однако простые тесты с маленькими файлами работали стабильно. Проблема проявлялась только при загрузке чего-то «потяжелее».

В какой-то момент он задал себе вопрос: а точно ли запрос доходит до приложений?

Задача

Почему при загрузке большого файла система возвращает ошибку 413, если сами сервисы даже не видят входящий запрос? Кто может остановить запрос еще до бэкенда?

Делитесь своим ответом в комментариях. А посмотреть полное решение можно в Академии Selectel.

Теги:
+4
Комментарии3

unraisable exceptions в питоне

Мы все с вами привыкли, что в питоне можно "зарайзить" исключение в любой момент: raise Exception
Но, что если в какой-то момент времени мы не можем вызывать исключение?

Простейший пример: что произойдет при запуске такого скрипта?

# ex.py
class BrokenDel:
    def __del__(self):
        raise ValueError('del is broken')

obj = BrokenDel()
del obj
print('done!')  # будет ли выведено?

Тут может быть два варианта:

  1. Или del вызовет ValueError и программа завершится

  2. Или случится какая-то магия, ошибка будет вызвана, напечатается, но программа продолжится

Ну и так как мы с вами на том канале, где мы с вами, то конечно же будет второй вариант.

» 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 раз. То есть – прям часто. Примеры:

  • Ошибки при завершении интерпретатора, попробуйте сами:

import atexit
def foo():
    raise Exception('foo')
atexit.register(foo)
  • Ошибки внутри sys.excepthook

  • Ошибки внутри gc

  • Ошибки внутри логики установки ошибок (вдруг память кончилась, например) 🌚️️️️

  • И многое другое

Пользовательское АПИ

Ну и конечно же, есть специальный хук для обработки таких ошибок: sys.unraisablehook

Он может выполнять любой пользовательский код, который мы установим при старте приложения.

Например, pytest использует кастомный хук, чтобы валить тесты при возникновении такой ситуации. Что логично.

Нравится контент про технику и устройство технологий? Присоединяйся к каналу @opensource_findings в телеге; там много такого.

Обсуждение: знали ли вы про такую особенность? Приходилось ли где-то в мониторинге особо настраивать?

Теги:
+10
Комментарии1

Google выпустила свой бесплатный генератор сайтов и приложений Stitch:

  • генерит простые, но стильные дизайны; 

  • под капотом мощнейшая модель Gemini; 

  • экспорт в Figma буквально парой кликой 

  • есть специальная фича Copy to Figma; 

  • любой элемент можно отредактировать.

Теги:
0
Комментарии1

🚀 291 установка за месяц. Как мы запустили браузерное расширение «Rar File Opener»

Расскажу про создание нового продукта — расширения для открытия RAR-архивов прямо в браузере. Простое решение проблемы, когда средствами ОС RAR не открыть.

Результаты за 30 дней:

- 291 установка

- 185 активных пользователей

Все это без каких-либо вложений в маркетинг.

Как мы это сделали?

1️⃣ Нашли идею в https://chrome-stats.com.

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 недели.

Копаем ил дальше в поисках идеи нового продукта! 😁

Инди-хакеры: стартапы из 💩 и 🥢 - канал про то, как два простых IT-шника запускают стартапы без инвестиций и смузи.

Теги:
+1
Комментарии0

Свой класс события для плагинов 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....

Теги:
+2
Комментарии0

Ближайшие события

Новый тайпчекер для Python от авторов ruff и uv, написанный на Rust

Вышло видео про новый тайпчекер и lsp: ty (старое название red-knot) от авторов ruff и uv. Пока по первым впечатлениям – бомба! Не смотря на версию 0.0.0a8 🌚

Из плюсов:

  • Быстрый

  • На расте

  • Куча новых фичей для типов

  • Полная спецификация

  • Интеграция с ruff и IDEшками

Из минусов:

  • Пока есть баги (но их поправят, конечно же)

  • Нет плагинов (и скорее всего никогда не будет)

  • Софт от молодой и маленькой компании

  • Как сделать поддержку ty и mypy вместе? А если использовались ty_extensions?

Обсуждение: а как вам проект? Успели попробовать?

Теги:
+10
Комментарии1

Поддержка должна быть бесплатной. Всегда!

Последнее время замечаю тенденцию, что многие хостинги и публичные облака вводят платную поддержку. 

Позиционируется поддержка как дополнительная опция и гарантия времени ответа. Но на мой взгляд это выглядит как вымогательство денег, когда компания может оказывать качественную поддержку, но если вы их не “подкупите” дополнительно, не будет.

Я основатель облака для простого деплоя проектов через Git push – Amvera Cloud. И вижу, что пользователи пишут нам в поддержку. И говоря честно – люди пишут только тогда, когда другие способы не помогли и они не знают, как решить их насущную проблему. А это значит мы не доработали и сделали что-то непонятно или неудобно. И это наша обязанность постараться им помочь. И я не вижу морального права просить за это с них деньги.

Поддержка может работать не идеально, можно даже разделять клиентов во время высокой нагрузки на постоянных или новых, с высоким или низким чеком или любым другим образом, чтобы кому-то помочь в первую очередь. Но помочь нужно всем.

И главное, я не верю, что на платной поддержке можно сильно заработать. Это просто предлог, чтобы работать хуже, чем может компания.

Поддержка должна быть бесплатной, всегда, и без всяких но! 

Теги:
Всего голосов 8: ↑7 и ↓1+6
Комментарии3

PEP 750: t-строки в 3.14

Недавно ревьюил один интересный PR в CPython: в питон добавили еще один способ форматировать строки. Теперь – со специальным АПИ для внешних интеграций. Расскажу: как и зачем.

Основная причина: использовать f строки удобно, но нет никакого АПИ для перехвата момента "вставки" или интерполяции значений. Например, при форматировании html или sql – требуется специальным образом делать escape для значений. И раньше код вида f"{template}" представлял собой дыру в безопасности и потенциальное место для XSS.

string.templatelib.Template

Новый префикс t не будет создавать объект str, он будет создавать объект класса string.templatelib.Template:

>>> user = 'sobolevn'
>>> template = t"Hi, {user}"
>>> template
Template(strings=('Hi, ', ''), interpolations=(Interpolation('sobolevn', 'user', None, ''),))

>>> from string.templatelib import Template
>>> isinstance(template, Template)
True

Обратите внимание, что при создании 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) -&gt; 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)

И вот результат:

>>> format_url(template)
'https://example.com?q=python+string+formatting+is+too+complex'

Только теперь наш Template был отформатирован. Нами. Ручками.
У нас есть полный контроль за процессом форматирования. Вот в чем суть данного ПЕПа.

Фичи одной строкой

  • Работает = как обычно в f строках: t'{user=}'

  • Есть привычные определители формата: !r, !s, .2f, тд

  • t строки можно конкатенировать: t'Hello' + t' , world!' и t'Hello, ' + 'world'

  • Поддерживается режим raw строк: rt"Hi \n!"

Как устроено внутри?

Интересные места имплементации:

>>> import dis
>>> user = 'sobolevn'
>>> dis.dis('t"Hi, {user}"')
  0           RESUME                   0

  1           LOAD_CONST               2 (('Hi, ', ''))
              LOAD_NAME                0 (user)
              LOAD_CONST               1 ('user')
              BUILD_INTERPOLATION      2
              BUILD_TUPLE              1
              BUILD_TEMPLATE
              RETURN_VALUE

Обсуждение: как вам еще один способ форматирования строк?

Если понравилось – заходи в тг, где я рассказываю, как я делаю CPython.

Теги:
Всего голосов 10: ↑10 и ↓0+13
Комментарии7

Сегодня второй день, как перенесли главное бизнес-медиа Казахстана на новый back-end.

Когда у тебя новостное медиа и 3000 уникальных пользователей в час, то переезд на новые рельсы с редизайном — это как ехать на машине 120 км/ч и пытаться поменять колёса.

Неделя стресса и бессонные ночи с командой — и второй день: полёт нормальный.

Это уже третье крупное медиа, которое мы делаем, и очень хочется подготовить материал о том, что такое медиа с точки зрения технической реализации. Но это уже в мае.

У меня родилась идея, сделать единый SaaS, который закроет все тех моменты по SEO для контентных проектов.

Проверка правильности фидов, сайтмепа, роботс, метаданные, снипеты, редиректы и еще сотни крайних сценариев. Сейчас отдохнуть немного и напишу материал и может даже сделаем свой SaaS для таких задач.

Теги:
Всего голосов 2: ↑1 и ↓1+2
Комментарии0

Может ли Бэтмен взять отпуск

Сегодня я расскажу вам о нашем небольшом, но очень ценном управленческом инструменте — мы называем его «техлид продукта». Если вы как-то связаны с созданием цифровых продуктов и заинтересованы в том, чтобы они хорошо работали, вам наверняка пригодится этот подход. Он особенно актуален, когда человеческие ресурсы по каким-то причинам ограничены.

Большинство инженеров любят быть героями. Я — люблю. Представьте себе хайлоад-продукт: куча пользователей, запросов, деньги летят миллионами. Система сложная, размазанная по разным серверам, а, пожалуй, даже по разным дата-центрам. В общем, всё мчится и бибикает. Но вдруг где-то откручивается гайка, труба отпадает, из неё бьёт пар. Экраны мониторов в командной рубке заливаются красным, женский голос повторяет: «Тревога! Прод лежит». Картина маслом.

Вы видите, насколько все серьезно и, не раздумывая, вступаете в неравную схватку с проблемой.  Вскоре вы разносите полгорода, находите и перерезаете красный провод. Мир спасен в самую последнюю секунду. Все женщины ваши, мужчины хотят быть как вы. Для вас это чувство — наркотик, и, как любой другой наркотик, он может разрушить вашу управленческую жизнь. Почему?

Потому что вы становитесь не-за-ме-нимы. Представьте себе ситуацию в Готэм-сити, когда Бэтмен уехал в отпуск посерфить на Шри Ланке.

Незаменимых быть не должно. Для решения этой проблемы мы во Флаге придумали дополнительную роль, которая позволяет надевать костюм Бэтмена любому разработчику, начиная с грейда мидл. Мы присвоили этой роли список обязанностей, определили премии, закрепили во внутренних системах.

Обязанности роли «техлид продукта»:

 1️⃣ Ответственность за работоспособность продакшена и стейджинга (боевой контур и финальный контур тестирования). Причем, именно работоспособность: создаёт и изменяет эти контуры другая роль.

 2️⃣ Управление процессом устранения аварий: координация как внутренних, так и внешних специалистов, информирование заинтересованных лиц о статусе устранения аварии.

 3️⃣ Ответственность за анализ аварий: ведение Post Mortem (отчётов об авариях), разбор аварий с командой, постановка организационных и технических задач для предотвращения аварий по итогам анализа.

 4️⃣ Ответственность за ключевые технические решения на проекте: библиотеки и фреймворки, архитектура и подходы к разработке.

 5️⃣ Ответственность за актуальность документации по разворачиванию сервисов локально у разработчиков. 

 6️⃣ Ответственность за создание и поддержку тестовых контуров.

 7️⃣ Ответственность за актуальность документации по контрактам взаимодействия модулей системы.

 🎱 Контроль технического долга на продукте.

 9️⃣ Ответственность за информационную безопасность продукта: принятие решений по уровню доступа к системе для участников команды и третьих лиц, актуальность версий ПО и другое.

Для Флага всё это уже давно не теория, а рутина где-то с лета 2023 года. Роль техлида «склеивает» множество узких специализаций, таких как DevOps, Backend, Frontend, Mobile, PM и SA. Сейчас я спокоен, потому что знаю: аварии устраняются быстро, выводы делаются, наши продукты и процессы становятся надёжнее с каждым факапом. Да, факапы всё равно происходят, никуда от них не денешься. Зато узнаю я об этом из отчётов, а не из ночных смс и звонков.

Теги:
Рейтинг0
Комментарии0

Опубликовано исследование о том что индексирование сайтов поисковиком (Google) не зависит от того, SPA ли это или же он SSR. Также пару лет назад делал аналогичное расследование и пришел к тому же выводу.

Вообще, мы пришли к идеалу достаточно давно - когда сервер занимается своими делами, а клиент статический, минифицирован, и раздается из CDN для быстроты и без траты ресурсов сервера.

https://vercel.com/blog/how-google-handles-javascript-throughout-the-indexing-process

Теги:
Всего голосов 2: ↑2 и ↓0+2
Комментарии9

ИИ-ассистенты (промпты) - это тоже low-code. Бизнес-аналитики сами разрабатывают ИТ-продукты. Сайт какой сложности можно разработать без знания JavaScript? Кейс app.2lead.ru

Возможности low-code растут. Бизнес-аналитики сами разрабатывают ИТ-продукты, фактически добавляя к своим обязанностям часть функций программистов. При этом эксперты не прогнозируют, что low-code полностью заменит традиционное программирование в ближайшие годы.

ИИ-помощники (промпты) - это тоже low-code

Чаще всего low-code определяют как создание ПО с помощью графических интерфейсов и настроек, а не через традиционное программирование. Мне ближе более широкое определение: low-code – это системы и платформы, которые предполагают изменение, дополнение кода пользователем, в том числе с применением ИИ-помощников (промптов).

Кейс: Сервисы app.2lead.ru разработаны бизнес-аналитиком

ИИ-ассистенты значительно ускорили разработку сервисов app.2lead.ru, созданных мной на JavaScript - без опыта программирования на этом языке. Это подтверждает возможность разработки ПО силами бизнес-аналитиков, продуктовых менеджеров и так далее. Ранее это была прерогатива только профессиональных программистов. 

Сервисы app.2lead.ru разработаны в конце 2024 года – начале 2025 года. Вошли в топ-5 Яндекса по запросу «калькулятор инфляции». Уже увеличили органический трафик сайта 2lead.ru более чем в 5 раз, без расходов на рекламу. // См. также «Нерекламные методы продвижения» https://habr.com/ru/articles/686736/

Сервисы app.2lead.ru // Калькуляторы инфляции. Аналитика. Прогнозы
Сервисы app.2lead.ru // Калькуляторы инфляции. Аналитика. Прогнозы

Что дальше? Массовое применение таких методов разработки ПО, более совершенные low-code системы и программирование голосом? Считаю, что практику low-code нужно расширять, разрабатывать учебные материалы по этому направлению и т.д. В этих инструментах есть большое пространство для развития.

Теги:
Всего голосов 5: ↑0 и ↓5-5
Комментарии0

Как я использую ИИ в разработке

Последний год я активно использую ИИ в разработке (особенно рутинных задачах): сначала ChatGPT 4o стал достаточно умным и подсказывал куски кода. Потом я освоил GitHub Copilot в VS Code (Go и TypeScript) и Inteliji IDEA (Java). А последние полгода пишу в основном в Cursor IDE.

Cursor IDE мне очень сильно понравился своим автокомплитом. Он не просто подставляет автодополнение, а умеет переписывать большие куски кода в разных частях файла.

Последние несколько месяцев я начал чаще использовать агентский режим: это когда говоришь IDE что делать, а она бегает по разным файлам и меняет их.

И тут мой мозг начал взрываться! Агентский режим Cursor'a и интеллект ChatGPT o3-mini-high творят чудеса. В типовых задачах — это жуткая экономия времени.

(Пока писал пост, Open AI выпустили полноценную o3 и o4-mini-high 🤯).

Как я понял, Cursor + Claude 3.7 действуют по следующему алгоритму:

  1. Проходит по исходникам, собирает контекст и паттерны.

  2. Залезает в исходники библиотек и смотрит их код.

  3. Если сильно нужно — бегает в интернет и обкашливает вопросики там.

  4. Вносит изменения в код.

  5. Смотрит ошибки линтеров и компиляции (!!!).

  6. Ещё раз исправляет код и, если нужно, снова бегает по исходникам и библиотекам.

  7. Говорит, что сделал и подсвечивает измененные куски кода.

На видео выше записал, как решаю задачу таким способом.

Задача: есть код, который принимает события от Telegram. В него нужно добавить поддержку новых событий и обновить DTO.

Cursor смотрит в интерфейс, что нужно добавить. Затем смотрит в библиотеку, какие там модельки. Обновляет код. Сам фиксит ошибки, если есть. Так ещё и говорит: "DTO и так нормальные, их трогать не буду". Красота!

К сожалению, как" вайб кодить" — я пока не понял. Потому что:

  • весь код нужно сильно перепроверять;

  • на задачах с весомой бизнес логикой получается фигня;

  • пограничные кейсы не обрабатываются;

  • тесты для чего-то больше CRUDов получаются с тоннами шаблонного кода, мало переиспользования;

  • если файлов сильно много и задача в духе "пройдись по паре сотням файлов и поменяй что-то", Cursor начинает галлюцинировать и выдавать фигню.

Итого: сейчас ИИ мне сильно экономит время на шаблонных и рутинных задачах. Особенно, если задача не выходит за рамки 2-3 файлов и в проекте всё ок с тестами.

Условно, я делаю на 10%-20% меньше рутинной работы, которая раньше могла отнимать 2-3 часа в день.

Что-то комплексное или "написать проект с ИИ, не смотря код" — пока не получается (как минимум, пока что).

Но, в любом случае, уметь использовать ИИ потихоньку становится must have навыком для среднестатистических разработчиков. Разумеется, если используется не редкий язык, не специфическая сфера (типа написание ОС, где недостаточно обучающих данных) или не что-то критичное (медицина, ядерка и т.д.).

---

Если вам понравился пост или оказался полезным, поставьте, пожалуйста лайк ❤️. Это мотивирует делиться опытом из разработки. И, как полагается, у меня есть Telegram-канал, в котором я рассказываю про разработку, развитие SaaS-сервисов и управление IT проектами.

Теги:
Всего голосов 11: ↑9 и ↓2+8
Комментарии1

Автоматическое подключение локализации для веб-ассета в Joomla

Начиная с Joomla 4 в ядре реализована концепция веб-ассетов. Управление JavaScript и CSS в Joomla значительно упростилось благодаря классу WebAssetManager. Есть замечательная статья Как правильно подключать JavaScript и CSS в Joomla 4, в которой подробно и с примерами кода рассказывается об этой концепции и её применении. Например, в web asset мы можем оформить какую-нибудь готовую js-карусель или библиотеку.

Также можно оформить веб-ассетом и свой собственный js-скрипт, которому могут понадобиться дополнительные данные для работы на странице: как данные из PHP, так и языковые константы. С помощью WebAssetManager мы можем получить эти данные в момент сразу при подключении ассета. Как это сделать?

Для веб ассетов в Joomla создаётся файл joomla.asset.json, в котором описываются url подключаемых файлов, версии, их зависимости друг от друга, собираются пресеты для подключения пачкой и т.д. В нём можно указать пользовательский класс WebAssetItem, который будет выполнять нужную работу для вашего ассета. Для этого определите свойства namespace и class для всего файла или же для каждого ассета.

{
  "$schema": "https://developer.joomla.org/schemas/json-schema/web_assets.json",
  "name": "com_example",
  "version": "4.0.0",
  "namespace": "Joomla\Component\Example\Administrator\WebAsset",
  "assets": [
    {
      "name": "foo",
      "type": "script",
      "class": "FooAssetItem",
      "uri": "com_example/foo.js"
    },
    {
      "name": "bar",
      "type": "script",
      "namespace": "MyFooBar\Library\Example\WebAsset",
      "class": "BarAssetItem",
      "uri": "com_example/bar.js"
    }
  ]
}

Ассет foo будет работать с классом Joomla\Component\Example\Administrator\WebAsset\FooAssetItem, а ассет bar с классом MyFooBar\Library\Example\WebAsset\BarAssetItem. Если namespace не указан, будет использоваться Joomla\CMS\WebAsset по умолчанию. Ну и сам класс должен находиться по указанному неймспейсу.

<?php
/**
 * Класс WebAssetItem для подключения данных для работы веб ассета
 */

namespace Joomla\Component\Example\Administrator\WebAsset\AssetItem;

\defined('_JEXEC') or die;

use Joomla\CMS\Document\Document;
use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\WebAsset\WebAssetAttachBehaviorInterface;
use Joomla\CMS\WebAsset\WebAssetItem;

class FooAssetItem extends WebAssetItem implements WebAssetAttachBehaviorInterface
{
    /**
     * Method called when asset attached to the Document.
     *
     * @param   Document  $doc  Active document
     *
     * @throws \Exception
     *
     * @since   1.0.0
     */
    public function onAttachCallback(Document $doc)
    {
        Factory::getApplication()->getLanguage()->load('com_example');

        // Add my-js-script.js language strings
        Text::script('COM_EXAMPLE_LANGUAGE_STRING_FOR_FRONTEND');

        /** @var array $data Данные для фронтенда, чтобы получать их
         *  в js через Joomla.getOptions('com_example.foo.js.data';)
         */
        $data = [
            'any' => 'data',
        ];
        /** @var bool $merge Whether merge with existing (true) or replace (false) */
        $merge = true;
        $doc->addScriptOptions('com_example.foo.js.data', $data, $merge);
    }
}

Таким образом для нашего js-скрипта мы получили и локализованные стринги сообщений (как? - пост на Хабре) и дополнительные данные из PHP для фронтенда (статья на Хабре - в середине). Теперь когда вы где-то в любом месте Joomla подключаете веб ассет с помощью $wa->useScript('foo') - автоматически подключится всё необходимое для его работы.

Теги:
Всего голосов 1: ↑1 и ↓0+1
Комментарии0

🗓 4.04 - World Webmasters Dаy [вехи_истории]

🗓 4.04 - World Webmasters Dаy [вехи_истории]
🗓 4.04 - World Webmasters Dаy [вехи_истории]

4 апреля отмечается День веб-мастера (World Webmasters Day) – праздник всех, кто разрабатывает, поддерживает и совершенствует сайты. Веб-мастера — это программисты, дизайнеры, SEO-специалисты, администраторы и многие другие профессионалы.

Выбор даты не случаен: 4.04 ассоциируется с известной ошибкой 404 «Страница не найдена». Это своеобразный символ работы веб-мастеров, ведь их задача — следить, чтобы сайты всегда работали гладко и без сбоев, но не всегда получается)

С момента появления первых веб-страниц интернет сильно изменился. Если раньше веб-разработчик отвечал за всё — от написания кода до оформления, то сегодня сфера веб-разработки включает UX/UI-дизайн, поисковую оптимизацию, маркетинг и кибербезопасность.

🩵 Поздравляю всех веб-разработчиков. Пусть ваши сайты падают реже)

YouTube | RuTube | Telegram | Pikabu

Теги:
Всего голосов 1: ↑1 и ↓0+1
Комментарии0

Совет по Joomla: dot-нотация для доступа к значениям вложенных массивов.

Позволю себе немного ребячества ))

Наткнулся на пост в одном из php-шных каналов о том, как в Laravel можно использовать нотацию "точка" для доступа к значениям вложенных массивов. И тем самым упростить доступ к многомерным массивам с помощью одной строки, разделенной точками.

😎 Joomla тоже так может!

use Joomla\Registry\Registry;
$data = [
        'user' => [
                'name' => 'John Doe',
                'email' => 'john@example.org',
        ]
];

$data = new Joomla\Registry\Registry($data);

$name = $data->get('user.name');
dump($name); // 'John Doe'

Чат русскоязычного Joomla-сообщества.

Upd. И коллеги сразу решили дополнить:

Преимущество джумлы перед ларой в этом плане:

  • можно так обращаться не только к массивам, но и к объектам и даже к json'у

  • можно дополнять

  • можно выполнять merge. Причём, как на весь объект, так и на отдельные его вложенности

Недостатки:

  • нужно сначала создать новый объект

  • нет вот такой нотации get('*.key'), т.е. чего-то похожего на array_column()

Теги:
Рейтинг0
Комментарии1

Как заговорить с сетевиками на одном языке? 😎

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

Курс подходит новичкам, которые хотят разобрать тему по полочкам. Но и опытным специалистам будет полезно: с этими материалами вы восполните пробелы в знаниях и вспомните все, что забылось со временем.

Начните обучение в Академии Selectel прямо сейчас ➡️

Теги:
Всего голосов 5: ↑5 и ↓0+8
Комментарии0

ОТП Банк дважды стал лауреатом премии Finnext 2025

ОТП Банк стал двукратным лауреатом премии Finnext 2025. Итоги подвели 27 марта в Москве. В рамках этого престижного события, учрежденного ИД «Регламент» и порталом FutureBanking, банк был признан победителем в двух ключевых номинациях: «Лучший кейс в технологиях работы с данными банка» и «Лучший кейс инноваций в маркетинге банковских продуктов».

Лучший кейс инноваций в маркетинге банковских продуктов

Награда была присуждена ОТП Банку за лучший кейс инноваций в маркетинге банковских продуктов. Проект по AI персонализации для холодного трафика на сайте банка позволил значительно улучшить взаимодействие с клиентами.

Используя платформу Sales Ninja, ОТП Банк перешел от ручных A/B тестов к автоматическим предиктивным персонализациям на основе искусственного интеллекта, что позволяет в режиме реального времени подстраивать сайт под каждого пользователя. Даже если он зашел на сайт в первый раз.

«Мы смогли не только «пробить потолок» классических подходов к работе над сайтом, но и улучшить ценность для наших клиентов. Персонализация — это не только про метрики, но и про то, что мы говорим с клиентом на понятном для него языке»,подчеркнул Вадим Валиуллин, product owner сайта ОТП Банка.

Лучший кейс в технологиях работы с данными банка

Проект «Data Governance: управление данными как активом в ОТП Банке» направлен на совершенствование культуры работы с данными. Николай Шевцов, директор по управлению данными ОТП Банка, отметил, что «данные в банке теперь воспринимаются как стратегический актив, а управление ими стало частью корпоративной культуры».

За последний год команда внедрила систему Data Governance и интегрированную с ней платформу автоматизированного контроля качества данных с элементами AI, обучила более 400 сотрудников работе с ней и интегрировала стандарты безопасности данных на всех уровнях организации. Результатом стало снижение ошибок при формировании отчетности, повышение доверия к качеству данных и улучшение процесса принятия бизнес-решений.

Он пояснил, что проект по внедрению культуры Data Governance играет ключевую роль в повышении эффективности, прозрачности и конкурентоспособности банка. «Глубокий анализ качественных клиентских данных позволяет персонализировать продукты и услуги, снижается вероятность ошибок в расчетах. А это значит, что коммуникации и предложения для клиентов становятся максимально индивидуальными», - подчеркнул Николай Шевцов.

Теги:
Всего голосов 1: ↑1 и ↓0+3
Комментарии0

К рекламе на сайтах все давно привыкли. Наверное, все так же понимают, что рекламные баннеры - это способ заработка для сайта, поэтому просьбы "отключите пожалуйста блокировщик" - это вполне понятно.

Но почему на некоторых сайтах, не будем ни на кого показывать пальцем, простая операция блокировки рекламы не только убирает какие-то там дополнительные картинки, которые можно было бы считать элементом дизайна и даже украшением - но еще и снижает загрузку CPU примерно в 8 раз?

Это что, показ картинки НАСТОЛЬКО процессор грузит? Какая-нибудь игра типа Quake c "живой" графикой - и то меньше ресурсов жретъ.
Или её попиксельно рисуют джваскриптом?
Или это не в картинке проблема?

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

Или эту мысль надо доносить до рекламодателей, в лице их SMM-щиков?

Теги:
Всего голосов 11: ↑11 и ↓0+13
Комментарии11

Регулярно на Хабре выходят статьи с рекомендацией использовать moment.js. В комментариях обязательно начинают советовать какой-нибудь dayjs или js-joda, но не потому, что они чем-то сильно лучше, а потому, что первый задепрекейчен авторами.. в пользу luxon.

Что за мания такая у JS-еров использовать раздутые тормозные библиотеки? Есть же быстрый и миниатюрный $mol_time с гораздо более удобным и функциональным API, почти полностью поддерживающим ISO8601, в отличие от всех остальных библиотек.

Бенчмарки говорят сами за себя
Бенчмарки говорят сами за себя

Что мотивирует людей довольствоваться не самым лучшим решением в индустрии? Я, наверно, странный, но я не могу этого понять.

Теги:
Всего голосов 19: ↑7 и ↓12-3
Комментарии39

Sketch-Programming: Минималистичная парадигма для проектирования кода (LLM transpiler)

(https://github.com/DmitryOlkhovoi/vscode-sketch-programming)

Удалось за вечер написать расширение под VS Code, которое на onSave траспайлит псевдокод (так называемый sketch код) и сохраняет.
Пока это POC и не полностью автоматизированный, но в качестве теста уже интересно

// @sketch:reactComponent

Component Count

props add = 0
state count = 0

<div onclick="count += add"> Add {add} </div>
<div>
    Current count: {count}
</div>

Превращает в

import React, { useState } from 'react';

interface Props {
    add?: number;
}

const CountComponent: React.FC<Props> = ({ add = 0 }) => {
    const [count, setCount] = useState<number>(0);

    const handleClick = () => {
        setCount((prev: number) => prev + add);
    };

    return (
        <div>
            <div onClick={handleClick}>Add {add}</div>
            <div>Current count: {count}</div>
        </div>
    );
};

export default CountComponent;

Следуя загруженным в векторное хранилище правилам (OpenAI)
https://github.com/DmitryOlkhovoi/Sketch-programming/blob/main/ReactComponentAskedModelToAddMoreRulesItself.md

К понедельнику постараюсь написать статью и более детально раскрыть тему

Теги:
Всего голосов 1: ↑1 и ↓0+1
Комментарии0

Представлен оналайн‑ресурс под названием «Утраченное искусство логарифмов», в котором исследуется полезность, история и повсеместность этого чудесного изобретения, логарифмы, включая то, что они, такое; с некоторыми демонстрациями их основного исторического применения в плоской и сферической тригонометрии.

Проект находится в разработке, но там уже есть основные начальные главы.

Теги:
Всего голосов 5: ↑5 и ↓0+6
Комментарии0

Как не надо использовать Assert, если реализуете подход Design by Contract

Использовать Assert вместо if err != nil { return err}

Одно из неправильных применений Assert — это замена им проверки, которая действительно должна быть и на которую нужно реализовать реакцию в коде.

Выполнять вычисления при вызове Assert

Еще одна распространенная и трудно выявляемая ошибка — это выполнение вычислений и присваивание значений переменным прямо при вызове Assert, которые могут быть упразднены при оптимизации кода компилятором:

  •  e.g. Assert(i++ > 0, “осторожно, не факт, что в релизе i увеличится”),

  •  Assert(call_to_f1(), “осторожно, не факт, что call_to_f1() будет вызвана в релизе”).

Удалять Assert, несмотря на то, что это часть описания контракта

Непонимание, что Assert — это реализация контракта, может привести к тому, что разработчик, незнакомый с DbC, захочет просто удалить проверку. Однако нужно всегда помнить, что срабатывание Assert говорит о нарушении контракта одной из сторон. То есть, если срабатывает Assert, надо прежде всего найти баг и пофиксить. А уж если контракт действительно должен быть изменен, Assert подскажет, где находятся участки кода, на которые нужно обратить внимание.

Например, вызывающая сторона может полагаться на некоторое поведение вызываемого кода. И если вызываемый код существенно изменился и контракт не выполнен, то вызываемая сторона тоже должна быть существенно переосмыслена.

В реализации пакета Go 1.23 fmt-функция Printf всегда возвращает err = nil. И практически все игнорируют возвращающееся значение ошибки, тогда как могли бы проверять постусловие assertion.Assert (err == nil). Так, рано или поздно в последующих версиях можно научить код реагировать на err, отличный от nil.

Как правильно применять assertions, если реализуете подход Design by Contract для улучшения производительности кода в продакшене? Читайте в статье →

Теги:
Всего голосов 1: ↑1 и ↓0+1
Комментарии0

Собственные макеты вывода для пользовательских полей Joomla

Мы привыкли использовать механизм переопределения макетов Joomla: скопируй нужный тебе файл макета в папку html шаблона и твори там что хочешь. Это в полной мере относится и к пользовательским полям Joomla.

Joomla ищет макеты рендера всех пользовательских полей в следующем порядке:

  • Есть ли файл templates/[template name]/html/layouts/[component name]/fields/render.php , переопределяющий макет вывода полей для конкретного компонента? Да - используем его.

  • Нет? Есть ли файл components/[component name]/layouts/fields/render.php в папке компонента? Да - используем его.

  • Нет? Есть ли файл templates/[template name]/html/layouts/com_fields/fields/render.php, переопределяющий вывод полей для com_fields? Да - используем его.

  • Нет? Используем файл components/com_fields/layouts/fields/render.php Это механизм поиска переопределений файлов макетов.

Вчера столкнулся с тем, что если поле вставлено в текст материала с помощью шорт-кода (кнопкой редактора) вида {field 25}, то переопределения не сработали. Поэтому стал вспоминать как сделать свой макет для поля Joomla.

Выбор пользовательского макета для рендера поля Joomla
Выбор пользовательского макета для рендера поля Joomla

Файл components/com_fields/layouts/field/render.php копируем в templates/YOUR_TEMPLATE/html/layouts/com_fields/field/etapy-raboty-nad-proektom.php. Обратите внимание, что мы файл переименовали, чтобы в настройках поля видеть его в выпадающем списке. После этого всё заработало как надо.

Благо, переводил уже раньше статью Как происходит рендер пользовательских полей в Joomla?. Потом, порывшись по своему же переводу увидел, что эта особенность работы Joomla в статье уже в ней описана 😂. А также напомнил себе о возможности указывать макет поля прямо в шорт-коде, через запятую: {field 25,etapy-raboty-nad-proektom}.

Теги:
Рейтинг0
Комментарии0

Стоит ли идти во фронтенд сейчас? Честный ответ разработчика

Артем несколько лет в сфере (вот его история). Сейчас он разработчик в крупном финтех-проекте. Вот его мысли:

— Да, фронтенд перенасыщен. Фреймворков много, технологии постоянно меняются. Все говорят об одном, но пишут по-разному. Но именно это и держит в тонусе — приходится регулярно обновлять знания. Сожалею ли я о своем выборе? Нет. Всегда любил погружаться в математические задачи, а фронтенд затягивает. Можно сутки биться над багом, ненавидеть его, плеваться… А потом решить — и словить кайф. В такие моменты код полностью поглощает, заставляя забыть о сне и еде.

Стоит ли идти во фронтенд сейчас?

— Никогда не поздно. Да, путь у каждого свой, и рынок сейчас нестабилен. Но при глубоком погружении за год можно набрать нужные скиллы и попасть на коммерческий проект.

🔥 Открыт набор на новый марафон!

Сейчас в Clevertec проходит марафон для начинающих фронтенд‑разработчиков. Это возможность погрузиться в профессию, получить реальный опыт и, возможно, стать частью команды. Участие бесплатное. Успей зарегистрироваться!

Теги:
Всего голосов 3: ↑1 и ↓2-1
Комментарии1

После выхода Firefox 136 оказалось, что разработчики значительно испортили переработали стартовую страницу (about:newtab). В комментарии к новости о релизе я уже поделился своим решением, но по мере того, как подмечал новые детали, решил завести под это дело отдельный пост и время от времени допиливать его. Коротко о том, что мы исправляем: сетку с шорткатами сделали слишком узкой, слишком высокой, а при наведении курсора подпись «прыгает».

Прежде всего, для этой задачи не помогут аддоны типа Stylus, потому что по соображениям безопасности им запрещён доступ к стилизации внутренних страниц. Нам понадобится папка chrome в профиле FF. Под Windows это \AppData\Roaming\Mozilla\Firefox\Profiles\profile\chrome. Если вы хотите подправить что-то в интерфейсе (стилизовать тулбар, например), создайте там файл с именем userChrome.css. Например, так можно удалить недавно появившуюся кнопку для показа всех вкладок:

#alltabs-button
{
display: none !important;
}

Но нам нужно поменять содержимое стартовой страницы, поэтому создадим в той же папке файл userContent.css.

Сетка стала узкой и высокой, потому что кто-то из дизайнеров поменял местами промежуток по горизонтали (20px → 0) и вертикали (0 → 20px). Будем надеяться, что хоть сознательно.

Вернём всё как было (ну, или можете установить свои значения):

ul.top-sites-list
{
column-gap: 20px !important;
row-gap: 0 !important;
}

Длинные заголовки при наведении мыши прыгают потому, что включается (при наведении, да!) режим переноса по словам. Пожалуйста, никогда так не делайте в пользовательских интерфейсах. Я не страдаю эпилепсией, но даже меня затошнило. Что уж говорить о более сенситивных личностях.

Исправляем:

.top-sites-list .top-site-outer .title .title-label
{
white-space: nowrap !important;

-webkit-line-clamp: none !important;
}

Ну и, наконец, шорткат можно сделать чуть побольше. Размеры его элементов рассчитываются на основе переменной, которая имеет значение 32px. Если добавить 4 пикселя, шорткат будет выглядеть, КМК, поприятнее:

:root
{
--size-item-large: 36px !important;
}

P.S. Пользуясь случаем, хочу попросить рекомендаций: чем вы пользуетесь в качестве главной страницы? Чтобы там были шорткаты (с полноценными preview, которые зачем-то убрала Мозилла), погода, калькулятор и что-нибудь ещё? Думаю, не запилить ли свой аддон со всем этим блэкджеком.

Теги:
Всего голосов 1: ↑1 и ↓0+1
Комментарии2

$mol_hack: finality

Вот и подошёл к концу первый хакатон по $mol, где нужно было переписать не хитрое научное оупенсорс приложение (Github, Online) на самый инновационный веб-фреймворк. Так что встречайте финалистов:

🥁🥁🥁 🥁🥁🥁

  1. ₽150K получает PavelZubkov (PR, Online). Он сделал не только наиболее полное и качественное решение, но и не большой PR в $mol.

  2. ₽75K получает reatailret (PR, Online). Он прислал достойное оригинальное решение в виде PWA приложения, но оно всё же не дотягивает до лидера по многим факторам: от неработающей авторизации, до расположения файлов не по фен-шую.

  3. ₽50K получает Lyumih (PR, Online). Его решение было самым ранним, но, как ни печально, так и осталось недоработанным. Даже не смотря на часть кода взятую у PavelZubkov.

✨✨✨ ✨✨✨

Решение dukinm (PR) существенно основано на некорректно расположенных файлах от PavelZubkov, а правки носят в основном косметический характер. Однако, он единственный, кто написал хоть немного тестов и комментариев!

Сводная таблица с анализом решений

Спасибо всем участникам за хорошую битву. Те, кто ещё не умеет в $mol, нервно грызут ногти из-за упущенной возможности.

Теги:
Всего голосов 8: ↑3 и ↓50
Комментарии0

Запускаем бесплатный онлайн-марафон по фронтенд-разработке. Будет как в «Рокки» 

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

Как записаться?

Заполни анкету по ссылке в профиле и скинь другу. Заявки принимаем до 26 марта.

Что будет?

Интенсивный 3-месячный тренинг. Это бесплатно. По сути, ты будешь поэтапно с дедлайнами писать приложение. Каждый спринт проверяем с помощью автотестов. Плюс будет поддержка менторов, наших крепких разработчиков. Это реальная прокачка твоих навыков и готовый проект в резюме.

Это уже четвертый марафон — после каждого наша команда фронтенд-разработчиков растет.

Кого ждём?

Начинающих веб-разработчиков (JS, React), которые уже изучали теорию и хотят прокачаться на практике в условиях, максимально близких к реальному проекту. Главное — желание кодить. Подойдут:

- студенты профильных вузов

- выпускники курсов

- самоучки

Важное условие: приглашаем участников из Беларуси и России.

Что дальше?

После 26 марта отправим на почту инструкции и первые задания. Старт марафона 1 апреля (это не шутка). До связи, Рокки. 

Теги:
Всего голосов 4: ↑3 и ↓1+4
Комментарии0

Как мы сокращали количество запросов по фичам в API

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

Одна из основных сущностей в коде — это BotUser. То есть пользователь, который появился в приложении (зашёл хотя бы раз), имеет имя и Telegram ID

За ~полгода проекта у нас добавилось много фич, привязанных к пользователю. Практически все сопоставляются 1 к 1 по ключу User ID. Например, квизы, бонусные дни, купленные страницы, купленный карточки апгрейдов, тариф и т.д.

Раньше для каждой новой фичи мы добавляли новый запрос в API с фронтенда. И вот мы заметили, что на каждый заход пользователя стало уходить >10 запросов в API ⚠️.

Примерно вот так:

GET /users/user
// Response
{
  "tgUsername": ...,
  "tgId": ...,
  ...
}

GET /users/features/quizzes/completed
// Response
{
  "completedQuizzes": ...,
}
   
GET /users/features/pages/bought
// Response
{
  "boughtPages": ...,
}
   
GET /users/features/rates/rate
// Response
{
  "userRate": ...,
}

При этом, на каждый запрос мы проверяли авторизацию. В Telegram это делается с помощью хеша от Telegram + проверка подписи токеном бота

Следовательно, на каждый запрос мы делали JOIN пользователя, брали бота (сущность Bot) из кэша и мэтчили подпись (+ логгировали). Это лишняя нагрузка

Сейчас подсобрали все фичи в один запрос. Теперь, на каждый заход пользователя получается только один GET /app/account/data, который возвращает данные пользователя вместе с данными фичей:

GET /app/account/data

// Response
{
  ...
  "user": ...,
  "completedQuizzes": ...,
  "boughtPages": ...,
  "currentRate": ...,
  ...
}

За одно перепроверили, что:

  • не подгружаем связанные сущности, где не нужно (one-to-one, one-to-many);

  • если подгружаем сущности, всегда делаем это одним JOIN'ом (а не бегаем по 2-3 раза в БД, как любит делать Hibernate);

  • берём общие часто запрашиваемые данные из кэшей.

Это позволило снизить нагрузку на сервер и БД. К посту прикрепляю график загрузки части наших серверов по CPU до и после оптимизации.

---

Если вам понравился пост или оказался полезным, поставьте, пожалуйста лайк ❤️. Это мотивирует делиться опытом из разработки. И, как полагается, у меня есть Telegram-канал, в котором я рассказываю про разработку, развитие SaaS-сервисов и управление IT проектами.

Теги:
Всего голосов 5: ↑3 и ↓2+1
Комментарии0

В Joomla 4 и Joomla 5 появилась концепция Web Assets и WebAssetManager, с помощью которого можно управлять подключениями css, js файлов, подключением. Все css и js файлы включаются в общий реестр ассетов, затем выстраивается граф зависимостей и в итоге на генерируемую страницу подключается только то что нужно на данной странице.

Поскольку веб-ассеты можно добавлять с помощью плагинов (ссылка на статью ниже) - можно сказать, что появилось новое направление для плагинов - веб-ассеты. Вы можете устанавливать плагины, включающие веб-ассеты и использовать их как зависимости в самых разных местах Joomla: в шаблоне, в макетах модулей и плагинов.

Одним из таких плагинов веб-ассетов является WT JSwiper.js. Плагин добавляет в Joomla Web Assets Registry ассет популярного скрипта swiper.js, который потом легко можно использовать в коде:

use Joomla\CMS\Factory;

$wa = Factory::getApplication()->getDocument()->getWebAssetManager();
// Локальный файл
$wa->useScript('swiper-bundle')->useStyle('swiper-bundle'); 
// Подключение из CDN
$wa->usePreset('swiper-bundle-remote'); 

😐 Например, было: иконочный шрифт могут использовать 2 разных модуля. CSS обычно подключается в шаблоне и он грузится везде, даже там, где не надо. Если же подключать CSS в одном модуле, а в другом нет - на странице стиль есть ровно до тех пор, пока опубликован модуль с этим подключением.

👍 Стало: теперь в макетах расширений мы просто пишем $wa->useStyle('my.style'); и за необходимостью подключения нужного ассета (в данном случае CSS с иконочным шрифтом) следит Web Asset Manager. Если мы снимем один модуль с публикации, то нужный ассет подключит другой модуль.

Поскольку плагин - расширение Joomla - его можно обновлять обычным для Joomla способом и всегда иметь самую свежую версию любимого js-скрипта или веб-ассета на всех своих сайтах и сайтах ваших клиентов.

В этой версии, кроме обновления собственно ассета до версии 11.2.5 к нему добавился пока что частичный перевод документации Swiper на русский язык.

Также будет полезно:

Теги:
Всего голосов 1: ↑1 и ↓0+1
Комментарии0

Представлен проект Scroll Buddy — анимация на полосе прокрутки.

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

Теги:
Всего голосов 2: ↑2 и ↓0+3
Комментарии2

В начале года я опубликовал статью про гибридное кэширование.

Гибридное кэширование в ASP.NET Core
В .NET 9 появилась новая библиотека для кэширования — HybridCache . В статье расскажу, что это такое...
habr.com

Прошло уже больше месяца, а стабильная версия nuget-пакета Microsoft.Extensions.Caching.Hybrid так и не вышла.

Я не делаю прогнозы по датам выхода, но хочу порассуждать на тему того, чего ожидаю от стабильной версии. И чего — точно нет.

Начну с последнего — каких изменений я не ожидаю

Изменение состава и сигнатур текущих методов. Если следить за выходом новых версий пакета Microsoft.Extensions.Caching.Hybrid, можно заметить, что методы объекта HybridCache не меняются уже давно. Из этого можно сделать вывод, что в стабильной версии мы увидим тоже самое, что наблюдаем сейчас.

Какие изменения я ожидаю увидеть

Удаление объекта из кэша по тегам. На момент написания статьи метод RemoveByTagAsync вообще не имел реализации. Сейчас в версии 9.2.0-preview.1.25105.6 он реализован и вполне себе работает, так что в релизную версию явно войдёт.

Не удивлюсь, если изменится логика присваивания тегов. Сейчас для многих она может быть неочевидной. Разберём пример:

  await cache.GetOrCreateAsync(
    "someKey",
    async ct => await SomeFuncAsync("someKey", ct),
    options,
    ["tag1", "tag2", "tag3"],
    cancellationToken);

  await cache.GetOrCreateAsync(
    "someKey",
    async ct => await SomeFuncAsync("someKey", ct),
    options,
    ["tag1", "tag4"],
    cancellationToken);

Представим, что метод GetOrCreateAsync вызывается несколько раз с одним и тем же ключом, но разным набором тегов. Теги будут присвоены только при первом попадании объекта в кэш, то есть в момент его извлечения из хранилища. Когда проектируем приложение, не всегда заранее известно, в какой из вызовов GetOrCreateAsync объект будет извлекаться из кэша, а в какой — из хранилища. Оно и логично — метод специально создали так, чтобы мы не задумывались об этом. Соответственно, сейчас при вызове этого метода мы не можем определить, какой из наборов тегов ляжет в кэш.

И тут у меня два варианта развития событий: или логика поменяется и теги будут перезаписываться всегда — независимо от того, берётся объект из кэша или хранилища. Или при написании программы нужно будет следить, не передаём ли мы разные наборы тегов.

Теги:
Всего голосов 3: ↑2 и ↓1+3
Комментарии0
1
23 ...