EvApps
192 subscribers
1.24K photos
52 videos
2 files
252 links
IT-aутстафферы из Тулы💚
https://evapps.ru/

Здесь пишем про веб- и мобильную разработку

▶️ Наш чат для системных аналитиков: https://t.me/pro_sa_evapps

▶️ Посмотреть, как мы живём: https://vk.com/evapps
Download Telegram
🤖Сегодня большинство цифровых продуктов рано или поздно получают AI-функциональность

AI-агенты, NLP, автоматические решения — постепенно становятся привычной частью продуктовой разработки.

И вместе с этим появился новый рефлекс:
- Ответ получился странным — переписываем промпт
- Модель ошиблась — добавляем больше контекста.
- Поведение непредсказуемо — промпт недостаточно точный.

Со временем складывается впечатление, что качество работы AI зависит от prompt engineering. На практике это не так.

🔍Что происходит на самом деле

AI редко существует сам по себе. Чаще он встроен в продукт:
Получает данные из backend-сервисов, использует API, опирается на модели данных и выполняет действия внутри системы.
Здесь и возникает главная проблема.
Когда AI начинает работать плохо, команда пытается исправить поведение модели, и промпт превращается в инструмент компенсации архитектурных пробелов.

🛠 Почему всё сводится к промптам
Потому что их изменить проще.
Не нужно наводить порядок в данных, вводить единый источник правды или пересобирать бизнес-логику.
Достаточно добавить инструкции вроде «если данные неполные — сделай разумное предположение» или «если значения конфликтуют — выбери логичное», и вроде бы начинает работать лучше.
Но часть архитектурных решений просто переносится внутрь запроса к модели.

⚡️Важно понимать:
AI не знает, как устроен продукт.
Он видит только ту картину мира, которую открыли — кусок данных, ограниченный контекст, описание правил.
Если бизнес-логика не формализована, модель будет угадывать.
Если не определила источник истины, будет интерпретировать.

Когда AI начинает не только отвечать, но и выполнять действия, ситуация становится ещё хуже.
AI-агент — это распределённая система с вероятностным компонентом: запросы выполняются асинхронно, состояние восстанавливается из контекста, операции повторяются, ошибки сложно воспроизводятся.
Если архитектура продукта не рассчитана на такие сценарии, появляются знакомые эффекты: действия выполняются дважды, решения принимаются на неполных данных, система уверенно делает неправильные шаги.
И снова кажется, что проблема в AI, хотя он лишь усиливает системные слабости.

Ограничения, проверки и дополнительные инструкции - помогают снизить количество ошибок.
Но чаще это выглядит так: ещё больше правил в промпте, дополнительные проверки после ответа, просьбы к модели уточнять действия у пользователя.
Снижаются симптомы, но не устраняется причина — отсутствие чёткой структуры взаимодействия между AI и продуктом.

🕵️Непопулярная правда
Со временем становится заметна одна неприятная закономерность: AI не упрощает архитектуру продукта и не компенсирует слабые места.
Наоборот, делает их очевидными.
Когда архитектура изначально спроектирована аккуратно — с понятными границами, согласованными данными и формализованной бизнес-логикой — AI внутри неё ведёт себя спокойно и предсказуемо.

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

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

🚀В итоге
Prompt engineering остаётся важным инструментом работы с AI
Но не исправляет продуктовую архитектуру, AI ускоряет момент, когда архитектурные проблемы становятся заметны и раньше, чем это происходило в системах без AI.

#AI #web #development #NLP #architecture #tech
🔥2
В прошлом посте я писал, что prompt engineering не исправит архитектуру.💻
И сразу получил ожидаемый ответ:
«Окей, но умение писать промпты — не менее важная часть работы с AI‑системами».

И… да.
Как и умение писать SQL, который компенсирует плохо спроектированную базу.
Полезно? Конечно.
Но это не отменяет того, что проблема — глубже.

Для тех, кто хочет разобраться в том, как писать запросы лучше, есть книга Prompt Engineering (Lee Boonstra, 2025). 

Давайте разберёмся, что в книге действительно полезно, а что стоит читать с поправкой на реальность.

Что в книге действительно ценно🧩
Книга честно проговаривает то, что хайп вокруг AI обычно замалчивает:
LLM — не разум. Это предсказательная машина.  
Она угадывает следующий токен. Вежливо. Последовательно. Без понимания.

Всё остальное — «мышление», «рассуждение», «принятие решений» — это надстройки, которые мы сами прикручиваем.

Техники, описанные в книге:
- Chain of Thought
- Step‑back prompting
- Self‑consistency
- ReAct
- JSON‑схемы
- Ограничения вывода

Это не магия. Это механизмы контроля.

Если вы когда‑то:
- Оборачивали нестабильный API ретраями,
- Добавляли идемпотентность,
- Заставляли ответ соответствовать схеме, чтобы он не ломал систему,

то вы уже занимались prompt engineering.
Просто не называли это так.

Ключевая мысль книги⚙️
Prompt engineering — это middleware для вероятностных систем.

Все техники в книге решают одни и те же проблемы:
- Недетерминизм,
- Отсутствие структуры,
- Отсутствие контрактов,
- Непредсказуемые ретраи,
- Побочные эффекты.

Классические проблемы распределённых систем.

Только вместо логов — абзацы.
Вместо stack trace — уверенность.

Когда промпт‑инжиниринг действительно уместен🎯
Он отлично работает, когда:
- Задача по природе размытая (язык, суммирование, классификация),
- Цена ошибки низкая,
- Вывод носит рекомендательный характер,
- Можно безопасно ретраить,
- Никто не притворяется, что система детерминирована.

Но если вы используете его, чтобы:
- Применять бизнес‑правила,
- Принимать финансовые решения,
- Менять состояние продакшена,
- Заменять доменную логику,

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

Главный урок книги ( о котором явно не говорят)📘
Лучшие промпты в книге имеют общие черты:
- Чёткие входные форматы,
- Явные схемы,
- Узкие обязанности,
- Детерминированные ожидания,
- Скучные, предсказуемые ответы.

Настоящий урок — не:
Стань гуру промптов
а:
«Твоя система наконец должна иметь границы. И AI больше не позволит тебе их игнорировать».

Вывод🧠
Книгу действительно стоит прочитать — не как набор трюков и не как быстрый способ «прокачать» навыки.
Она полезна, если смотреть на неё глазами инженера, который разбирается с тем, как ведут себя вероятностные системы

Prompt engineering не исправит архитектуру.
Он делает важную вещь:
Помогает увидеть те проблемы, которые раньше было легко не замечать.
Возможно, именно поэтому создаётся ощущение, что это такой мощный инструмент.
2
🌐Браузер сегодня — это уже не просто «рендер HTML».
Проблема в том, что мы часто по привычке тянем библиотеки… даже когда нужный инструмент уже встроен:
1) Structured Clone API 🧬
Раньше вопрос «как правильно скопировать объект?» был классикой.
Кто-то вспоминал про ссылки, кто-то — про Object.assign, кто-то — про JSON, а кто-то начинал гуглить 😉
Сегодня всё стало проще:
const copy = structuredClone(original);

Почему это удобно:
- Работает с Map, Set, Date, Blob, File, ArrayBuffer
- Корректно обрабатывает циклические ссылки
- Поддерживается всеми современными браузерами

2) Performance API ⏱️
Мы часто спорим об оптимизациях, но редко честно измеряем результат.
А между тем, браузер уже даёт простой инструмент:
performance.mark("start");
// код
performance.mark("end");
performance.measure("test", "start", "end");
console.log(performance.getEntriesByName("test"));

Это полезно для:
- Микро-бенчмарков
- Сравнения разных реализаций
- Проверки, имеет ли смысл Worker или WASM
Работает стабильно во всех современных браузерах.

3) Page Visibility API 👀
Этот API сообщает, активна ли вкладка.
document.addEventListener("visibilitychange", () => {
if (document.hidden) {
video.pause();
}
});

Реальный мир выглядит так:
Пользователь открыл ваше приложение — и ушёл в другую вкладку на полчаса.
Или вообще забыл вернуться.
Можно:
- Cтавить видео и анимации на паузу
- Останавливать polling
- Снижать нагрузку на CPU
И серверу станет легче жить.

4) ResizeObserver 📐
Наконец-то можно следить за размером элемента, а не только окна.
const ro = new ResizeObserver(entries => {
for (const entry of entries) {
console.log(entry.contentRect.width);
}
});
ro.observe(element);

Если вы делали адаптивные компоненты или графики, вы точно писали костыли под resize.

5) IntersectionObserver 📍
Этот API отвечает на вопрос: попал ли элемент в область видимости?
const io = new IntersectionObserver(entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
console.log("Элемент виден");
}
});
});
io.observe(element);

Идеально подходит для:
- Lazy loading
- Infinite scroll
- Анимаций при скролле
Любой, кто реализовывал infinite scroll вручную, знает, насколько это «весёлое» занятие 😄

6) AbortController 🛑
Чаще всего его используют с fetch, но на самом деле он подходит для любых отменяемых операций.
const controller = new AbortController();
fetch(url, { signal: controller.signal });
// позже
controller.abort();

Плюсы:
- Можно отменять несколько операций
- Подходит для fetch, стримов, обработчиков событий и т.д.

7) Idle Detection API 🧍
Если Page Visibility говорит о вкладке, то Idle Detection говорит активен ли пользователь за устройством
const detector = new IdleDetector();
await detector.start();
detector.addEventListener("change", () => {
console.log(detector.userState);
});

Пользователь может держать вкладку открытой, но в реальности — уйти на созвон.
Примеры применения:
- Авто-выход из аккаунта
- Статус «away»
- Оптимизация фоновых задач
Поддержка в основном в Chromium и требует разрешения.

8) BroadcastChannel API 📡
Простой способ общаться между вкладками одного сайта.
const channel = new BroadcastChannel("app");
channel.postMessage("logout");
channel.onmessage = e => {
console.log(e.data);
};

Подходит для:
- Cинхронизации логаута
- Cостояния авторизации
Особенно актуально, когда у пользователя открыты пара вкладок.

9) Web Locks API🔐
Нужен, чтобы не делать одну и ту же работу в нескольких вкладках.
navigator.locks.request("data-lock", async () => {
await fetchData();
});

Например:
- Только одна вкладка опрашивает сервер
- Меньше лишних запросов

10) File System Access API 📁
Да, браузер умеет работать с файлами напрямую.
const [fileHandle] = await window.showOpenFilePicker();
const file = await fileHandle.getFile();

Это открывает дорогу для:
- Веб-редакторов
- Инструментов импорта/экспорта
Поддержка в основном у Chromium-браузеров.

А какими вы уже пользовались? 😊

#web #frontend #javascript #dev
🤖 AI убил рынок джунов?
Сейчас много разговоров о том, что AI убил рынок джунов.
Статистика вакансий действительно выглядит пугающе.

Но проблема немного в другом.
Роль junior-разработчика не умерла — просто сломалась карьерная лестница.

Раньше путь выглядел довольно понятно:

junior делал скучную работу — писал тесты, фиксил мелкие баги, делал CRUD, конвертировал схемы.
Для сеньоров это была рутина.
Для джунов — лучший способ понять, как на самом деле работают системы.
Через эту “скучную работу” постепенно появлялось главное:
интуиция — как ломаются системы, где появляются баги, как течёт data flow.
Сегодня эту работу делает AI.
Boilerplate, тесты, схемы, простые функции — всё это модель генерирует быстрее и дешевле.
То есть нижняя ступенька лестницы просто исчезла.

В результате рынок начинает выглядеть как странная “гантеля”:
• На одном конце — супер-сеньоры, которые с AI работают в 10 раз быстрее
• На другом — люди, которые умеют писать промпты
А моста между ними почти нет
И именно это сейчас ломает карьерный pipeline.
Но из этого не следует, что роль junior исчезла.Скорее она трансформировалась.

Новый junior — это не кодер, а аудитор
AI может генерировать код.
Но кто проверяет, что он правильный?
Именно здесь появляется новая роль.
Новый ключевой навык джуна — verification.

То есть способность:
— Читать код, который написал AI
— Находить архитектурные проблемы
— Замечать баги, которые проходят тесты
— Понимать, где AI ошибается
Проблема в том, что проверить можно только то, что понимаешь.
А значит от джунов теперь требуют почти сеньорские навыки анализа —но без нормального пути, как до них дойти.
Раньше обучение происходило через практику.Теперь эту практику всё чаще делает AI.

🔎Исследования это подтверждают
В эксперименте Anthropic джуны с AI выполняли задачи быстрее, но хуже понимали код.
Разница составила –17% по тестам на знание.
Разница не в инструменте.
А в том, как его использовали:
— одни делегировали задачу AI
— другие задавали вопросы и пытались понять решение
Те, кто пытался разобраться, учились.
Те, кто копировал ответ — нет.

🧠Почему это происходит

Во многом мы начинаем понимать идею именно в процессе её формулирования.
Когда этот процесс полностью отдаётся AI, результат появляется — но мышление может так и не сформироваться.
Если junior делегирует решение модели, он получает функцию.
Но пропускает сам процесс рассуждения, который позволил бы заметить, почему это решение может сломаться

⚠️Плохие ответы на Stack Overflow, странные баги, неожиданные проблемы —всё это заставляло сомневаться и проверять решения.
Иногда ответ выглядел правильным, но через пару часов становилось понятно, что он ломает половину системы.
Так появлялось настоящее понимание.
AI убирает этот опыт.
Он всегда отвечает уверенно и выглядит правым.
Поэтому легко просто скопировать решение —
и не разбираться, почему оно работает.

🧑‍💻В 2026 портфолио джуна — это уже не todo-app.

AI делает такой проект за 30 секунд.
Гораздо ценнее показать мышление и суждение:
— “Вот код, который предложил AI — и почему я его отклонил”— “Вот баг, который AI пропустил”
— “Вот как я проверил архитектурное решение”
— “Вот почему чистое решение AI ломается на масштабе”
Сегодня ценится не столько генерация кода, сколько способность разобраться, где он неправильный.
Не генерация. Суждение.

В Если компании перестанут нанимать джунов, потому что “AI дешевле” —откуда возьмутся сеньоры через 5–10 лет?
Пока хорошего ответа ни у кого нет.
Но компании, которые смогут заново построить эту лестницу, получат огромный кадровый запас.

А как вы думаете?
#ai #webdev #career #junior #programming #discussion
🔥5
🎨CSS функции в 2026: насколько далеко они зашли

Когда-то в CSS было всего две функции:

- calc()
- rgb()
И даже calc() многие использовали с осторожностью

Сегодня в CSS появились новые функции:
- anchor()
- anchor-size()
- exp()
- hypot()
- sign()
- shape()
- xywh()
- image-set()
CSS постепенно получает всё больше возможностей для работы с layout, вычислениями и адаптивностью

Разберём несколько интересных функций.
⚓️1. anchor() — позиционирование относительно элемента
Раньше для позиционирования tooltip или popover часто использовали JavaScript:
getBoundingClientRect()
+ scroll offsets
+ ResizeObserver

Теперь часть подобных задач можно решить средствами CSS
.tooltip {
position-anchor: --btn;
left: anchor(left);
top: anchor(bottom);
}

CSS может позиционировать элемент относительно другого элемента-якоря
Это упрощает реализацию tooltip, popover и похожих интерфейсных элементов

📏2. anchor-size() — размеры относительно другого элемента
Теперь элемент может брать размер от другого элемента, а не только от родителя или viewport
.popover {
width: anchor-size(width);
}

Это полезно для:
- Dropdown меню
- Popover
- Контекстных панелей
- Floating UI
Например, когда ширина выпадающего меню должна совпадать с шириной кнопки

📈3. exp() — экспонента в CSS
CSS получил функцию для экспоненциальных вычислений
width: calc(exp(2) * 10px);

Это может быть полезно для:
- Систем масштабирования
- Типографических шкал
- Плавных кривых анимации
Пример:
font-size: calc(1rem * exp(var(--scale)));

📐4. hypot() — вычисление расстояния
Функция возвращает длину гипотенузы по теореме Пифагора
width: hypot(30px, 40px);

Она может использоваться, например, при вычислениях расстояния или диагонали
Иногда применяется в сложных layout или анимациях:
transform: translate(
hypot(10px, 20px)
);

5. sign() — работа со знаком числа
Функция возвращает:
-1
0
1
в зависимости от значения
Пример:
opacity: calc(sign(var(--value)) * 1);

Это позволяет строить простые условные зависимости через CSS-вычисления

🖼6. image-set() — изображения для разных плотностей экранов
Позволяет указывать несколько версий изображения
background-image: image-set(
"image.png" 1x,
"image@2x.png" 2x
);

Браузер сам выберет подходящую версию в зависимости от плотности пикселей экрана
Плюсы:
- Оптимальная загрузка
- Экономия трафика
- Более чёткое отображение на retina-экранах

🔺7. shape() — работа с геометрией
Функция позволяет задавать геометрические формы для clipping
clip-path: shape(
from 0 0,
line to 100% 0,
line to 50% 100%,
close
);

Это упрощает создание нестандартных форм без SVG

📦8. xywh() — понятный синтаксис
Функция задаёт прямоугольник через координаты и размеры
Раньше:
clip-path: inset(10px 20px 30px 40px);

Теперь:
clip-path: xywh(10px 20px 200px 100px);

x, y, width, height
Такой синтаксис легче читать и поддерживать

🧩Итог
Современные функции CSS позволяют решать больше задач прямо на уровне стилей
Многие задачи интерфейса, которые раньше решались с помощью JavaScript, теперь иногда можно реализовать напрямую в CSS.

💬 Как вы относитесь к тому, что часть задач интерфейса постепенно переходит из JavaScript в CSS?
Это упрощает разработку или наоборот усложняет поддержку?


#css #webdev #frontend #webdevelopment #dev #programming
Готовь сани летом, а архитектуру - на старте проекта! 🚀

Если не хотите через пару лет плакать над контроллерами на 2000+ строк и молиться на God Class - приходите на наш вебинар.

2 апреля в 18:30 МСК встречаемся с ведущим fullstack-разработчиком EvApps Михаилом Прохоровым, чтобы поговорить по делу:

Почему «просто MVC» - это путь к архитектурному долгу?
Где проходит грань, когда DDD реально окупается, а не просто «усложняет ради понтов»?
Как тактические паттерны (Value Objects, Aggregates) вытаскивают проект из болота?

Участие бесплатное, но места надо занять😉
🔗 Регистрация по ссылке: clck.ru/3SaKJV
Media is too big
VIEW IN TELEGRAM
Врываемся в твою рабочую неделю с новым эпизодом подкаста IT ToLк🚀

В новом выпуске - Андрей Карпов, сооснователь проекта PVS-Studio: поиск ошибок в коде программ. Андрей 17 лет в IT, у него есть бэкграунд CTO, а сегодня он является амбассадором статического анализа кода, автором целого сборника "вредных советов" о C#, а еще строит DevRel в своей компании.

Что в подкасте?

⭐️ Скучают ли топ-разработчики по C++ после перехода в управление?

⭐️ Rust вытеснит C++ или это хайп?

⭐️ Почему AI-код - это новая головная боль для SAST-инструментов?

⭐️ И главное: что посоветовать себе в 2007 году, чтобы писать код без багов?

Гость честный, вопросы интересные. Поехали 🎧

Смотрим по ссылке: https://clck.ru/3Si2SR
1
Стартуем через полчаса🚀

EvApps приглашает вас на запланированную конференцию: Zoom.
Подключиться к конференции Zoom
https://us06web.zoom.us/j/86917612389?pwd=g9Lpv9yy4Jj4xNP9VqL2BNO5zjqm3u.1

Идентификатор конференции: 869 1761 2389
Код доступа: 874163
1
Architecture Evolution.pdf
1.6 MB
Всем, кто очень хотел, но не успел на вчерашний вебинар по эволюции архитектуры, дарим ссылочку на запись и прочие материалы😊

🔗 Запись вебинара здесь
Презентацию прикрепили👌
Ссылка на код здесь
2
Третья часть про то, что уже встроено в браузер, но мы всё равно городим лишнее.

1) <dialog> 🪟
Признайтесь — вы ставили bootstrap или MUI только ради модалки.
А браузер давно закрыл этот вопрос — и сразу с нормальной доступностью:
<dialog id="alert">
<p>Вы уверены? Это нельзя отменить.</p>
<button onclick="alert.close()">Подумаю ещё</button>
<button onclick="doTheThing()">Да, я понимаю</button>
</dialog>
<button onclick="alert.showModal()">Удалить всё</button>

Никаких зависимостей. Работает. Доступно.

2) Container Queries 📦
Media queries всегда смотрели на окно целиком — и это было источником боли при переиспользовании компонентов. Теперь компонент живёт своей жизнью:
.widget { container-type: inline-size; }

@container (min-width: 500px) {
.widget__body {
display: flex;
gap: 1rem;
}
}

Положи его в сайдбар или в центр страницы — он сам разберётся.

3) @supports 🧪
Раньше — полифилы, гадание на кофейной гуще и молитвы перед деплоем.
Теперь просто пишете условие и браузер сам решает:
.hero {
background: #1a1a2e;
}

@supports (background: oklch(50% 0.2 270)) {
.hero {
background: oklch(20% 0.15 270);
}
}

Старые браузеры получают fallback, новые — красоту.

4) crypto.getRandomValues 🔐
Вот этот паттерн живёт в миллионе кодовых баз:
const id = Math.random().toString(36).slice(2);
// где-то в продакшене плачет дев

Замените на нормальное решение:
const arr = new Uint8Array(10);
crypto.getRandomValues(arr);
const id = [...arr].map(n => n.toString(16).padStart(2, "0")).join("");

Энтропия реальная, вероятность коллизий — смешная.

5) requestIdleCallback ⏸️
Отправка аналитики прямо в момент рендера — один из способов испортить пользователю жизнь незаметно. Браузер сам скажет, когда у него есть свободное время:
const sendStats = () => {
navigator.sendBeacon("/api/stats", JSON.stringify(stats));
};

"requestIdleCallback" in window
? requestIdleCallback(sendStats)
: setTimeout(sendStats, 300);

Safari долго саботировал этот API — fallback обязателен.

6) :focus-within 🎯
Классика жанра: инпут в фокусе, а стилизовать нужно обёртку вокруг него. Раньше это решалось через JS и eventListener. Сейчас:
.field {
border: 2px solid transparent;
transition: border-color 0.2s;
}

.field:focus-within {
border-color: #6c63ff;
}

Чисто, без единой строчки скрипта.

7) navigator.onLine 📶
Офлайн — это не баг, это сценарий. Телефон в кармане, лифт, метро — всё это реальность:
const queue = [];

window.addEventListener("offline", () => {
queue.push(getPendingData());
});

window.addEventListener("online", async () => {
while (queue.length) {
await sendToServer(queue.shift());
}
});

Главная ловушка — online говорит только о наличии сети, но не о том, что ваш сервер жив.

8) Speech Recognition API 🎙
Перед тем как добавить ещё один тяжёлый пакет — сначала это:
const Engine = window.SpeechRecognition || window.webkitSpeechRecognition;

if (Engine) {
const voice = new Engine();
voice.lang = "ru-RU";
voice.onresult = ({ results }) => {
handleInput(results[0][0].transcript);
};
voice.start();
}

Работает только в Chromium-браузерах. В продакшен — с осторожностью, для прототипа — идеально.

9) requestAnimationFrame 🎞
setInterval для анимаций — это как делать setTimeout(fn, 16) и надеяться на лучшее. Браузер знает точный момент перерисовки, воспользуйтесь этим:
let position = 0;

function loop(timestamp) {
position = Math.sin(timestamp / 800) * 120;
el.style.transform = `translateX(${position}px)`;
requestAnimationFrame(loop);
}

requestAnimationFrame(loop);

Плавно, без артефактов, CPU не страдает.

Библиотеки — хорошо. Но перед npm install стоит спросить себя: а не встроено ли это уже? 😄

Что из списка уже в вашем коде?

#web #frontend #javascript #css #webdev
А есть ли среди нас РП и прочие руководители разработки? Сейчас проверим👌

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

🤬 Команда часами ворошит дашборды, пытаясь понять, "что вообще не так с продуктом", а проблема в сломанной кнопке, миграции, которую никто не отследил, или воронке с дырой размером в 30% пользователей?

10 июня в 18:30 по Москве наш системный аналитик Мария Костыкова расскажет:

Как найти в воронке "слабое звено", в котором исчезает почти треть лидов - и не сломать то, что работает;
Как отличить "метрики для управления" от "метрик для видимости";
Как посчитать ROI самого мониторинга, чтобы прийти к финансистам с цифрами, а не с фразой "нам бы еще отчетик настроить..."

У Маши 8 лет опыта в финтехе, промышленности и на ведомственных проектах - она разбирается💪

⭐️ Результат: ваша команда перестанет тратить часы на диагностику, а вы начнете видеть, где реально и безболезненно срезать затраты.

Участие бесплатно, но без регистрации - никак.
🔗 Ссылочка для регистрации
А вот и прямая ссылка для подключения к вебинару⬇️
Ждем всех в 18:30 МСК👌

EvApps приглашает вас на запланированную конференцию: Zoom.
Подключиться к конференции Zoom
https://us06web.zoom.us/j/85033644309?pwd=fnxE9hKm233Fso1Y5hgo9s1GE2k14l.1

Ссылка на чат конференции
https://us06web.zoom.us/launch/jc/85033644309

Идентификатор конференции: 850 3364 4309
Код доступа: 068498
⚡️Как обещали на вчерашнем вебинаре, делимся полезными материалами для тех, кто хочет знать, какие метрики помогут сэкономить бюджет, а какие дадут только красивые дашборды.

⬇️ Запись вебинара
📎 Презентация
📎 Шаблон дорожной карты

‼️ А подписаться на новый канал для IT руководителей можно здесь
Четвёртая часть про то, что браузер уже умеет сам — а мы по привычке тянем пакет.
Popover API 🎈 В прошлой части был <dialog> для модалок. Но половина случаев — это не модалка, а поповер: меню, тултип, дропдаун. И вот тут раньше начинался цирк с z-index, кликом «мимо» и Escape. Теперь два атрибута:
<button popovertarget="menu">Меню</button>
<div id="menu" popover>
<a href="#">Профиль</a>
<a href="#">Выйти</a>
</div>

Клик вне — закрывает. Escape — закрывает. Всё в top layer, никаких войн со z-index. Ноль JS.
:has() — родительский селектор 🎯 Двадцать лет фронтенд просил «а можно стилизовать родителя от ребёнка?». Наконец можно:
/* карточка, внутри которой есть картинка */
.card:has(img) { padding-top: 0; }

/* форма с невалидным полем */
form:has(:invalid) button { opacity: .5; }

Раньше это был querySelectorAll + навешивание классов вручную. Теперь — одна строка CSS.
crypto.randomUUID() 🆔 Классика, которая до сих пор живёт в проде:
const id = Date.now() + Math.random();

Нормальный UUID v4 встроен:
const id = crypto.randomUUID();
// "6f4d2c1e-8a3b-4f9c-b2e1-7d0a5c3e1f92"

Криптографически стойкий, коллизий можно не бояться. Работает во всех современных браузерах (нужен https или localhost).
Object.groupBy() 🗂 Сколько раз вы писали reduce, чтобы сгруппировать массив? Теперь это одна функция:
const users = [
{ name: "Аня", role: "dev" },
{ name: "Петя", role: "qa" },
{ name: "Ира", role: "dev" },
];

const byRole = Object.groupBy(users, u => u.role);
// { dev: [Аня, Ира], qa: [Петя] }

Есть и Map.groupBy(), если ключом должен быть объект. lodash можно не звать.
Intl.RelativeTimeFormat «2 часа назад», «через 3 дня» — ради этого до сих пор ставят moment/dayjs. А это уже в браузере, да ещё и с локализацией:
const rtf = new Intl.RelativeTimeFormat("ru", { numeric: "auto" });

rtf.format(-2, "hour"); // "2 часа назад"
rtf.format(1, "day"); // "завтра"

Сам знает про склонения и «вчера/завтра». Бесплатно, без килобайтов зависимостей.
Иммутабельные методы массива 🔄 sort() и reverse() десятилетиями мутировали исходный массив — и ловили баги в React, где стейт менять нельзя. Теперь есть неразрушающие версии:
const sorted = list.toSorted((a, b) => a - b);
const reversed = list.toReversed();
const patched = list.with(2, "new"); // заменить по индексу

Оригинал цел, возвращается копия. Больше никаких [...arr].sort().
View Transitions API 🎬 Плавные переходы между состояниями UI раньше означали Framer Motion или ручные костыли. Теперь браузер сам анимирует разницу до/после:
document.startViewTransition(() => {
updateTheDOM();
});

Меняете DOM внутри колбэка — браузер делает кроссфейд между старым и новым кадром. Для SPA-переходов и списков выглядит дорого почти бесплатно. Пока стабильно в Chromium, для остальных — прогрессивное улучшение.
inert 🚫 Открыли модалку, а Tab всё равно уводит фокус на кнопки под ней. Классическая дырка в доступности. Один атрибут — и целое поддерево выключено: ни фокуса, ни кликов, ни скринридера.
<main inert>...весь фон...</main>
<dialog open>...</dialog>

Раньше это был ручной обход всех focusable-элементов и tabindex="-1". Теперь — inert.
text-wrap: balance ⚖️ Заголовок, у которого одно слово одиноко висит на второй строке — вечная боль. Раньше лечили   вручную. Теперь браузер сам балансирует строки:
h1 { text-wrap: balance; }
p { text-wrap: pretty; }

balance — ровные строки для заголовков, pretty — убирает висячие слова в абзацах. Красиво и без ручной вёрстки.
Перед тем как поставить очередную библиотеку, всё чаще стоит проверить — а вдруг платформа это уже умеет? 😄
Что из этого уже используете?
#web #frontend #javascript #css #webdev #dev
🔥1
🤖 Кто отвечает за код, который написал AI?

Ассистент выдал 200 строк, вы нажали Tab. По закону вы, возможно, не владеете ни одной из них — но отвечать за каждый баг будете именно вы. В этом зазоре и живёт вся тема: модель не засудишь, а вендор давно всё написал мелким шрифтом — ответственность течёт вниз, к человеку, нажавшему Tab.

⚖️ Что говорят суды В США копирайт требует живого автора — то самое правило, по которому обезьяна не смогла зарегистрировать своё селфи. Copyright Office уточнил: AI-код охраняется, только если человек внёс «достаточно выразительного вклада». Одних промптов мало — в отчёте это сравнили с рулеткой: колесо крутишь, результат не контролируешь.

Инженерный перевод: «Tab to accept» — это рулетка. А «принял, переписал 4 строки, встроил в свой класс» — уже твой вклад. Код, вышедший из модели нетронутым, может юридически не принадлежать компании так, как код сеньора: его не защитить как актив и не засудить того, кто скопировал.

📜 Что говорит договор Строка из условий GitHub Copilot, которую не цитируют на встречах про внедрение AI: «Вы сохраняете всю ответственность за ваш код, включая Suggestions в нём».

Одно предложение отдаёт вам suggestions — и вешает все риски: лицензии из обучающих данных, чужой копирайт, баги. Это единственная рабочая форма: вендор не может гарантировать чистоту кода, обученного на всём GitHub, поэтому риск уходит туда, где кнопка merge.

🕳 Дыра с защитой от исков GitHub прикрывает от исков — но только на Business/Enterprise. На Individual те же suggestions, тот же риск и ноль защиты. А проекты сплошь едут на личных подписках: компания платит за Enterprise и думает, что закрыта, но код через личный аккаунт под защиту не попадает. CISO узнаёт об этом, когда прилетает иск.

🇪🇺 Регулятору всё равно, кто писал В ЕС смотрят не на владение, а на результат. AI Act, Cyber Resilience Act и Product Liability Directive складываются в одну логику: неважно, писал человек, AI или подрядчик — важен продукт на рынке. Уже 2 августа 2026 вступает часть AI Act. «Это модель предложила» — не аргумент, как и «это подрядчик написал».

⚠️ Тихая проблема ревью AI-код ревьюят менее внимательно: меньше времени, меньше замечаний, больше «компилируется, выглядит норм — го». Диф вдвое длиннее, ревью вдвое поверхностнее — там и проскакивают баг, косяк с лицензией и тихая дыра в авторизации.

🧭 Рабочая ответственность — четыре скучных шага — Все на индемнифицированном тарифе, никаких личных подписок для рабочего кода. — Duplicate-фильтр включён и проверяется в аудите, как SSO. — AI-код на ревью = сторонняя зависимость. Вопрос себе: «подписался бы я под этим, если бы модели рядом не было?» — У каждого PR есть человек с именем, который возьмёт трубку, когда всё сломается. Не модель, не вендор, не «команда».

Каждый suggestion — это вклад анонимного соавтора, который прочитал весь опенсорс планеты, которого не допросишь и которого договор вынес за пределы ответственности. Это не повод бросать AI и не повод тормозить. Вся защита сводится к самой скучной части процесса: человек смотрит на диф и решает, мержить или нет.

Ты написал merge commit — значит, он твой.

А у вас в команде кто отвечает за AI-код? 🤔

#ai #programming #career #law #webdev #discussion
👍1
Поздравления в студию🎉🎉🎉

Мы прошли ежегодную процедуру Минцифры России и в очередной раз подтвердили: EvApps — официально аккредитованная ИТ-компания.

И это вам не формальность "для галочки"!

💭 Ежегодная переаккредитация — это проверка того, что компания действительно ведёт профильную ИТ-деятельность, соответствует требованиям по структуре доходов и продолжает работать прозрачно.

Проходить её из года в год — значит стабильно расти и подтверждать это документально, а не только на словах💪

Что вообще все это значит?

Для наших сотрудников, попадающих под нужные категории, сохраняется отсрочка от призыва, остаётся доступной льготная ИТ-ипотека, а компания продолжает пользоваться налоговыми — а значит, может стабильно инвестировать в команду💚

Для наших партнёров и клиентов это дополнительная гарантия надёжности при выборе подрядчика по аутстаффингу, никаких сюрпризов и рисков, связанных со статусом компании, и это ещё одно подтверждение того, что с нами можно планировать сотрудничество вдолгую.

Спасибо нашей команде, чья ежедневная работа делает такие результаты возможными 🙌
🔥2
🤖 Как AI-агент тихо выбирает за тебя зависимости

Ты спрашиваешь агента: «какую библиотеку использовать под фича-флаги?».
Получаешь уверенный ответ с обоснованием и сразу идёшь пилить.
Кажется, что за тебя провели ресёрч и что именно этот вариант подобран под твой кейс.
Но на самом деле нейросеть выбрала архитектурное решение — а ты даже не заметил, что размышления не было.

📊 Что показывают цифры На llmrank.fyi каждый месяц гоняют одни и те же промпты через Claude, ChatGPT и Gemini и смотрят, что те советуют.
Картина такая: — Каждая модель называет один и тот же топ-вариант в 97–99% случаев.
Выглядит как устоявшийся консенсус — Но между собой три модели сходятся в топ-3 только в 58% случаев.

В 42% сценариев стоило спросить вторую модель — и она указала бы на другое решение. Консенсуса нет.
Есть три уверенных монолога, которые друг с другом не согласны.

🔍 Пример — Фича-флаги:
LaunchDarkly доминирует у всех, но Split.io всегда по-разному, а ChatGPT его вообще не упоминает.
Альтернативы AWS: ChatGPT в 100% случаев выдаёт Azure, а Gemini её не включает ни разу.

Одна и та же задача, разные модели — разный «очевидный» выбор.

🕵️ В чём настоящая ловушка
Опасность не в том, что совет плохой.
Опасность в том, что уверенность маскирует разногласие.
Детерминированный, гладкий ответ читается как результат исследования — а это всего лишь один предвзятый сэмпл с капелькой уверенности
И мы просматриваем план внедрения ровно с тем же ленивым доверием, с каким апрувим чужой PR по диагонали.

Раньше выбор зависимости — это был ресёрч, обсуждение в команде, проверка лицензии, иногда целый RFC.
Теперь дефолтный флоу: спросил агента → получил ответ → начал пилить.
Этап, где решение вообще осмыслялось, просто выпал.

🧭 Что с этим делать
Не «взять то, за что проголосовало большинство моделей».
Само разногласие — это сигнал.
Сходятся три модели — риск низкий.
Разошлись — это не шум, который надо усреднить, это флаг: вот здесь настоящая точка выбора, и тут нужен человек, который реально разберётся.

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

А вы проверяете, что советует агент, второй моделью — или сразу пилите? 🤔

#ai #agents #architecture #programming #webdev #discussion
1
🧠 Что реально происходит, когда ты вызываешь LLM API
Ты пишешь await openai.chat(...), ждёшь ответ и думаешь, что тормозит твой код. Чаще всего код тут ни при чём. Между твоим fetch и текстом ответа лежит физика, железо и география — и большую часть задержки ты не оптимизируешь ни одной строчкой.
Разберём путь запроса по частям.

🌍 1. Дорога до дата-центра (это физика, а не баг) Сигнал в оптоволокне идёт примерно на 2/3 скорости света — это жёсткий предел, его не обойти. От Лагоса до Лондона ~5000 км, и только на дорогу туда-обратно уходит минимум ~50 мс — ещё до того, как сервер начал думать. С учётом маршрутизации и заторов набегает 100–200 мс чистой географии.
Почему так? Потому что почти вся LLM-инфраструктура живёт в us-east-1 (Вирджиния) и eu-west (Ирландия/Франкфурт). В Нигерии, для контраста, 17 дата-центров, в США — больше 5500. Чем ты дальше от железа, тем дороже тебе обходится каждый вызов — просто по расстоянию.

⚙️ 2. GPU считает ответ по одному токену Промпт приходит на GPU, и та прогоняет миллиарды операций слой за слоем, чтобы предсказать следующий токен (это примерно 3/4 слова). Дальше — ещё один, и ещё, строго по очереди. Ответ не появляется целиком: он собирается токен за токеном.
Отсюда два следствия: — Длинный промпт грузит вход, длинный ответ грузит выход. Оба стоят компьюта. — Rate limits — это не вредность вендора, а отражение физического потолка железа. Один Nvidia H100 стоит ~$30 000, и он не резиновый.

❄️ 3. Cold start Модель — это сотни гигабайт весов, которые надо загрузить в память GPU. Если запросов давно не было, система могла выгрузить модель, чтобы освободить ресурсы. Первый запрос после простоя ждёт, пока веса заедут обратно — поэтому он заметно медленнее следующих. Тот самый «почему первый ответ тупил, а дальше полетело».

🛠 Что с этим делать на практике — Стримь ответ. Показывай токены по мере поступления, а не жди весь блок. Реальная задержка та же, но воспринимается сильно быстрее. — Кэшируй агрессивно. Повторяющиеся и почти одинаковые промпты — из кэша. Экономишь и инференс, и дорогу. — Бери модель под задачу. Для классификации, извлечения и коротких ответов 7B обычно быстрее и дешевле 70B — и по качеству не хуже.
Мораль простая: когда LLM «тормозит», сначала посмотри, где именно — на дороге, на железе или на холодном старте. Промпт-инжиниринг тут не поможет, а стриминг и кэш — очень даже.

А вы что делаете с латентностью LLM — стрим, кэш, свой прокси поближе к региону? 🤔
#ai #llm #webdev #backend #dev #performance
Двенадцать лет назад мы торжественно отделились от материнской компании и начали свой самостоятельный путь - то есть, все почти как у людей 😀
Сегодня EvApps - это порядка 100 спецов, которые каждый день усиливают ИТ-команды банков, страховых, маркетплейсов и промышленных компаний по всей России.
Более 450 проектов.
Более 100 клиентов, которые возвращаются к нам снова.

Двенадцать лет на ИТ-рынке — это несколько эпох.
И мы прошли их все💪

Менялись технологии, рынок труда (и не один раз!), правила игры. И каждый раз мы не просто удерживались на плаву - мы росли. Потому что за эти годы научились главному: быстро разбираться в новом, честно говорить с клиентом и не бросать проект, когда становится сложно.

Но цифры — это следствие, а причина всего — наша команда💚 Люди, которые остаются на проектах годами, а не месяцами, и клиенты потом просят «дайте нам ещё таких же!»

Спасибо каждому в команде EvApps — вы и есть компания!
Спасибо клиентам, которые доверяют нам свои задачи. И партнерам, которые всегда поддержат.

Нам 12, и мы только разгоняемся 🚀
🔥9
🗄 Почему твой SQL-индекс молчит
Знакомая история: повесил индекс, а запрос как тормозил, так и тормозит.
Индекс вроде есть, но планировщик смотрит на него и проходит мимо.
Собрал самые частые причины, из-за которых так происходит.
1. Обернул колонку в функцию 🔧 Вот это ломает индекс чаще всего:
WHERE YEAR(created_at) = 2024

Как только колонка попадает внутрь функции, индекс по ней уже не применить — и привет, seq scan по всей таблице. Лечится диапазоном:
WHERE created_at >= '2024-01-01'
AND created_at < '2025-01-01'

Ну или заводишь функциональный индекс, если без функции совсем никак.

2. LIKE, который начинается с % 🔍 Тут всё просто:
WHERE name LIKE '%anton'   -- бесполезно
WHERE name LIKE 'anton%' -- работает

B-tree умеет искать по началу строки, а не по середине. Если тебе реально нужен поиск по куску внутри — это уже полнотекстовый индекс или триграммы (в постгресе pg_trgm).

3. Порядок колонок в составном индексе 📚 Индекс (a, b) устроен как телефонная книга: сначала сортировка по a, и только внутри неё по b. Поэтому запрос, где есть только b, его не подхватит:
INDEX (user_id, created_at)

WHERE user_id = 5 -- норм
WHERE user_id = 5 AND created_at… -- норм
WHERE created_at > … -- мимо, левого префикса нет


4. Типы не совпали 🎭 Классика, на которой все хоть раз спотыкались:
-- phone у нас VARCHAR
WHERE phone = 89991234567 -- число против строки, индекс мимо
WHERE phone = '89991234567' -- порядок

База молча приведёт типы сама, а заодно тихо выкинет индекс.
Так что следи, чтобы тип значения совпадал с колонкой.

5. Индекс на колонке, где всего два значения 🎲 is_active, gender и прочие флаги индексировать почти бессмысленно.
Если под условие подходит половина таблицы, планировщику дешевле прочитать её целиком, чем скакать туда-сюда по индексу.
И он тут прав.
Индексы хороши там, где значение отсекает много строк, а не половину.

6. SELECT * мешает covering index 📦 Иногда индекс уже содержит все поля, которые тебе нужны, и база может отдать ответ прямо из него, не заглядывая в таблицу.
Красота. Но стоит написать SELECT * — и она вынуждена лезть в таблицу за каждой строкой ради остальных колонок. Бери только то, что реально используешь.

В общем, индекс — это не «создал и забыл».
Прежде чем гадать на кофейной гуще, открой EXPLAIN ANALYZE и посмотри, что там планировщик на самом деле делает.
Он-то не соврёт.

А у вас какой случай в духе «индекс есть, но его как бы нет» бесил сильнее всего? 🤔

#sql #database #postgres #backend #performance #dev