#webdevelopment
🔖 Высокотехнологичные ресурсы для веб-разработчиков
Веб-разработка не стоит на месте. Собрал подборку малоизвестных, но мощных инструментов, которые поднимут ваши проекты на новый уровень.
🔹 UI/UX & Design
Chakra UI — React-библиотека с готовыми компонентами
Тематическое оформление + доступность из коробки
Framer — интерактивные прототипы с реальным кодом
Мост между дизайном и разработкой
Midjourney — AI для генерации визуальных концепций
Уникальные дизайн-решения по текстовому описанию
🔹 Фуллстек & Backend
RedwoodJS — React + Prisma в одном фреймворке
Единая экосистема для фронта и бэка + GraphQL API
Deno Deploy — безопасное развертывание TypeScript
Альтернатива AWS Lambda с фокусом на безопасность
🔹 Технологии
Alchemy — инструменты для Web3 и dApps
Полный стек для блокчейн-разработки
Three.js — 3D-графика в браузере через WebGL
VR/AR и интерактивные 3D-конфигураторы
🔹 Совет от автора:
- Начинайте с малого — выберите 1-2 инструмента
- Присоединяйтесь к сообществам
- Вносите вклад в open source проекты
📎 Статья
🎙 Новости
📝 База вопросов
Веб-разработка не стоит на месте. Собрал подборку малоизвестных, но мощных инструментов, которые поднимут ваши проекты на новый уровень.
Chakra UI — React-библиотека с готовыми компонентами
Тематическое оформление + доступность из коробки
Framer — интерактивные прототипы с реальным кодом
Мост между дизайном и разработкой
Midjourney — AI для генерации визуальных концепций
Уникальные дизайн-решения по текстовому описанию
RedwoodJS — React + Prisma в одном фреймворке
Единая экосистема для фронта и бэка + GraphQL API
Deno Deploy — безопасное развертывание TypeScript
Альтернатива AWS Lambda с фокусом на безопасность
Alchemy — инструменты для Web3 и dApps
Полный стек для блокчейн-разработки
Three.js — 3D-графика в браузере через WebGL
VR/AR и интерактивные 3D-конфигураторы
- Начинайте с малого — выберите 1-2 инструмента
- Присоединяйтесь к сообществам
- Вносите вклад в open source проекты
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
#golang
🔖 Паттерн «Стратегия» в Go: от хаоса к порядку
Надоели бесконечные
Когда использовать:
Было:
Стало:
©️ Три простых шага:
1. Интерфейс стратегии — общий контракт для алгоритмов
2. Конкретные реализации — каждый алгоритм в отдельном классе
3. Контекст — управляет выбором и выполнением стратегий
©️ Реальные применения:
- Платежи: PayPal, карта, крипта — одним переключением
- Сортировка: быстрая, пузырьковая, слиянием — по размеру данных
- Сжатие: ZIP, RAR, GZIP — динамический выбор
- ML алгоритмы: линейная регрессия vs случайный лес
©️ Преимущества:
✅ Принцип открытости/закрытости — новые стратегии без изменения кода
✅ Тестируемость — каждый алгоритм изолированно
✅ Читаемость — прощай, огромные switch'и
✅ Масштабируемость — добавляй стратегии на лету
©️ Вместо цирка из условий:
Паттерн «Стратегия» использует отношение has-a (композиция), делая код гибким и расширяемым. Каждая стратегия — самостоятельная единица, которую можно тестировать и переиспользовать.
📎 Статья
🎙 Новости
📝 База вопросов
Надоели бесконечные
if-else и switch в коде? Паттерн «Стратегия» превращает спагетти-код в элегантную архитектуру с взаимозаменяемыми алгоритмами.Когда использовать:
Было:
switch operation {
case "add": return a + b
case "subtract": return a - b
case "multiply": return a * b
// ... еще 20 кейсов
}Стало:
calculator.SetStrategy(AddStrategy{})
result := calculator.Calculate(10, 5)1. Интерфейс стратегии — общий контракт для алгоритмов
2. Конкретные реализации — каждый алгоритм в отдельном классе
3. Контекст — управляет выбором и выполнением стратегий
- Платежи: PayPal, карта, крипта — одним переключением
- Сортировка: быстрая, пузырьковая, слиянием — по размеру данных
- Сжатие: ZIP, RAR, GZIP — динамический выбор
- ML алгоритмы: линейная регрессия vs случайный лес
Паттерн «Стратегия» использует отношение has-a (композиция), делая код гибким и расширяемым. Каждая стратегия — самостоятельная единица, которую можно тестировать и переиспользовать.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
#sysadmin
🔖 Цифровая энтропия: почему сервер с аптаймом в 1000 дней — это бомба замедленного действия
Сисадмин со стажем рассказал историю про сервер «Феникс» с аптаймом 986 дней. Гордость команды. Пример для новичков. После планового выключения-включения не взлетел — RAID-контроллер решил, что с него хватит. Тогда автор осознал: цифровой мир подчиняется тем же законам распада, что и физический.
В теории код и данные вечны. На практике любая система деградирует. Это цифровая энтропия — медленный скат в беспорядок. Долгий аптайм не показатель стабильности, а тикающая бомба. Система годами не проверяла собственные процедуры запуска.
Примеры из жизни: vSphere-хост после перезагрузки не нашел загрузочный USB — он был поврежден. SAN с аптаймом 1400 дней никто не трогал, боясь массового отказа дисков. Сервер выключили заменить диск в RAID — при включении умер еще один. Debian с аптаймом 1300+ дней — репозитории для этой версии уже не существуют.
Причины страха перезагрузки рациональны: файлы загрузки могут быть повреждены, железо деградирует (смазка густеет, конденсаторы высыхают), обновления безопасности не установлены годами.
Призраки в системе: утечки памяти в Apache/PHP/PostgreSQL, зомби-процессы исчерпывают PID, протухший DNS-кэш на всех уровнях, разросшиеся логи съедают диск. Долгий аптайм усугубляет все это.
Решение — смена философии. От «серверов-питомцев» (их лечат) к «серверам-стаду» (их заменяют). Неизменяемая инфраструктура: золотой образ, регулярная замена серверов, никаких ручных правок. Проблема долгого аптайма исчезает, утечки сбрасываются, дрейф конфигурации невозможен.
Главное правило: если боитесь перезагружать сервер — вы уже потеряли над ним контроль.
📎 Статья
🎙 Новости
📝 База вопросов
Сисадмин со стажем рассказал историю про сервер «Феникс» с аптаймом 986 дней. Гордость команды. Пример для новичков. После планового выключения-включения не взлетел — RAID-контроллер решил, что с него хватит. Тогда автор осознал: цифровой мир подчиняется тем же законам распада, что и физический.
В теории код и данные вечны. На практике любая система деградирует. Это цифровая энтропия — медленный скат в беспорядок. Долгий аптайм не показатель стабильности, а тикающая бомба. Система годами не проверяла собственные процедуры запуска.
Примеры из жизни: vSphere-хост после перезагрузки не нашел загрузочный USB — он был поврежден. SAN с аптаймом 1400 дней никто не трогал, боясь массового отказа дисков. Сервер выключили заменить диск в RAID — при включении умер еще один. Debian с аптаймом 1300+ дней — репозитории для этой версии уже не существуют.
Причины страха перезагрузки рациональны: файлы загрузки могут быть повреждены, железо деградирует (смазка густеет, конденсаторы высыхают), обновления безопасности не установлены годами.
Призраки в системе: утечки памяти в Apache/PHP/PostgreSQL, зомби-процессы исчерпывают PID, протухший DNS-кэш на всех уровнях, разросшиеся логи съедают диск. Долгий аптайм усугубляет все это.
Решение — смена философии. От «серверов-питомцев» (их лечат) к «серверам-стаду» (их заменяют). Неизменяемая инфраструктура: золотой образ, регулярная замена серверов, никаких ручных правок. Проблема долгого аптайма исчезает, утечки сбрасываются, дрейф конфигурации невозможен.
Главное правило: если боитесь перезагружать сервер — вы уже потеряли над ним контроль.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
#webdev
🔖 Что если не отправлять HTML вообще?
Знаете, что делает большинство фреймворков? Они генерируют HTML на сервере, отправляют его вам, а потом начинают танцы с бубном под названием "гидратация". Тяжело, медленно, дорого.
А разработчик Neo.mjs подумал: "А что если вообще не отправлять HTML?"
И сделал приложение, которое стартует с пустым body. Звучит дико?
🔸 Вот как это происходит:
Браузер получает крошечные JS-генераторы, кэширует их один раз, и всё. Дальше с сервера летит только лёгкий JSON с данными — никакого HTML-мусора. Генераторы строят интерфейс на лету, и навигация работает так быстро, что кажется, будто страницы уже загружены.
Внутри этого приложения живёт редактор Monaco — 3 мегабайта кода из VSCode. Обычно такой монстр хоронит любые метрики производительности. Но здесь он летает. Более того — вы пишете код прямо в нём, импортируете модули, и они вживую встраиваются в приложение. Без перезагрузки. Магия? Нет, SharedWorker.
🔸 Самое безумное:
Вы можете открыть компонент и буквально вытащить его в другое окно браузера. Не создать копию. Не открыть iframe. А переместить тот же самый JS-объект! Открыли три окна? Они все синхронизированы, делят состояние, работают как один организм.
И вот кульминация: production-версия приложения (минифицированная, оптимизированная) и development-код из редактора работают одновременно в одном SharedWorker, не конфликтуя. До недавнего времени это было технически невозможно.
🔸 Почему это важно?
Потому что main thread свободен. Пока другие фреймворки душат браузер вычислениями, Neo.mjs спокойно выдаёт 60 FPS, потому что вся тяжёлая работа в воркере. Плюс экономия трафика — для корпораций с тысячами пользователей это реальные деньги.
Откройте демо, покликайте по навигации. Переходы мгновенные. А ведь страницы генерируются прямо сейчас, на ваших глазах.
Код открыт, MIT-лицензия. И да, там спрятан секретный режим "cube layout". Просто потому что можно 😎
Демо | GitHub
📎 Статья
🎙 Новости
📝 База вопросов
Знаете, что делает большинство фреймворков? Они генерируют HTML на сервере, отправляют его вам, а потом начинают танцы с бубном под названием "гидратация". Тяжело, медленно, дорого.
А разработчик Neo.mjs подумал: "А что если вообще не отправлять HTML?"
И сделал приложение, которое стартует с пустым body. Звучит дико?
Браузер получает крошечные JS-генераторы, кэширует их один раз, и всё. Дальше с сервера летит только лёгкий JSON с данными — никакого HTML-мусора. Генераторы строят интерфейс на лету, и навигация работает так быстро, что кажется, будто страницы уже загружены.
Внутри этого приложения живёт редактор Monaco — 3 мегабайта кода из VSCode. Обычно такой монстр хоронит любые метрики производительности. Но здесь он летает. Более того — вы пишете код прямо в нём, импортируете модули, и они вживую встраиваются в приложение. Без перезагрузки. Магия? Нет, SharedWorker.
Вы можете открыть компонент и буквально вытащить его в другое окно браузера. Не создать копию. Не открыть iframe. А переместить тот же самый JS-объект! Открыли три окна? Они все синхронизированы, делят состояние, работают как один организм.
И вот кульминация: production-версия приложения (минифицированная, оптимизированная) и development-код из редактора работают одновременно в одном SharedWorker, не конфликтуя. До недавнего времени это было технически невозможно.
Потому что main thread свободен. Пока другие фреймворки душат браузер вычислениями, Neo.mjs спокойно выдаёт 60 FPS, потому что вся тяжёлая работа в воркере. Плюс экономия трафика — для корпораций с тысячами пользователей это реальные деньги.
Откройте демо, покликайте по навигации. Переходы мгновенные. А ведь страницы генерируются прямо сейчас, на ваших глазах.
Код открыт, MIT-лицензия. И да, там спрятан секретный режим "cube layout". Просто потому что можно 😎
Демо | GitHub
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
#Cloudflare
🔖 Cloudflare запустила свой стейблкоин для AI-агентов
Cloudflare представила Net Dollar — криптовалюту, привязанную к доллару 1:1. Но это не очередной стейблкоин для трейдеров, а инфраструктура для "экономики агентов".
🔸 Зачем это нужно?
Идея в том, что AI-агенты смогут совершать платежи автоматически: покупать билеты, когда цена упала, оплачивать API-запросы или заказывать продукты. Всё это — без участия человека и мгновенно.
Cloudflare считает, что традиционные банковские переводы слишком медленные для такого сценария. Net Dollar обещает:
🔸 Что говорит CEO:
"Десятилетиями интернет жил на рекламе и банковских переводах. Следующая эра — это оплата по факту использования и микротранзакции", — Мэтью Принс.
🔸 Скептически:
Вопрос в том, нужен ли для этого ещё один стейблкоин, или это решение в поисках проблемы. Пока что AI-агенты с кошельками звучат как концепция из далёкого будущего.
🔸 Бонус: на прошлой неделе Cloudflare также анонсировала свой email-сервис — Cloudflare Email Service, который объединит отправку и маршрутизацию писем в одном интерфейсе.
📎 Статья
🎙 Новости
📝 База вопросов
Cloudflare представила Net Dollar — криптовалюту, привязанную к доллару 1:1. Но это не очередной стейблкоин для трейдеров, а инфраструктура для "экономики агентов".
Идея в том, что AI-агенты смогут совершать платежи автоматически: покупать билеты, когда цена упала, оплачивать API-запросы или заказывать продукты. Всё это — без участия человека и мгновенно.
Cloudflare считает, что традиционные банковские переводы слишком медленные для такого сценария. Net Dollar обещает:
• Платежи из любой точки мира
• Мгновенные микротранзакции
• Новую модель монетизации для разработчиков
"Десятилетиями интернет жил на рекламе и банковских переводах. Следующая эра — это оплата по факту использования и микротранзакции", — Мэтью Принс.
Вопрос в том, нужен ли для этого ещё один стейблкоин, или это решение в поисках проблемы. Пока что AI-агенты с кошельками звучат как концепция из далёкого будущего.
Please open Telegram to view this post
VIEW IN TELEGRAM
#GitHub
🔖 Рабочий процесс на GitHub: как работать профессионально
Работа в команде требует чёткой организации. Разбираем ключевые этапы GitHub workflow — от создания issue до слияния кода.
🔸 1. Issues — начало всего
Формулируем задачи по шаблону:
Крупные задачи разбиваем на подзадачи с префиксом
🔸 2. Ветки
Создаём ветку отдельно от main, чтобы ошибки не попали в продакшн. GitHub позволяет привязать issue к ветке — после мержа проблема закроется автоматически.
Формат именования:
🔸 3. Коммиты
Правила хорошего коммита:
• Коммитим часто, не ждём завершения всей фичи
• Пишем понятные сообщения до 50 символов
• Используем настоящее время и повелительное наклонение
Примеры:
Для монорепозиториев добавляем scope:
🔸 4. Pull Request
После пуша создаём PR. Название должно отражать ветку без номера issue:
Добавляем описание, связываем с issue, назначаем ревьюверов, ставим метки (bug, feature, enhancement).
🔸 5. Code Review
Рекомендуется минимум 2 ревьювера на каждый PR. Это помогает найти больше проблем и делиться знаниями внутри команды.
🔸 6. Merge
После аппрува мержим PR — связанная issue закроется автоматически. Не забываем удалить ветку, чтобы держать репо в чистоте.
✔️ Итого:
Issue → Branch → Commits → PR → Review → Merge
Полезные типы:
feat, style, fix, enhance, refactor, docs
Scope'ы для монорепо:
front, back, api, db, docs, test, chore
Лайфхак: используйте Git-хук
Поначалу кажется сложно, но быстро входит в привычку.
📎 Статья
🎙 Новости
📝 База вопросов
Работа в команде требует чёткой организации. Разбираем ключевые этапы GitHub workflow — от создания issue до слияния кода.
Формулируем задачи по шаблону:
[FIX]: Fix auth flow
[STYLE]: Improve login page styling
[FEATURE]: Implement admin dashboard
Крупные задачи разбиваем на подзадачи с префиксом
[SUB-FEAT].Создаём ветку отдельно от main, чтобы ошибки не попали в продакшн. GitHub позволяет привязать issue к ветке — после мержа проблема закроется автоматически.
Формат именования:
<type>/<issue-number>/<short-description>
fix/92/fix_auth_flow
feature/15/implement_dashboard
Правила хорошего коммита:
• Коммитим часто, не ждём завершения всей фичи
• Пишем понятные сообщения до 50 символов
• Используем настоящее время и повелительное наклонение
Примеры:
feat: implement dashboard header
fix: fix data fetching
refactor: improve API readability
Для монорепозиториев добавляем scope:
feat(front): implement dashboard header
feat(back): implement dashboard APIs
После пуша создаём PR. Название должно отражать ветку без номера issue:
feature/implement-dashboard
style/improve-login-page-styling
Добавляем описание, связываем с issue, назначаем ревьюверов, ставим метки (bug, feature, enhancement).
Рекомендуется минимум 2 ревьювера на каждый PR. Это помогает найти больше проблем и делиться знаниями внутри команды.
После аппрува мержим PR — связанная issue закроется автоматически. Не забываем удалить ветку, чтобы держать репо в чистоте.
Issue → Branch → Commits → PR → Review → Merge
Полезные типы:
feat, style, fix, enhance, refactor, docs
Scope'ы для монорепо:
front, back, api, db, docs, test, chore
Лайфхак: используйте Git-хук
pre-commit для автоматической проверки формата коммитов.Поначалу кажется сложно, но быстро входит в привычку.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
This media is not supported in your browser
VIEW IN TELEGRAM
#Video
🔖 Улучшение воспроизведения видео с помощью ExoPlayer
Команда Reddit поделилась практическими советами по оптимизации видео на Android, подкреплёнными реальными production-данными. Разбираем ключевые находки.
🔸 Доставка контента: MP4 vs DASH
75% видео на Reddit длятся менее 45 секунд. Команда провела эксперимент: для коротких роликов заменили адаптивный DASH на обычный MP4.
Результаты для видео < 45 сек:
• Ошибки воспроизведения: -5,5%
• Выход до старта видео: -2,5%
• Общие просмотры: +1,7%
Вывод: для короткого контента адаптивные протоколы избыточны — MP4 быстрее и надёжнее.
🔸 Кэширование: подводные камни
Проблемы SimpleCache:
• ExternalDir недоступен везде (например, на OPPO) — лучше использовать internalDir
• Может удалять другие файлы — нужна отдельная папка
• Бьёт по диску в конструкторе — создавайте в фоновом потоке
• URL как ключ — если у вас разные сигнатуры, нужна своя фабрика ключей
🔸 Предзагрузка контента
Протестировали варианты: следующее видео, два параллельно, только MP4. Лучше всего сработала предзагрузка только следующего видео:
• Загрузка < 500ms: +1,9%
• Загрузка > 1000ms: -0,872%
Попытка учитывать пропускную способность (2-20 Мбит/с) провалилась — метрики ухудшились.
🔸 LoadControl: настройка буферизации
По умолчанию значения буфера в ExoPlayer слишком большие для коротких видео. Reddit снизил:
•
•
Результаты:
• Загрузка < 250ms: +2,7%
• Загрузка < 500ms: +4,4%
• Загрузка > 1000ms: -11,9%
• Ребуферинг: -4,8%
• Общие просмотры: +1,5%
Самый впечатляющий эксперимент!
🔸 BandwidthMeter и адаптивный битрейт
Проблема: предзагрузка через DownloadManager не учитывалась в общей пропускной способности. После фикса:
• Разрешение видео: +1,4%
• Просмотры в цепочке: +0,5%
• Смена битрейта: -0,5%
• Загрузка > 1000ms: +0,3% (компромисс)
🔸 Декодеры
Ошибка 4001 (декодер недоступен) — частая проблема. Решения:
• Включить fallback на программный декодер
• Запрашивать audio focus явно
• Рассмотреть пул плееров или один экземпляр
Fallback снизил ошибки на 0,9%.
🔸 Рендеринг: SurfaceView vs TextureView
SurfaceView эффективнее (рендерит на GPU напрямую), но до Android N были проблемы с анимациями.
В Compose постоянное re-inflation занимало до 30ms. Решение — собственный ViewPool:
• Загрузка < 250ms: +1,7%
• Просмотренные минуты: +1,4%
• P50 создания: улучшено в 30 раз (1ms)
🔸 Ключевой вывод
Всё упирается в аналитику и A/B-тесты. Обязательные метрики:
• Время до первого кадра
• Ребуферинг
• Старт/стоп воспроизведения
• Ошибки
ExoPlayer предоставляет
📎 Статья
🎙 Новости
📝 База вопросов
Команда Reddit поделилась практическими советами по оптимизации видео на Android, подкреплёнными реальными production-данными. Разбираем ключевые находки.
75% видео на Reddit длятся менее 45 секунд. Команда провела эксперимент: для коротких роликов заменили адаптивный DASH на обычный MP4.
Результаты для видео < 45 сек:
• Ошибки воспроизведения: -5,5%
• Выход до старта видео: -2,5%
• Общие просмотры: +1,7%
Вывод: для короткого контента адаптивные протоколы избыточны — MP4 быстрее и надёжнее.
Проблемы SimpleCache:
• ExternalDir недоступен везде (например, на OPPO) — лучше использовать internalDir
• Может удалять другие файлы — нужна отдельная папка
• Бьёт по диску в конструкторе — создавайте в фоновом потоке
• URL как ключ — если у вас разные сигнатуры, нужна своя фабрика ключей
Протестировали варианты: следующее видео, два параллельно, только MP4. Лучше всего сработала предзагрузка только следующего видео:
• Загрузка < 500ms: +1,9%
• Загрузка > 1000ms: -0,872%
Попытка учитывать пропускную способность (2-20 Мбит/с) провалилась — метрики ухудшились.
По умолчанию значения буфера в ExoPlayer слишком большие для коротких видео. Reddit снизил:
•
bufferForPlaybackAfterRebufferMs: 1000ms•
minBuffer и maxBuffer: 20000msРезультаты:
• Загрузка < 250ms: +2,7%
• Загрузка < 500ms: +4,4%
• Загрузка > 1000ms: -11,9%
• Ребуферинг: -4,8%
• Общие просмотры: +1,5%
Самый впечатляющий эксперимент!
Проблема: предзагрузка через DownloadManager не учитывалась в общей пропускной способности. После фикса:
• Разрешение видео: +1,4%
• Просмотры в цепочке: +0,5%
• Смена битрейта: -0,5%
• Загрузка > 1000ms: +0,3% (компромисс)
Ошибка 4001 (декодер недоступен) — частая проблема. Решения:
• Включить fallback на программный декодер
• Запрашивать audio focus явно
• Рассмотреть пул плееров или один экземпляр
Fallback снизил ошибки на 0,9%.
SurfaceView эффективнее (рендерит на GPU напрямую), но до Android N были проблемы с анимациями.
В Compose постоянное re-inflation занимало до 30ms. Решение — собственный ViewPool:
• Загрузка < 250ms: +1,7%
• Просмотренные минуты: +1,4%
• P50 создания: улучшено в 30 раз (1ms)
Всё упирается в аналитику и A/B-тесты. Обязательные метрики:
• Время до первого кадра
• Ребуферинг
• Старт/стоп воспроизведения
• Ошибки
ExoPlayer предоставляет
AnalyticsListener для трекинга.Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
Forwarded from YeaHub
🚀 Прокачиваем подготовку к собеседованиям на максимум!
Если ты ещё не заглядывал(а) в👍 «Авось Прорвёмся» — самое время.
Это проект Ани для самостоятельной подготовки, где есть:
- 1000+ записей реальных собеседований с разбором задач и вопросов;
- контакты рекрутеров;
- гайды по резюме, трудоустройству и стратегиям поиска работы.
- задачи и вопросы с собеседований
Мы в YeaHub продолжаем добавлять собеседования из этих чатов — теперь их можно проходить в тренажёре, тренируя ответы на реальные вопросы работодателей.
🎧 Сначала слушай, как проходят настоящие собесы,
💡 потом — разбирай и практикуй те же кейсы в тренажёре.
Направления: iOS, Android, Frontend, Python, Go, Java, C#, QA, Analytics.
👉 Обучайтесь, общайтесь, растите вместе с YeaHub и Авось Прорвемся
Если ты ещё не заглядывал(а) в
Это проект Ани для самостоятельной подготовки, где есть:
- 1000+ записей реальных собеседований с разбором задач и вопросов;
- контакты рекрутеров;
- гайды по резюме, трудоустройству и стратегиям поиска работы.
- задачи и вопросы с собеседований
Мы в YeaHub продолжаем добавлять собеседования из этих чатов — теперь их можно проходить в тренажёре, тренируя ответы на реальные вопросы работодателей.
🎧 Сначала слушай, как проходят настоящие собесы,
💡 потом — разбирай и практикуй те же кейсы в тренажёре.
Направления: iOS, Android, Frontend, Python, Go, Java, C#, QA, Analytics.
👉 Обучайтесь, общайтесь, растите вместе с YeaHub и Авось Прорвемся
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3🔥3🤝3
#MachineLearning
🔖 Как Random Forest вычисляет продавцов-мошенников на маркетплейсах
Автор столкнулась с обманом на маркетплейсе и решила разобраться: можно ли с помощью ML выявлять мошенников до того, как они обманут покупателей?
🔸 Данные
Набор данных с Kaggle содержит информацию о продавцах C2C-платформы: подписчики, активность, количество товаров, давность входа. Целевая переменная
Проблема: датасет несбалансирован — среднее значение
🔸 Построение модели
Используется Random Forest с GridSearchCV для подбора гиперпараметров. Ключевой момент — параметр
Метрика оптимизации — ROC AUC score.
Первый запуск:
Результат показал, что
Второй запуск:
Лучшие параметры оказались внутри диапазона — модель найдена.
Результат: Recall для класса 1.0 (мошенники) = 69.77%
Недостаточно для production!
🔸 Оптимизация порога
Автор предлагает сместить акцент с точности на полноту (Recall). Логика:
Два типа ошибок:
- False Negative: пропустили мошенника (опасно!)
- False Positive: заблокировали честного продавца (менее критично)
Лучше заблокировать несколько честных продавцов, чем пропустить мошенника — на маркетплейсе всегда много альтернатив.
ROC-кривая в 3D
Построена интерактивная 3D ROC-кривая с осями:
- X: False Positive Rate
- Y: True Positive Rate
- Z: Probability Threshold
Автор отмечает три точки компромисса:
Красная черта: FPR ≈ 36%, порог = 0.35
Оранжевая: FPR ≈ 50%, порог = 0.25
Зелёная: FPR ≈ 60%, порог = 0.20
Выбор зависит от толерантности к ложным срабатываниям. Автор выбрала зелёную (порог 0.20) как оптимальную.
🔸 Финальные результаты
После сдвига порога до 0.20:
Recall для класса 1.0 = 90.11%
Прирост с 69.77% до 90.11% — модель теперь обнаруживает 9 из 10 мошенников!
🔸 Ключевые выводы
1. Дисбаланс классов решается через
2. GridSearchCV помогает найти оптимальные гиперпараметры
3. Сдвиг порога критически важен для несбалансированных задач
4. ROC-кривая в 3D — удобный инструмент для выбора порога
5. Бизнес-логика важнее технических метрик: лучше больше FP, чем FN
Практическое применение:
Маркетплейс может использовать эту модель для:
- Автоматической проверки новых продавцов
- Дополнительной верификации подозрительных аккаунтов
- Приоритизации ручных проверок
Конечно, 10% мошенников всё равно проскочат, но это огромный прогресс для защиты покупателей.
📎 Статья
🎙 Новости
📝 База вопросов
Автор столкнулась с обманом на маркетплейсе и решила разобраться: можно ли с помощью ML выявлять мошенников до того, как они обманут покупателей?
Набор данных с Kaggle содержит информацию о продавцах C2C-платформы: подписчики, активность, количество товаров, давность входа. Целевая переменная
Fraud (1 = мошенник) добавлена на основе несоответствия отправленного товара описанию.Проблема: датасет несбалансирован — среднее значение
Fraud меньше 0.5, что означает перекос в сторону честных продавцов.Используется Random Forest с GridSearchCV для подбора гиперпараметров. Ключевой момент — параметр
class_weight: ['balanced', 'balanced_subsample'] для борьбы с дисбалансом классов.Метрика оптимизации — ROC AUC score.
Первый запуск:
paramdict = {
'criterion': ['gini','entropy'],
'min_samples_leaf': range(1,5),
'class_weight': ['balanced','balanced_subsample'],
...
}Результат показал, что
min_samples_leaf=4 (верхняя граница диапазона) — нужно расширить поиск.Второй запуск:
'min_samples_leaf': range(4,10)
Лучшие параметры оказались внутри диапазона — модель найдена.
Результат: Recall для класса 1.0 (мошенники) = 69.77%
Недостаточно для production!
Автор предлагает сместить акцент с точности на полноту (Recall). Логика:
Два типа ошибок:
- False Negative: пропустили мошенника (опасно!)
- False Positive: заблокировали честного продавца (менее критично)
Лучше заблокировать несколько честных продавцов, чем пропустить мошенника — на маркетплейсе всегда много альтернатив.
ROC-кривая в 3D
Построена интерактивная 3D ROC-кривая с осями:
- X: False Positive Rate
- Y: True Positive Rate
- Z: Probability Threshold
Автор отмечает три точки компромисса:
Красная черта: FPR ≈ 36%, порог = 0.35
Оранжевая: FPR ≈ 50%, порог = 0.25
Зелёная: FPR ≈ 60%, порог = 0.20
Выбор зависит от толерантности к ложным срабатываниям. Автор выбрала зелёную (порог 0.20) как оптимальную.
После сдвига порога до 0.20:
Recall для класса 1.0 = 90.11%
Прирост с 69.77% до 90.11% — модель теперь обнаруживает 9 из 10 мошенников!
1. Дисбаланс классов решается через
class_weight='balanced'2. GridSearchCV помогает найти оптимальные гиперпараметры
3. Сдвиг порога критически важен для несбалансированных задач
4. ROC-кривая в 3D — удобный инструмент для выбора порога
5. Бизнес-логика важнее технических метрик: лучше больше FP, чем FN
Практическое применение:
Маркетплейс может использовать эту модель для:
- Автоматической проверки новых продавцов
- Дополнительной верификации подозрительных аккаунтов
- Приоритизации ручных проверок
Конечно, 10% мошенников всё равно проскочат, но это огромный прогресс для защиты покупателей.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Создаём систему, которая транскрибирует речь с микрофона в текст в режиме реального времени, с автоматической расстановкой знаков препинания и заглавных букв.
Каждую секунду микрофон передаёт аудио в AssemblyAI, которая распознаёт речь пословно. По завершении предложения ИИ понимает смысл и добавляет пунктуацию.
pip install pyaudio
pip install websockets
Mac:
brew install portaudio — всё настроится автоматическиWindows: Скачайте wheel-файл с [неофициального сайта Python](https://www.lfd.uci.edu/~gohlke/pythonlibs/), затем:
pip install pyaudio‑0.2.11‑cp39‑cp39‑win_amd64.whl
Импорты:
import websockets
import asyncio
import base64
import json
from configure import auth_key
import pyaudio
Создайте файл
configure.py:auth_key = 'ваш_API_ключ_из_AssemblyAI'
Ключ можно получить на сайте AssemblyAI. Для real-time транскрибации нужен платный план.
FRAMES_PER_BUFFER = 3200
FORMAT = pyaudio.paInt16
CHANNELS = 1
RATE = 16000
p = pyaudio.PyAudio()
stream = p.open(
format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=FRAMES_PER_BUFFER
)
URL = "wss://api.assemblyai.com/v2/realtime/ws?sample_rate=16000"
Частота дискретизации 16000 синхронизирована с AssemblyAI API.
Главная функция подключения:
async def send_receive():
async with websockets.connect(
URL,
extra_headers=(("Authorization", auth_key),),
ping_interval=5,
ping_timeout=20
) as _ws:
session_begins = await _ws.recv()
print(session_begins)
Функция отправки аудио:
async def send():
while True:
try:
data = stream.read(FRAMES_PER_BUFFER)
data = base64.b64encode(data).decode("utf-8")
json_data = json.dumps({"audio_data": str(data)})
await _ws.send(json_data)
except websockets.exceptions.ConnectionClosedError as e:
break
await asyncio.sleep(0.01)
return True
Функция получения текста:
async def receive():
while True:
try:
result_str = await _ws.recv()
print(json.loads(result_str)['text'])
except websockets.exceptions.ConnectionClosedError as e:
break
send_result, receive_result = await asyncio.gather(send(), receive())
while True:
asyncio.run(send_receive())
Запустите командой:
python speech_recognition.py
1. Микрофон захватывает аудио каждые 3200 фреймов
2. Аудио кодируется в base64 и отправляется через WebSocket
3. AssemblyAI транскрибирует в реальном времени
4. Получаете два типа результатов:
- Частичные: посекундная транскрипция
- Финальные: с заглавными буквами и пунктуацией
Пример вывода:
hello
hello world
hello world this
Hello world, this is a test.
- ИИ автоматически форматирует предложения
- Добавляет знаки препинания
- Исправляет грамматику
- Работает в реальном времени с минимальной задержкой
- pyAudio — захват аудио с микрофона
- websockets — двусторонняя связь с API
- asyncio — асинхронная обработка
- AssemblyAI — ML-движок для распознавания речи
С развитием ИИ создание таких систем стало гораздо проще. Раньше точное распознавание речи было сложной задачей, теперь это реализуется несколькими десятками строк кода.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Пакеты NPM — компоненты многократно используемого кода, которые делают JavaScript-разработку более управляемой. Разбираемся в истории, преимуществах и сценариях использования.
Пакет NPM — многократно используемый код JavaScript, которым можно делиться через реестр NPM. От простых утилит до полноценных фреймворков.
Ключевые особенности:
• Многократное использование — написал один раз, используй везде
• Контроль версий через семантическое версионирование (1.0.0)
• Совместная работа через публичный реестр
Начальный период (до 2009):
• Copy-paste — копировали код с форумов, что вело к несоответствиям
• Ручная загрузка — скачивали jQuery с сайта и подключали через
<script>• Git-репозитории — клонировали вручную, управляли зависимостями самостоятельно
• Браузерные войны — адаптировали код под IE или Netscape
Рождение NPM (2009):
Выход Node.js позволил JavaScript работать на серверах. Появилась потребность в эффективном обмене кодом. NPM решил проблему:
• Централизованный реестр пакетов
• Простая установка:
npm install <package-name>• Автоматическое управление зависимостями
1. Многократное использование
Если код решает общую проблему в нескольких проектах:
// Валидатор email
function isValidEmail(email) {
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return regex.test(email);
}
// Публикуем как пакет
npm install my-email-validator
2. Межкомандное сотрудничество
Для больших организаций, где фронтенд, бэкенд и мобильные команды используют общий код:
// Общие типы TypeScript
export type User = {
id: string;
name: string;
email: string;
};
npm install @company/shared-types
3. Вклад в open source
Публикация помогает другим разработчикам и укрепляет вашу репутацию.
4. Заполнение пробела
Если для вашей проблемы нет решения — создайте пакет, который интегрируется со сложным API или форматирует данные уникальным образом.
1. Код слишком специфичен
Скрипт, работающий только с вашей уникальной схемой БД, не имеет смысла публиковать.
2. Слишком простой код
// Слишком просто для пакета
const reverseString = (str) => str.split('').reverse().join('');
Лучше поделиться как фрагментом или включить в существующую библиотеку.
3. Уже есть лучшее решение
Перед созданием проверьте реестр NPM. Зачем дублировать
date-fns?// Ваша функция
function formatDate(date) {
const d = new Date(date);
return `${d.getMonth() + 1}/${d.getDate()}/${d.getFullYear()}`;
}
// Уже есть date-fns
import { format } from "date-fns";
console.log(format(new Date("2023-01-01"), "MM/dd/yyyy"));
4. Нет ресурсов на поддержку
Публикация = обязательства: обновления, исправление багов, поддержка пользователей. Пакет с хакатона, который никто не будет поддерживать, лучше не публиковать.
NPM-пакеты — основа современной JavaScript-разработки. Они позволяют:
• Переиспользовать код
• Обеспечивать консистентность в командах
• Делиться решениями с сообществом
Но помните: не каждый код должен стать пакетом. Оцените масштаб задачи и готовность к долгосрочной поддержке.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1
Современный JavaScript развивается стремительно. Разбираем 6 фич, которые делают код короче и чище.
1. Опциональные цепочки (?.)
Безопасная навигация по объектам без множественных проверок:
const someObject = {
profile: {
firstName: 'Nicky',
lastName: 'Christensen'
}
}
// ✅ С optional chaining
if (someObject?.profile?.firstName) {
console.log(someObject.profile.firstName)
}
// ❌ Старый способ
if (someObject && someObject.profile && someObject.profile.firstName) {
console.log(someObject.profile.firstName)
}
// Не выполнится, если свойства нет
if (someObject?.profile?.name) {
console.log('Not executed')
}2. Оператор нулевого слияния (??)
Возвращает правый операнд только если левый
null или undefined:const falsy = false;
const emptyString = '';
const nullish = null;
console.log(falsy ?? 'Default'); // false
console.log(emptyString ?? 'Default'); // "" (не заменяется!)
console.log(nullish ?? 'Default'); // "Default"
// VS оператор ||
console.log(falsy || 'Default'); // "Default"
console.log(emptyString || 'Default'); // "Default"
console.log(nullish || 'Default'); // "Default"
Преимущество `??`: не заменяет
false, 0 или "" — только null/undefined.3. Динамический импорт
Асинхронная загрузка модулей (code splitting):
let someAsyncModule = await import('/modules/my-module.ts');4. Promise.allSettled()
Узнать результат всех промисов, даже отклонённых:
const promise1 = Promise.resolve("OK");
const promise2 = Promise.reject("Error");
const promise3 = Promise.resolve("Done");
Promise.allSettled([promise1, promise2, promise3])
.then((results) => console.log(results));
// Результат:
// [
// { status: 'fulfilled', value: 'OK' },
// { status: 'rejected', reason: 'Error' },
// { status: 'fulfilled', value: 'Done' }
// ]Отличие от `Promise.all()`: не падает при reject, показывает статус каждого промиса.
5. Spread-оператор (...)
Для массивов:
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const arr3 = [...arr1, ...arr2]; // [1,2,3,4,5,6]
Для объектов:
const basePerson = {
name: 'Nicky C',
country: 'DK'
}
const footballer = {
...basePerson,
team: 'Man UTD',
shirtNumber: '11'
}
// { name: 'Nicky C', country: 'DK', team: 'Man UTD', shirtNumber: '11' }6. Деструктуризация объектов
Распаковка значений из объекта в переменные:
const footballer = {
name: 'Nicky C',
team: 'Man UTD',
shirtNumber: '11'
}
const { team, shirtNumber } = footballer;
console.log(team, shirtNumber); // "Man UTD" "11"- Сокращают код
- Улучшают читаемость
- Снижают количество багов
- Стандарт в современном JavaScript
Используйте уже сегодня!
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2
Зачем моделировать данные, если Snowflake всё обработает сам? Разбираемся на примере.
Проанализировать элементы, которые пользователи видят в списке (товары, результаты поиска, посты в ленте).
Аналитикам нужно:
- Оценить CTR
- Определить влияние позиции (1-я vs 10-я)
Этап 1: Сбор данных
Фронтенд отправляет JSON-событие:
{
"user_id": 3299223,
"event_time": "2022-04-21 12:31:55 UTC",
"items_shown": [1037287139, 1727228887, ..., 1665899805]
}Этап 2: Доставка
API → Kafka/Airbyte/Fivetran → Snowflake → таблица
RAW_EventsЭтап 3: Готово!
Преимущества:
- Не нужно думать о масштабируемости
- Не нужно преобразовывать данные
- JSON работает из коробки
Запрос 1: Развернуть массив
SELECT
user_id,
value::NUMBER as item_id,
index as position
FROM RAW_Events,
LATERAL FLATTEN(input => items_shown)
Запрос 2: Сколько пользователей видели item на позиции 1?
SELECT COUNT(DISTINCT user_id)
FROM (
SELECT user_id, value, index
FROM RAW_Events,
LATERAL FLATTEN(input => items_shown)
)
WHERE value = 1037287139
AND index = 0
AND DATE(event_time) = CURRENT_DATE
- Сложный синтаксис
- Читает ВСЕ JSON из таблицы
- Распаковывает и разворачивает каждый раз
- Медленно и дорого
- При JOIN'ах всё повторяется
Создаём таблицу Events:
CREATE TABLE Events AS
SELECT
user_id,
event_time,
value::NUMBER as item_id,
index as position
FROM RAW_Events,
LATERAL FLATTEN(input => items_shown)
Обновляем инкрементально (ежедневно/ежечасно).
Запрос 4: Тот же вопрос, но проще
SELECT COUNT(DISTINCT user_id)
FROM Events
WHERE item_id = 1037287139
AND position = 0
AND DATE(event_time) = CURRENT_DATE
Запрос 2 (без модели) | 47 сек | X-Small |
Запрос 4 (с моделью) | 0.5 сек | X-Small |
Разница: 94x быстрее!
При миллиардах JSON разница в 1000+ раз по времени и деньгам.
1. Данные достаточно большие
2. Запросы достаточно частые
3. Количество аналитиков ограничено
4. Нужна консистентность результатов
10-20 лет назад: аналитик не мог работать с сотнями миллионов строк без инженера данных.
Сегодня: современный стек позволяет исследовать данные самостоятельно. Моделирование не обязательно, но:
- Ускоряет запросы
- Упрощает SQL
- Снижает затраты
- Повышает производительность
Современный стек даёт свободу. Моделирование даёт скорость.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
Создаём одинаковое приложение на двух языках и сравниваем подходы.
CLI-приложение с 4 командами:
-
list — показать все задачи-
add — добавить задачу-
done — отметить выполненные-
clear — удалить всеФормат хранения:
[ ] заголовок задачи
[*] выполненная задача
pnpm init
Node v20, ESM модули, без сторонних библиотек. Файл
todo.mjs.Добавить задачу:
async function addTodo(filePath, todoTitle) {
return await useTodoFile(filePath, async (fd) => {
fd.appendFile(`[ ] ${todoTitle}\n`)
})
}Форматированный список:
async function formattedTodos(filePath) {
return await useTodoFile(filePath, async (fd) => {
const content = await fd.readFile('utf8')
return content
.split('\n')
.filter((title) => title)
.map((title, index) => {
const isDone = /^\[\*\]/.test(title)
const rawTitle = title.match(/^\[[\s*]\]\s(.+)/)?.[1]
return `${index + 1} ${isDone ? strikethrough(rawTitle) : rawTitle}`
})
.join('\n')
})
}Отметить выполненной:
async function markDone(filePath, ids) {
return await useTodoFile(filePath, async (fd) => {
const content = await fd.readFile('utf8')
const lines = content.split('\n')
ids.forEach((id) => {
lines[id - 1] = lines[id - 1].replace(/^\[\s\]/, '[*]')
})
await fd.truncate()
await fd.writeFile(lines.join('\n'))
})
}gleam new gleam_todos
gleam add argv simplifile gleam_community_ansi
Добавить задачу:
pub fn add_todo(file_path: String, title: String) -> Result(Nil, Nil) {
simplifile.append(file_path, "[ ] " <> title <> "\n")
|> result.replace(Nil)
|> result.nil_error
}Форматированный список:
pub fn formatted_todos(file_path: String) -> Result(String, Nil) {
simplifile.read(file_path)
|> result.map(split_to_lines)
|> result.map(format_todo_lines)
|> result.map(join_lines)
|> result.nil_error
}
fn format_todo_lines(lines: List(String)) -> List(String) {
list.index_map(lines, fn(line, index) {
case line {
"[ ] " <> rest -> int.to_string(index + 1) <> " " <> rest
"[*] " <> rest -> int.to_string(index + 1) <> " " <> ansi.strikethrough(rest)
_ -> line
}
})
}Отметить выполненной:
pub fn mark_done(file_path: String, ids: List(Int)) -> Result(Nil, Nil) {
simplifile.read(file_path)
|> result.map(split_to_lines)
|> result.map(fn(lines) { mark_todo_done(lines, ids) })
|> result.map(join_lines)
|> result.try(fn(content) { simplifile.write(file_path, content) })
|> result.nil_error
}JavaScript:
node todo.mjs add "first todo"
node todo.mjs list
Gleam:
gleam run add "first todo"
gleam run list
Итог
JavaScript:
-
-
-
-
Gleam:
-
-
-
-
|> для цепочек операций-
Автор предпочитает Gleam за красивый код, мощную обработку ошибок и простые зависимости.
Gleam код читается как описание того, что делает программа, а не как она это делает.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
Массивы — фундаментальные структуры данных C++. Разбираем эффективные способы их вывода для отладки и визуализации.
void printArray(int arr[], int size) {
for (int i = 0; i < size; i++) {
std::cout << arr[i];
if (i < size - 1) std::cout << ", ";
}
}for (int i : std::array<int, 5>{arr, arr + size}) {
std::cout << i << " ";
}std::copy(arr, arr + N,
std::ostream_iterator<T>(std::cout, ", "));
void print2DArray(int arr[][3], int rows, int cols) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
std::cout << arr[i][j] << " ";
}
std::cout << std::endl;
}
}Вложенные циклы для матриц.
template<typename T, size_t N>
void printArray(const std::array<T, N>& arr) {
for (size_t i = 0; i < N; ++i) {
std::cout << arr[i];
if (i < N - 1) std::cout << ", ";
}
}
struct Person {
std::string name;
int age;
friend std::ostream& operator<<(
std::ostream& os, const Person& p) {
return os << p.name << " (" << p.age << ")";
}
};Переопределяем
operator<< для кастомных объектов.struct SensorReading {
double temperature;
double humidity;
friend std::ostream& operator<<(
std::ostream& os, const SensorReading& sr) {
return os << "Temp: " << sr.temperature
<< "°C, Humidity: "
<< sr.humidity << "%";
}
};• Простой for — полный контроль
• Range-based — современный код
• std::copy — STL-стиль
• std::array — фиксированный размер
• operator<< — свои типы
Эффективный вывод массива — это представление данных в понятном формате для отладки, анализа и работы с пользователем.
Please open Telegram to view this post
VIEW IN TELEGRAM
Написание CSS с нуля отнимает много времени. Эти бесплатные инструменты помогут ускорить разработку и повысить продуктивность.
Генератор модного стиля "мягкого UI". Создаёт плавные тени и объёмные элементы.
Настройки:
Автоматическая генерация CSS-кода для неоморфного дизайна.
Создание сложных фигур без знания свойства
clip-path:Визуальный редактор + готовый CSS-код.
Коллекция готовой CSS-анимации:
Выбираете анимацию → редактируете → копируете код.
Удаление неиспользуемого CSS-кода.
Зачем нужен:
Особенно полезен с Bootstrap, Tailwind и другими фреймворками.
Генератор плавных теней.
Настройки:
Создаёт реалистичные многослойные тени одним кликом.
Создание градиентных фонов:
Визуальный редактор + копирование кода.
Премиум-инструмент для просмотра CSS любого элемента.
Возможности:
Идеально для изучения чужого кода и поиска вдохновения.
Генератор макетов CSS Grid.
Настройки:
Получаете CSS + HTML-код сетки.
Создание SVG-волн для фона.
Параметры:
Готовый SVG + CSS для вставки в проект.
Итог
Эти инструменты:
Используйте их для быстрого создания красивых страниц без написания CSS с нуля.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
Команда Whitespectre создала библиотеку rn-modal-presenter для решения проблем с множественными модальными окнами в React Native.
1. Управление состояниями — нужна переменная для каждого модального окна
2. iOS ограничение — нельзя показать >1 модального окна одновременно
3. Размонтирование — при навигации модалки исчезают
4. Тихие ошибки — вторая модалка не появляется без предупреждений
Пример проблемы:
const App = () => {
const [showRateAppModal, setShowRateAppModal] = useState(false);
const [showAppRatedPositiveModal, setShowAppRatedPositiveModal] = useState(false);
const [showAppRatedNegativeModal, setShowAppRatedNegativeModal] = useState(false);
const [showActivateGadgetModal, setShowActivateGadgetModal] = useState(false);
return (
<SafeAreaView>
{showActivateGadgetModal && <ActivateGadgetModal />}
{showRateAppModal && <RateAppModal />}
{showAppRatedPositiveModal && <PositiveFeedbackModal />}
{showAppRatedNegativeModal && <NegativeFeedbackModal />}
</SafeAreaView>
);
};Проблемы:
Почему сторонние библиотеки не помогли
react-native-modal:
react-native-modalfy:
Преимущества:
1. Императивный API — вызов из любого места
2. Без состояний — не нужны useState
3. Множественные модалки — из коробки
4. Гибкость — любой компонент как модалка
5. 100% JavaScript — работает кроссплатформенно
Установка:
yarn add @whitespectre/rn-modal-presenter
Использование:
import { ModalPresenterParent, showModal } from '@whitespectre/rn-modal-presenter';
const App = () => (
<ModalPresenterParent>
<SafeAreaView>
<Button
title="Activate Gadget"
onPress={() => showModal(ActivateGadgetModal, {})}
/>
</SafeAreaView>
</ModalPresenterParent>
);Модалка управляет собой:
const ActivateGadgetModal = ({dismiss}: ModalContentProps) => (
<View style={styles.modal}>
<Text>Your Gadget has been activated</Text>
<Button
title="Close"
onPress={() => {
dismiss();
showModal(RateAppModal, {});
}}
/>
</View>
);Сравнение подходов
Standard Modal:
react-native-modal:
react-native-modalfy:
rn-modal-presenter:
Планы развития
Итог
rn-modal-presenter упрощает работу с множественными модальными окнами, убирая управление состояниями и предоставляя императивный API. Идеально для сложных флоу с несколькими последовательными модалками.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
Сортировка строк — фундаментальная операция в программировании. Разбираем все методы от базовых до продвинутых.
#include <algorithm>
#include <string>
std::string str = "zycbwvutsrqponmlkjihgfedcba";
std::sort(str.begin(), str.end());
// Результат: "abcdefghijklmnopqrstuvwxyz"
Символы сортируются по значениям ASCII в порядке возрастания.
std::vector<std::string> words = {"banana", "apple", "cherry", "date"};
std::sort(words.begin(), words.end());
// Результат:
// apple
// banana
// cherry
// dateЛексикографическая сортировка (словарный порядок).
bool case_insensitive_compare(const std::string& a, const std::string& b) {
return std::lexicographical_compare(
a.begin(), a.end(),
b.begin(), b.end(),
[](char a, char b) {
return std::tolower(a) < std::tolower(b);
}
);
}
std::vector<std::string> words = {"Banana", "apple", "Cherry", "date"};
std::sort(words.begin(), words.end(), case_insensitive_compare);
// Результат:
// apple
// Banana
// Cherry
// dateПользовательский компаратор игнорирует регистр, но сохраняет исходное написание.
std::vector<std::string> words = {"short", "very long string", "medium"};
std::sort(words.begin(), words.end(),
[](const std::string& a, const std::string& b) {
return a.length() < b.length();
});
// Результат:
// short
// medium
// very long stringЛямбда-функция сравнивает длину строк.
struct Name {
std::string first;
std::string last;
};
std::sort(names.begin(), names.end(),
[](const Name& a, const Name& b) {
if (a.last != b.last) {
return a.last < b.last;
}
return a.first < b.first;
});
// Входные данные:
// John Doe, Jane Doe, Alice Smith, Bob Johnson
// Результат:
// Jane Doe
// John Doe
// Bob Johnson
// Alice SmithМногокритериальная сортировка: сначала по фамилии, затем по имени.
#include <unicode/coll.h>
bool compare_unicode(const std::string& a, const std::string& b) {
UErrorCode status = U_ZERO_ERROR;
icu::Collator* collator = icu::Collator::createInstance(icu::Locale(""), status);
icu::UnicodeString ua = icu::UnicodeString::fromUTF8(a);
icu::UnicodeString ub = icu::UnicodeString::fromUTF8(b);
UCollationResult result = collator->compare(ua, ub, status);
delete collator;
return result == UCOL_LESS;
}
std::vector<std::string> words = {"café", "cafe", "résumé", "resume"};
std::sort(words.begin(), words.end(), compare_unicode);
Корректная обработка диакритических знаков.
1. std::string_view
Избегайте копирования для строк только для чтения.
2. std::stable_sort
Сохраняет относительный порядок эквивалентных элементов.
3. Параллельная сортировка (C++17+)
Для больших наборов данных.
Бенчмарк:
100,000 строк по 10 символов:
• std::sort: 0.245 сек
• std::stable_sort: 0.298 сек
Простая сортировка:
→ std::sort
Без учёта регистра: → Кастомный компаратор
По длине: → Лямбда-функция
Unicode: → ICU библиотека
Сохранить порядок: → std::stable_sort
Большие данные: → Параллельная сортировка (C++17+)
Итог
Сортировка строк в C++ — от базовой лексикографической до сложной многокритериальной — позволяет эффективно обрабатывать любые задачи.
Выбирайте метод исходя из требований: регистр, Unicode, критерии, производительность.
Please open Telegram to view this post
VIEW IN TELEGRAM