Перейти к содержанию
  • Лента
  • Категории
  • Последние
  • Метки
  • Популярные
  • Пользователи
  • Группы
Свернуть
exlends
Категории
  • ru
    Игры
    Образование
    Искусственный Интеллект
    Новости
    Бекенд, разработка серверов
    Фронтенд
    Мобильная разработка
    Языки программирования
    Разработка игр | 3D | 2D
    Базы данных
    CMS
    Системное Администрирование
    Операционные системы
    Маркетинг
    Девайсы
    Сообщество
    Юмор, Мемы

  • en
    Humor
    News
    AI
    Programming languages
    Frontend
    GameDev

  • Блоги

Авторизуйтесь, чтобы написать сообщение

  • Все категории
  • hannadevH
    hannadev
    Object.entries + Map против for: парсинг плоского JSON в группы за 5 строк кода

    API часто кидает плоский JSON - сплошной массив объектов без группировки. Хочешь по категориям разложить - пишешь for на 50 строк с if-ами и push. А можно Object.entries + Map за 3-5 строк. Это решает проблему раздутого кода и утечек в логике.

    Зачем это нужно: группировка ускоряет рендер списков, фильтры и поиск. Без нее фронт тонет в nested циклах. Покажу, как парсить заказы по статусам или товары по брендам - чисто, без костылей.

    Плоский JSON из API: типичная яма

    API возвращает массив заказов: каждый объект с id, status, amount, date. statuses - это ‘pending’, ‘shipped’, ‘delivered’. Хочешь сгруппировать по статусам для дашборда. Ручной for: проверяешь status, пушить в массив группы, нуляешь счетчики. Легко накосячить - забыть else, дубли push или off-by-one в индексах.

    Пример данных:

    const orders = [
      {id:1, status:'pending', amount:100},
      {id:2, status:'shipped', amount:200},
      {id:3, status:'pending', amount:150}
    ];
    

    В итоге groups = {pending: , shipped: […]}. Но код разрастается: if для каждого status, else для default. А если статусов 10? Boilerplate душит.

    • Проблема 1: Ручной for не масштабируется - добавь статус, допиши if.
    • Проблема 2: Легко сломать порядок вставки или пропустить элемент.
    • Проблема 3: Нет size или быстрого .has() - приходится Object.keys().length.
    Подход Строк кода Масштабируемость Ошибки
    for + if 30-50 Плохо Часто
    Map 3-5 Отлично Минимально

    Object.entries: почему это твой новый друг

    Object.entries(obj) выдает [[key, value]] - готовый массив для Map или reduce. Из плоского объекта в итерируемый формат за 1 строку. Идеально для JSON.parse, где ключи строковые, а значения - любые.

    Пример: у тебя конфиг {theme:‘dark’, lang:‘ru’}. entries дает [[‘theme’,‘dark’], [‘lang’,‘ru’]]. Теперь forEach или map - как по масиву. Без entries пришлось бы for…in с hasOwnProperty - легаси 2010-х.

    Ключевой трюк: new Map(Object.entries(flatObj)). Map сохраняет порядок вставки, ключи любого типа (не только строки, как в объекте).

    • entries vs keys: keys() - только ключи, теряешь значения. entries - полная пара.
    • Нюанс: entries не рекурсивно - только own properties, прототипы игнорит.
    • Когда entries выигрывает: группировка, где ключ - динамический (userId, timestamp).
    const config = {theme:'dark', lang:'ru'};
    const mapConfig = new Map(Object.entries(config));
    console.log(mapConfig.get('theme')); // 'dark' - O(1)
    

    Map для группировки: 5 строк вместо 50

    Берем плоский массив orders. Цель: groups = new Map(), где ключ - status, значение - массив заказов. Ручной способ: forEach с if status === ‘pending’ ? groups.pending.push : else if…

    С Map: orders.forEach(order => { const group = groups.get(order.status) || []; group.push(order); groups.set(order.status, group); }). 4 строки. Или one-liner с reduce.

    Полный код:

    const groups = orders.reduce((acc, order) => {
      const group = acc.get(order.status) || [];
      group.push(order);
      acc.set(order.status, group);
      return acc;
    }, new Map());
    

    Map.get/set - быстрее Object[key], особенно с нестроковыми ключами.

    • Преимущество 1: Map сохраняет порядок вставки - первый pending будет первым в массиве.
    • Преимущество 2: .size вместо Object.keys().length - короче, быстрее.
    • Преимущество 3: .delete(key) - чисто удалить группу без undefined.
    Операция Object Map
    Получить размер Object.keys(obj).length obj.size
    Проверить ключ ‘key’ in obj obj.has(‘key’)
    Удалить delete obj.key obj.delete(‘key’)
    Итерация for…in for…of obj.entries()

    Таблица сравнения: for vs entries + Map

    Ручной for хорош для 2-3 групп. Добавь ‘cancelled’, ‘refunded’ - код мутирует в монстра. entries + Map - динамично: статусы из данных, без hardcode.

    Бенчмарк на 10k items: for ~15ms, Map ~12ms. Разница в реальном app - в читаемости и багфиксах. Map не ломается при NaN ключах или Symbol.

    Реальный кейс - парсинг логов API: group by endpoint, count errors.

    • For: if (item.status === ‘error’) errors++; else if…
    • Map трюк: new Map().set(endpoint, (map.get(endpoint)||0) +1 )
    • fromEntries обратно в obj: Object.fromEntries(groups) - для localStorage.
    Сценарий Ручной for Map-вариант Выигрыш
    5 статусов 40 строк 4 строки x10 короче
    Динамические ключи Переписать Работает Без багов
    Фильтр + group Nested loops chain .filter().reduce Читаемо

    Когда Map под капотом ломается

    Map жрет памяти под хеш-таблицу - для 1M items подумай WeakMap. Но для фронта (до 50k) - ок. Не сериализуется в JSON напрямую - stringify(Map) = {}. Фикс: Object.fromEntries(map.entries()).

    Итерация: for (let [status, list] of groups) renderList(list). Порядок как в данных - не как Object.keys (enum order).

    Подведем: entries + Map - антидот boilerplate в парсинге. Осталось за кадром: группировка по нескольким полям (composite key как ${cat}-${brand}) и интеграция с React/Vue keys. Подумай, где в твоем коде висит for на 50 строк - замени, сэкономь час дебага.


    0 0 0 Ответить
  • kirilljsxK
    kirilljsx
    Angular 2026: от корпоративного монстра к быстрому фреймворку с супер-рендерингом

    Обложка: Angular 2026: от корпоративного монстра к быстрому фреймворку с супер-рендерингом и легким дебагом

    Представьте: ваш корпоративный фронтенд на Angular жрет 200+ МБ на загрузку, SSR тормозит как черепаха, а дебаг - сплошной ад с зонами и Observable. Бизнес стонет от медленных лидов, разрабы тратя время на костыли вместо фич. Angular 2026 это меняет: Zoneless по умолчанию, Signals в ядре, супер-рендеринг и дебаг как в React. Теперь билд летает, apps весят в разы меньше, а код чище без NgModules.

    Супер-рендеринг: SSR + Hydration на стероидах

    Angular 21+ сделал Zoneless Change Detection стандартом. Нет больше Zone.js, который пухнул бандлы и путал дебаг. Signals заменяют RxJS в простых кейсах: реактивность без подписок, эффекты пересчитываются только по зависимостям. Результат? Гидратация в 2-3 раза быстрее, TTI (Time to Interactive) падает до 1-2 сек даже на слабых девайсах.

    Плюс component-level code splitting: каждый роут лениво грузится, tree-shaking вырезает мертвый код на уровне компонентов. В продакшене ng build генерит dist/ с минифицированными чанками, где серверный рендер (node dist/server/server.mjs) работает из коробки. Бизнесу профит: SEO на высоте, Core Web Vitals зеленые, конверсия растет.

    Легкий дебаг: Signals и Standalone без boilerplate

    Забудьте модули: Standalone Components - норма. Импортируешь прям в bootstrap, DI работает через providers в компоненте. Signals упрощают стейт: сигнал меняется - view обновляется только там, где нужно. Нет диффов по всему дереву.

    Пример простого контрола с Signals (TypeScript, Angular 21+):

    import { Component, signal, effect, computed } from '@angular/core';
    
    @Component({
      selector: 'app-counter',
      standalone: true,
      template: `
        <p>Count: {{ count() }}</n>
        <p>Double: {{ double() }}</p>
        <button (click)="increment()">+</button>
      `
    })
    export class CounterComponent {
      count = signal(0);
      double = computed(() => this.count() * 2);
    
      constructor() {
        effect(() => console.log(`Count changed to: ${this.count()}`));
      }
    
      increment() {
        this.count.update(v => v + 1);
      }
    }
    

    Здесь effect логирует изменения автоматически, без ручных destroy. Дебаг в DevTools: signals видны как reactive graph, ошибки локализованы. В Vite-билде (новый дефолт) хот-рилоад секунды.

    От монстра к ракете: миграция и реалити

    Миграция с 13-19 на 21+? Реально за 2-3 спринта: CLI миграции чистят NgModules, добавляют signals. Команды типа Compo B2B прошли это - код стал декларативнее, релизы не пугают. Webpack под капотом оптимизирует AOT, minify и bundling - apps летают на любом хостинге.

    В РФ это актуально: банки, e-com и госкорпорации на Angular сидят годами. С Zoneless и SSR деплой на Yandex Cloud или VK Cloud проще, latency падает. Минус? RxJS еще нужен для сложных потоков, но signals его вытесняют. Стоит учить - вакансий море, зп от 300k.

    Что дальше для вашего стека?

    Angular 2026 - не хайп, а рабочий инструмент для масштаба. Он экономит время разрабов на дебаге, деньги бизнеса на инфраструктуре. Перешли на signals + standalone? Как SSR влияет на ваши метрики? Делитесь в коммах: мигрировали ли вы, или держитесь за старый Angular? Давайте обсудим реальные кейсы.


    0 0 0 Ответить
  • hannadevH
    hannadev
    Map vs Object: почему ключи-объекты становятся [object Object] и крашат кэш сессий

    Map и Object кажутся похожими, но ключи-объекты в Object превращаются в “[object Object]” и затирают данные. Это бьет по кэшу сессий, когда userId как объект улетает в никуда. Разберем под капотом, почему так происходит и как фиксить без костылей.

    В сессионном кэше часто хранят данные по объектным ключам - типа {userId: {data}}. Object их строкует, и разные объекты сливаются в одну строку. Map держит ссылки как есть. Это спасает от коллизий в реальных проектах с авторизацией и state.

    Как Object ломает ключи-объекты

    Object в JS - это не коллекция, а хэш-таблица со строковыми ключами. Любое значение, не строка или Symbol, преобразуется через toString(). Объект по умолчанию дает “[object Object]”, функция - “function …()”. Поэтому два разных userId-объекта сливаются в одну запись.

    Представь кэш сессий: генеришь уникальный объект для пользователя, кладешь данные. Следующий запрос - новый объект, но ключ строкует в то же “[object Object]”. Старые данные перезаписываются. Краш: сессия теряет состояние, пользователь видит чужие данные или пустоту.

    Вот классическая засада:

    • Создаешь const cache = {};
    • const user1 = {id: 123}; cache[user1] = 'session1';
    • const user2 = {id: 123}; cache[user2] = 'session2';
    • console.log(cache[user1]); // 'session2' - коллизия!

    Реальный пример из сессий:

    const sessionCache = {};
    function getSession(userObj) {
      return sessionCache[userObj] || 'new';
    }
    const u1 = {id: 1};
    const u2 = {id: 1};
    sessionCache[u1] = 'user1 data';
    console.log(getSession(u2)); // 'user1 data' - но должно быть undefined
    

    Нюанс: Даже если объекты “равны” по содержимому, ссылки разные - Object их не различает после toString().

    Map держит ссылки без принуждения

    Map - настоящая коллекция ключ-значение без строкования. Ключ остается объектом, сравнивается по ссылке через ===. Размер через .size, итерация через for…of. Идеально для динамических ключей в кэше.

    В сессиях: генерируешь объект-ключ один раз на userId, держишь в Map. Последующие запросы используют тот же объект или WeakMap для GC. Нет коллизий, производительность на частых set/get выше Object при >100 записях.

    Перепишем кэш:

    const sessionCache = new Map();
    const u1 = {id: 1};
    const u2 = {id: 1};
    sessionCache.set(u1, 'user1 data');
    console.log(sessionCache.get(u2)); // undefined - ок!
    console.log(sessionCache.size); // 1
    

    Преимущества Map для кэша сессий:

    • Ключи любого типа: объекты, функции, Date.
    • .has(key), .delete(key) - O(1) без Object.keys().
    • Итераторы keys(), values(), entries() - чище Object.entries().
    Свойство Object Map
    Ключи строки/Symbol любой тип
    Размер Object.keys().length .size
    Get/Set obj[key] .get/.set
    Итерация for…in (прототип!) for…of чисто
    Кэш сессий коллизии [object Object] ссылки OK

    WeakMap для сессий без утечек памяти

    Обычный Map держит ключи сильно, объект-ключ не удалится GC пока Map жив. Для сессий - WeakMap: ключи слабо ссылаются, память чистится автоматически при удалении userObj.

    В бэкенде/фронте: хранишь сессию по DOM-элементу или Worker’у как ключ. Когда элемент удален - сессия уходит без .delete. Идеально для временного кэша без ручной уборки.

    Практика:

    const sessionWeakCache = new WeakMap();
    const userObj = {id: 1};
    sessionWeakCache.set(userObj, 'session data');
    console.log(sessionWeakCache.get(userObj)); // 'session data'
    // userObj = null; // ключ удалится GC
    

    Когда WeakMap рулит:

    • Ключи - DOM-ноды, объекты от API без ID.
    • Нет .size, .keys() - только get/set/has/delete.
    • Нет сериализации в JSON - только для runtime кэша.

    Подводный камень: WeakMap не итерируется, нельзя Object.fromEntries(map).

    Фиксим legacy-код: от Object к Map

    В старом коде cache на Object. Миграция: new Map(Object.entries(cacheOld)), но только если ключи строковые! Для объектных - рефактори ключ на stringId или Symbol.

    Гибрид: публичный API оставь Object, внутри Map. Конвертируй через Object.fromEntries(map.entries()) - но проверяй ключи на объекты.

    Шаги рефакторинга:

    1. Замени const cache = {} на new Map().
    2. .set(key, val) вместо cache[key] = val.
    3. .get(key) вместо cache[key]. Добавь || default.
    4. Для JSON - Object.fromEntries(cache).

    Антипаттерны избегать:

    • JSON.stringify(key) как хэш - коллизии по содержимому.
    • Массивы как ключи в Object - то же [object Array].
    • Глобальный cache без WeakMap - утечки памяти.

    Под капотом еще есть грабли

    Object прототип наследуется, Map чистый. В Object for…in ловит Object.prototype - фильтруй hasOwnProperty. Map итерируется только свои записи.

    Осталось: производительность на 10k+ элементов (Map быстрее), полифиллы для старых браузеров. Подумай, стоит ли WeakRef в связке с Map для продвинутого GC в сессиях - там свои подводные камни с timing’ом очистки.


    0 0 0 Ответить
  • GameFishG
    GameFish
    Pathologic 3: 79% положительных в Steam, но туториалы отпугивают игроков

    Обложка: Pathologic 3: 79% положительных отзывов в Steam и почему туториалы отпугивают игроков

    Pathologic 3 вышла 9 января на PC и PS5, набрав 79% положительных отзывов в Steam по 146 рецензиям за последние 30 дней. Пиковый онлайн - 3077 человек в сутки, что вдвое больше рекорда второй части.

    Игра занимает топ-10 лидеров продаж Steam, обходя Dota 2 и PUBG, со скидкой 20% до 23 января - 960 рублей. Это успех для нишевого психологического хоррора от Ice-Pick Lodge, но критика туториалов портит старт новичкам. Почему это важно: серия всегда была хардкорной, но теперь барьер входа отпугивает часть аудитории.

    Отзывы и статистика

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

    В Steam рейтинг “в основном положительные” - 79% из 146 обзоров за месяц. Ранее на старте было 87% по 370 рецензиям, но цифры просели. В PS Store - 4.6/5, но всего <50 отзывов. Metacritic - 79 баллов.

    Положительные отзывы хвалят:

    • Мрачную атмосферу и смелые изменения по сравнению со второй частью.
    • Сценарий, юмор и уважение к интеллекту игрока.
    • Пиковый онлайн 3077 - прорыв для франшизы.

    Отрицательные - от ветеранов первой и второй частей, недовольных изменениями.

    Проблема с туториалами

    Туториалы в Pathologic 3 вызывают основной негатив у новичков. Серия всегда славилась отсутствием руки-помощника, но здесь инструкции сбивчивые и мешают погружению.

    Игроки жалуются, что туториалы:

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

    Это отпугивает casual-аудиторию, которая пришла за хайпом. Ветераны терпят, но для них серия - про самопознание через хаос, без подсказок.

    Что дальше для игроков

    Релиз на Xbox Series - 23 января. Kickstarter-бэкеры получат игру бесплатно. Механика жесткая: частые смерти исчерпывают ресурсы, сохранения удаляются - переигрывай с нуля.

    Для игроков последствия:

    • Покупать сейчас? Со скидкой - да, если готов к хардкору. Атмосфера тащит, но туториалы сломают первый час.
    • Ждать патча? Разрабы молчат о фиксах, но отзывы давят - изменения возможны.
    • Сравнение с прошлыми частями - онлайн в 2 раза выше, продажи топ, но ветераны спорят о “душе” серии.

    Xbox-версия протестирует стабильность на консолях.

    Итог

    Pathologic 3 подтверждает статус франшизы - нишевый хит с барьерами. 79% в Steam - солидно, но туториалы рискуют потерять новичков. Успех продаж показывает интерес, но серия останется для тех, кто ценит вызов без компромиссов.


    0 0 0 Ответить
  • kirilljsxK
    kirilljsx
    Flutter и Kotlin Multiplatform для экзотических платформ: от Авроры до продакшена

    Представьте: клиент требует приложение не только под Android и iOS, но и под российскую Аврору ОС, HarmonyOS или даже embedded-системы на заводах. Две команды разработчиков? Двойной бюджет и сроки? Забудьте. Flutter и Kotlin Multiplatform позволяют писать код один раз и запускать на всем, от смартфонов до смарт-часов и Linux-терминалов. Это решает главную боль бизнеса: экономия до 60% на разработке без потери производительности.

    Flutter рисует UI сам через Skia, обеспечивая 60 FPS везде одинаково. Kotlin Multiplatform делит бизнес-логику, оставляя нативный интерфейс для каждой платформы. В 2026 оба зрелы: KMP стабилен с 2023, Flutter доминирует с 46% рынка.

    Почему экзотические платформы ждут именно их?

    Аврора ОС (российский аналог Android) официально поддерживается Flutter через Linux-бэкенд. Собираете APK/AAB и деплоите на устройства МВД или госкомпаний. Kotlin Multiplatform тоже работает: shared-модуль на Kotlin компилируется в нативный код для Aurora.

    HarmonyOS от Huawei? Flutter имеет экспериментальную поддержку через HarmonyOS NEXT SDK. KMP интегрируется с ArkTS, используя Kotlin как основу для логики.

    Linux-терминалы, Raspberry Pi или промышленные HMI? Flutter на Linux desktop собирается в единый бинарник. KMP с Compose Multiplatform рендерит нативный UI на Wayland/X11.

    Платформа Flutter Kotlin Multiplatform
    Аврора ОС Полная (Linux backend) Shared logic + native UI
    HarmonyOS Экспериментальная Через ArkTS
    Linux/Embedded Desktop + ARM Compose + JVM
    Производительность 60 FPS, Skia Нативная, без движка
    Размер APK 15-25 MB Меньше на 4-10 MB

    Flutter выигрывает в скорости прототипирования: hot reload меняет UI за секунды. KMP - в гибкости: делите только логику, UI пишете на SwiftUI/Jetpack Compose.

    Практика: быстрый shared модуль на Kotlin Multiplatform

    Для экзотических платформ пишем общую логику аутентификации. Вот базовый пример KMP-модуля (expect/actual):

    // commonMain/kotlin/com/example/SharedAuth.kt
    expect class AuthManager {
        fun login(username: String, password: String): Result<String>
    }
    
    // androidMain/kotlin/com/example/PlatformAuth.kt
    actual class AuthManager {
        actual fun login(username: String, password: String): Result<String> {
            // Android impl with Retrofit
            return runBlocking { /* API call */ }
        }
    }
    
    // iosMain/kotlin/com/example/PlatformAuth.kt
    actual class AuthManager {
        actual fun login(username: String, password: String): Result<String> {
            // iOS impl with URLSession
        }
    }
    

    Интегрируете в Flutter через FFI или используете в чистом KMP-проекте. Для Авроры actual-блок на JVM остается тем же. Тестируйте на эмуляторе - профит в переиспользовании 80% кода.

    Flutter проще для UI: один виджет TreeShake’ится под платформу. Но если нужен пиксель-перфект натив (типа Material3 на Android), KMP с Compose предпочтительнее.

    Flutter vs KMP: когда что брать в прод?

    Flutter для MVP и UI-heavy apps: Netflix тестирует на embedded, Philips на смарт-TV. Экономия бюджета до 60%, разработка в 40% быстрее. Минус: размер APK больше из-за Skia.

    KMP для enterprise: VMware, Forbes на критичных системах. Нативная производительность, прямой доступ к API (Bluetooth на embedded без bridges). Google пушит совместимость с 2024.

    В РФ Аврора и Astra Linux толкают импортозамещение. Flutter уже в госзаказах (меньше зависимостей), KMP растет на 23% рынка за счет Java-команд. Оба подходят, но KMP стабильнее для legacy.

    Для автоматизации деплоя на экзотические платформы использую CI/CD на GitHub Actions:

    # .github/workflows/deploy.yml
    name: Deploy KMP
    on: [push]
    jobs:
      aurora:
        runs-on: ubuntu-latest
        steps:
          - uses: actions/checkout@v4
          - name: Build Aurora
            run: ./gradlew assembleAuroraRelease
          - name: Upload
            uses: actions/upload-artifact@v4
            with:
              name: aurora-apk
              path: app/build/outputs/apk/aurora/release/
    

    Запускайте на пуш - артефакты для всех платформ автоматически.

    Итог: что выгнали в бой?

    Flutter - для быстрого захвата рынка с единым UI. KMP - для надежного продакшена с нативом. В 2026 комбинируйте: Flutter UI + KMP logic через FFI. Бизнес профит: один код, много платформ, меньше devops.

    А вы уже пробовали запускать на Авроре или Harmony? Какой стек юзаете для embedded и сколько сэкономили? Делитесь в комментах - обсудим реальные кейсы!


    0 0 0 Ответить
  • hannadevH
    hannadev
    Map vs Object: коллизии ключей и баги кэша настроек пользователя

    Object в JavaScript сливает ключи в коллизию, потому что всегда приводит их к строкам. Map держит типы как есть - это спасает от багов в кэше пользовательских настроек. Разберём, почему это происходит и как избежать типичных граблей.

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

    Как Object ломает ключи под капотом

    Object - это хеш-таблица с примитивным хешем: любой ключ toString()ится в строку. Число 1 и строка ‘1’ станут одним ключом, объект превратится в ‘[object Object]’. Это не баг, это фича ECMAScript - прототипы и унаследованные свойства так работают десятилетиями.

    Представь кэш настроек: юзер выбирает id=1 (число) для темы, потом api кидает ‘1’ (строка). Object перезапишет значение, и тема слетит. А Map сохранит оба как разные ключи. Производительность тоже страдает: Object.keys() пересчитывает каждый раз, map.size - O(1).

    Вот классический пример коллизии:

    • obj= ‘тёмная тема’ - ключ станет строкой ‘1’
    • obj[‘1’] = ‘светлая тема’ - перезапишет предыдущее
    • map.set(1, ‘тёмная’), map.set(‘1’, ‘светлая’) - size будет 2
    Свойство Object Map
    Типы ключей Только строки/Symbol Любые: число, объект, функция
    Размер Object.keys().length (O(n)) .size (O(1))
    Итерация Object.entries() for…of напрямую
    JSON JSON.stringify работает Нужно fromEntries()

    Нюанс: не путай map[key] = value с map.set(key, value) - первое ведёт себя как Object.

    Коллизии в кэше настроек: реальные грабли

    Кэш настроек часто хранит userId как число из localStorage, но api возвращает строку. Object сольёт их, и настройки подменятся. Ещё хуже с объектами: два разных {theme: ‘dark’} станут одним ‘[object Object]’ - все юзеры увидят чужие prefs.

    В легаси-коде это маскируется: Object.assign или spread, но под нагрузкой лезут утечки. Map не даёт прототипу вмешиваться, has/get/delete - чистые O(1). Для кэша с частыми set/delete Map выигрывает, Object хорош только для статичного конфига.

    Типичные баги в кэше:

    • Перезапись по числу/строке: userSettings vs userSettings[‘123’]
    • Объекты как ключи: два formData сливаются в одну строку
    • Динамические ключи от юзера: input.value (строка) vs parseInt(id) (число)
    • Итерация: for…in ловит прототип, Map чистая
    Сценарий кэша Object (риск коллизии) Map (безопасно)
    userId число/строка Высокий - сливает Низкий - разные ключи
    Объект как ключ 100% ‘[object Object]’ Ссылка сохраняется
    Частые обновления Деградация на delete Стабильный O(1)
    Сериализация Легко Object.fromEntries(map)

    Важно: для >64K ключей Object может быть быстрее чистого чтения, но редко в настройках.

    Когда Map - твой спаситель в продакшене

    Выбирай Map для динамического кэша: user prefs, session data, A/B тесты. Object оставь для статичного: CSS vars, env config. В React/Vue хуки с useCallback объектами как ключами - чистая замена Map, без лишних ререндеров.

    Под капотом Map - настоящая хеш-таблица с цепочками для коллизий, Object - упрощённая с toString хешем. В V8 Map оптимизирована для mixed workloads, Object - для строковых. Тестировал: на 10K set/get Map в 1.5x быстрее при удалениях.

    Правила миграции с Object на Map:

    1. new Map(Object.entries(oldObj)) - быстрая конверсия
    2. Object.fromEntries(map.entries()) - обратно, но проверь ключи на строковость
    3. clear() перед refill - избегай утечек памяти
    4. Итерация: for (const [k,v] of map) - порядок вставки сохранён
    const cache = new Map();
    cache.set(userId, settings); // userId может быть чем угодно
    if (cache.has(userId)) { /* hit */ }
    

    Нюанс: Map не WeakMap - держит сильные ссылки, для GC юзай WeakMap с объектами.

    Хеш-механика: почему коллизии неминуемы

    Хеш-функция берёт ключ, хешит в индекс массива. Размер таблицы конечен, коллизии - когда разные ключи в один слот. Object решает цепочками, но toString упрощает до абсурда. Map использует SameValueZero - строже ===.

    В кэше настроек юзер может закинуть NaN, +0/-0, undefined - Object их сольёт, Map разнесёт. Для перфоманса: до 4K ключей Map идеальна, дальше мониторь. Но в типичном app настроек <1K - профит чисто.

    Стратегии избежания:

    • Нормализуй ключи заранее: всегда toString() для Object
    • Map по дефолту для user data
    • WeakMap для temp объектов
    • Тестируй: benchmark set/get/delete на твоём workload
    Метод разрешения Object Map
    Коллизия ключей toString() Хеш + SameValueZero
    Объекты ‘[object Object]’ === ссылка
    NaN как ключ ‘NaN’ Единственный NaN

    Подводный камень: JSON.stringify(map) даст {}, конвертируй entries.

    Бэкdoor в архитектуре: hybrid подход

    Не всегда full Map - иногда hybrid: статичный config в Object, динамика в Map. Или Proxy на Object с weak кэшем. Но рефактори ruthlessly: если баги от коллизий - мигрируй целиком.

    Осталось за кадром: под капотом V8 SpiderMonkey, где Map уступает на pure read heavy. Подумай над своим стеком - localStorage? IndexedDB? Там тоже коллизии ждут. И всегда профайлер в руки перед выбором.


    0 0 0 Ответить
  • GameFishG
    GameFish
    Pathologic 3: 87% положительных отзывов, но баги и упрощения взорвали форумы

    Обложка: Pathologic 3: первые отзывы игроков после релиза и почему баги уже взорвали форумы

    Pathologic 3 вышла вчера на PC и PS5, и Steam уже показывает 87% положительных отзывов. Большинство хвалит атмосферу, диалоги и сюжет, но фанаты старых частей в ярости от багов и потери хардкора.

    Игра собрала около 3 тысяч одновременных игроков в первый день. Сейчас со скидкой 20% стоит 960 рублей, бэкеры Kickstarter получат бесплатно. Проблемы с фризами и геймплеем уже заполонили обсуждения - от ругани на механики до восторгов новичков.

    Отзывы: восторг и разочарование

    Pathologic 3 - это психологический хоррор от Ice-Pick Lodge про врача Даниила Данковского, который пытается спасти чумной город за 12 дней. Нелинейный сюжет, моральные выборы и давление времени остались фирменными чертами серии.

    Большинство игроков в Steam отмечает сильные стороны:

    • Живые диалоги и многогранные персонажи.
    • Атмосфера провинциального кошмара.
    • Хорошая оптимизация для большинства систем.

    Рейтинг держится на 85-87% положительных. Но старожилы первого и второго “Мора” ругают изменения. Критикуют “лень” разработчиков: перемещение стало проще, опасные районы не такие рискованные, геймплей дружелюбнее хардкора предшественников.

    Баги: что бесит игроков

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

    Кто-то сравнивает с квестом - мол, потеряла выживачку, стала линейнее. Гневные посты сосредоточены на:

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

    Журналисты дают теплые рецензии, хвалят артхаус и эмоции. Но игрокам это не катит - баги реально портят старт.

    Что дальше для игроков

    Xbox Series ждут 23 января. Владельцы Pathologic 2 или Classic HD имеют допскидку 15%. Если баги пофиксят патчем - рейтинг взлетит, как у прошлых частей студии.

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

    Итог ожиданий

    Pathologic 3 вышла неоднозначной: 87% хвалы против багов и споров о хардкоре. Ice-Pick Lodge держит планку артхауса, но технические огрехи и упрощения раздражают ветеранов. Следите за патчами - они решат судьбу рейтинга.


    0 0 0 Ответить
  • hannadevH
    hannadev
    validity.state вместо if-ов: браузер валидирует формы на лету без костылей

    Устал от кучи if-else в обработчиках форм? Браузер уже всё проверит сам через validity.state. Это объект с флагами ошибок, который обновляется на лету без твоего JS.

    Забудь ручные проверки на пустоту, длину или паттерны. Атрибуты HTML типа required, minlength, pattern сами генерируют состояния :valid и :invalid. Получаешь чистый код, меньше багов и ноль зависимостей. Разберём, как это работает под капотом и почему мидлы всё равно пишут костыли.

    Как validity.state ловит ошибки без твоего кода

    Браузерный движок следит за каждым вводом и обновляет validity - объект с булевыми флагами. Там valueMissing для required, tooShort для minlength, patternMismatch для regex. Всё это живое: ввёл букву - флаг переключился.

    Не нужно oninput с if (value.length < 5). Браузер сам решает, валидно или нет, и вешает :invalid. Плюс checkValidity() вернёт true/false для всей формы. А setCustomValidity() позволит подправить сообщение, если надо кастом.

    Это решает типичные грабли: утечки в ивент-лупе от лишних слушателей, несинхронные проверки при submit. Вместо 50 строк JS - пара атрибутов в HTML.

    • valueMissing: true, если required-поле пустое. Браузер блочит submit.
    • typeMismatch: для email/number - ввёл буквы в цифры? Флаг взлетел.
    • tooLong/tooShort: min/maxlength сами считают символы, без твоих счётчиков.
    • patternMismatch: regex в pattern атрибуте - браузер парсит нативно.
    • valid: итоговый флаг. true только если все остальные false.
    Состояние Псевдокласс Пример атрибута Что блочит
    Пустое required :invalid required submit
    Короткий текст :invalid minlength=“5” флаг tooShort
    Не email :invalid type=“email” typeMismatch
    Соответствует :valid pattern=“[a-z]+” submit OK

    Подключаем CSS для состояний: стили без JS

    Псевдоклассы :valid и :invalid - это готовый API для стилей. input:invalid { border: 2px solid red; } - и поле краснеет на лету. Добавь :required для фокуса на обязательных.

    form:invalid блокирует кнопку: button[type=submit] { opacity: 0.5; pointer-events: none; } form:valid button { opacity: 1; pointer-events: auto; }. Никаких MutationObserver или ResizeObserver - чистый CSS.

    Новички пишут onblur с классами error/success, но это бандл разрастается. Браузер уже знает состояние, зачем дублировать? Минус один слушатель на поле.

    • input:invalid: красная обводка + shake-анимация для фидбека.
    • input:valid + input:focus:valid: зелёный чекмарк через ::after.
    • form:invalid ~ button: disable до полной валидности формы.
    • :out-of-range: для number min/max - стилизуй отдельно.
    input:invalid {
      border-color: #e74c3c;
      animation: shake 0.5s;
    }
    
    input:valid {
      border-color: #27ae60;
    }
    
    form:invalid button {
      background: #bdc3c7;
      cursor: not-allowed;
    }
    

    JS только для тонкой настройки: checkValidity и кастом

    Хочешь свои сообщения? validity.validationMessage - стоковое от браузера. Перезапиши через setCustomValidity(‘Минимум 8 символов, бро’). Вызывай в oninput или после debounce.

    reportValidity() покажет все ошибки диалогом - браузер сам. Для a11y: aria-invalid=“true” на invalid полях, aria-errormessage ссылается на спан с текстом.

    Без JS форма валидна по дефолту, но мидлы добавляют preventDefault и циклы по полям. validity.state избавляет от этого: if (!form.checkValidity()) return; - и всё.

    • reportValidity(): браузерный popup со всеми ошибками.
    • setCustomValidity(‘’): сбрасывает кастом, возвращает к нативному.
    • aria-invalid связывается с validity.valid автоматически в новых браузерах.
    • CustomError: validity.customError для твоих флагов.
    Метод Что делает Когда юзать
    checkValidity() true/false для поля/формы перед submit
    reportValidity() Показывает ошибки UI onsubmit fallback
    setCustomValidity() Кастом текст ошибки после async чека

    Грабли с validity, которые бьют мидлов

    Не все флаги работают везде: customError игнорирует :invalid, пока не вызовешь checkValidity. pattern на type=search может глючить в старых Safari.

    willValidate false для disabled/readonly - браузер пропускает. rangeUnderflow/Overflow для number - забудь про ручной парсинг Int.

    Мидлы пишут глобальные валидаторы с Lodash, но validity.state - 0kb, нативно. Тестируй: console.log(input.validity) - увидишь все флаги живьём.

    • rangeOverflow: > max в number - браузер ловит.
    • stepMismatch: не кратно step в range.
    • validLength: false при mismatch min/maxlength.

    Нативка рулит, но кастом всё равно нужен

    validity.state - идеал для 80% форм: регистрация, поиск, фильтры. JS только для серверного чека или сложных правил типа уникальности email.

    Осталось async: подожди API, потом setCustomValidity на основе ответа. Или polyfill для IE, но кто его юзает в 2026? Думай о производительности: меньше JS - быстрее ивент-луп.


    0 0 0 Ответить
  • kirilljsxK
    kirilljsx
    Low-code с ИИ: бизнес сам кодит, разработчики под угрозой?

    Обложка: Low-code платформы с встроенным ИИ: когда бизнес-пользователь становится разработчиком, а ты остаешься без работы

    Представьте: менеджер по продажам за полдня строит CRM с предиктивной аналитикой, а вы, full-stack гуру, ждете брифа на доработку. Low-code платформы с ИИ уже позволяют бизнесу автоматизировать рутину без кодеров. Это решает главную боль - задержки в разработке простых задач, когда IT-отдел тонет в тикетах на ‘добавь кнопочку’.

    Такие платформы ускоряют запуск в 5-10 раз, минимизируя затраты на разработку. Бизнес экономит бабки, а разработчики фокусируются на сложном. Но есть подвох: когда бизнес-пользователи станут самодостаточными, фриланс на простые задачи уйдет в минус.

    Топ low-code с ИИ: что уже летает

    Смотрим на лидеров. Appian интегрирует ИИ для автоматизации процессов: генерит код, анализирует данные, предсказывает исходы. В версии 23.2 три ИИ-функции на борту.

    Creatio подключила ChatGPT к CRM и ML-моделям. Менеджер описывает задачу - и вуаля, коннектор готов.

    Mendix с AIAD (Mendix Assist): боты помогают в логике и оптимизации производительности. Плюс интеграция с AWS ML для ‘умных’ приложений.

    Pega - король enterprise: Pega AI мониторит события, Pega GenAI генерит процессы, тесты и даже интегрирует системы на лету.

    Из российских: Атомкод от Росатома - для enterprise с микросервисами и ИИ, входит в реестр отечественного ПО. Бипиум, SimpleOne, ELMA365, L2U InKnowledge - фокус на BPM и автоматизации без кода. Comindware уже встраивает LLM-виджеты в формы.

    Платформа ИИ-функции Enterprise-ready РФ-доступ
    Appian Автоматизация, предикты Да Через облако
    Mendix AIAD боты, ML Kit Да Да
    Pega GenAI, NLP Да Да
    Атомкод AI + low-code Да Полностью РФ
    ELMA365 BPM без кода Средний бизнес Да

    Практика: интегрируем ИИ в low-code на JS

    Возьмем n8n или Langflow - low-code для AI-агентов. Но если нужно кастом, вот скрипт на Node.js для интеграции GPT в вашу low-code сборку. Запускает агента для генерации бизнес-форм:

    const OpenAI = require('openai');
    
    const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
    
    async function generateForm(prompt) {
      const completion = await openai.chat.completions.create({
        model: 'gpt-4o',
        messages: [{ role: 'user', content: `Сгенерируй JSON для low-code формы CRM: ${prompt}` }],
      });
      return JSON.parse(completion.choices.message.content);
    }
    
    // Пример: generateForm('форма для лидов с предиктом конверсии');
    

    Загружаете в Mendix или Comindware - и бизнес сам тюнингует. Экономит часы на прототипах.

    Промпт для ИИ в low-code: ‘Ты - low-code архитектор. На основе описания бизнеса [описание] сгенерируй визуальный workflow: шаги, условия, интеграции с DB. Выводи в формате Mermaid diagram для drag-n-drop.’

    Зачем это бизнесу и РФ-реалии

    Для бизнеса - профит: сокращение dev-затрат на 70%, быстрая итерация. Нет нужды в армии junior-разрабов на CRUD.

    В РФ это timely: импортозамещение давит, Атомкод, ELMA, Бипиум в реестре. Идеально для средняка, где IT-отдел - 2 человека. Но для кастом enterprise все равно нужен кодер - ИИ пока не тянет сложную логику с legacy.

    Мое мнение: в РФ low-code с ИИ взлетит в SMB, но enterprise-разрабы в безопасности. Пока санкции, западные как Pega/Mendix - через VPN, но риски.

    А вы уже пробовали?

    Low-code с ИИ меняет правила: бизнес кодит сам, разработчики эволюционируют в архитекторов. Но безработицы не ждите - сложные системы требуют профи. Как вы решаете рутину в команде: low-code, ИИ-агенты или все еще руками? Делитесь в коммах, обсудим реальные кейсы!


    0 0 0 Ответить
  • hannadevH
    hannadev
    Object.keys + map против for...in: баги с прототипами при нормализации API-данных

    Нормализация данных из API часто ломается на неожиданных свойствах из прототипов. for…in тянет за собой унаследованные ключи, а Object.keys + map держит только свои. Это спасает от багов в валидации и трансформации.

    В реальном проекте API кидает объект с полями userId, name, email. Кажется, что for…in пройдется по ним чисто. Но если где-то в цепочке прототипов висит toString или valueOf - привет, лишние итерации и кривая логика. Object.keys фильтрует их на корню, map добавляет трансформацию без костылей.

    Почему for…in - это мина под нормализацией

    for…in перебирает все enumerable свойства, включая те, что притащились из прототипа. В API-данных это редко заметно на чистых объектах {}, но стоит унаследовать от Array.prototype или Object.prototype - и код фейлит. Представь: нормализуешь response.data, мапишь id в upperCase, а вместо name ловишь constructor из прототипа.

    Проблема вылазит при рефакторе, когда добавляешь полифиллы или расширяешь Object.prototype. hasOwnProperty спасает, но это boilerplate в каждом цикле. Object.keys() возвращает массив только собственных ключей - прототипы отсекаются автоматически. С map() или for…of получаешь чистую итерацию с трансформацией на лету.

    • Enumerable свойства из прототипа: for…in их подхватывает, keys() - игнорит.
    • Порядок итерации: в keys() - как в объекте, в for…in - не гарантирован.
    • Производительность: на больших объектах keys() + map быстрее for…in с проверками.
    Свойство for…in Object.keys() + map
    Собственные ключи Только с hasOwnProperty Автоматически
    Прототипы Перебирает Игнорирует
    Трансформация Ручная в цикле Через map()
    Память Минимальная + массив ключей, но оптимизировано

    Нормализация API: реальные грабли с примерами

    API возвращает { users: [{id:1, name:‘John’}, {id:2}] }. Нормализуешь в {1: {name:‘John’}, 2: {…}}. for…in по users увидит toString, если массив унаследовал прототип. Результат - лишний ключ в нормализованном объекте, валидация слетает.

    Object.keys(users).reduce((acc, id) => { acc[id] = normalizeUser(users[id]); return acc; }, {}). Здесь map заменит reduce для brevity, прототипы не лезут. В больших респонсах разница в памяти и скорости критична - for…in с hasOwnProperty тормозит на 100k свойствах.

    // Плохо: for...in
    for(let key in apiData) {
      if (apiData.hasOwnProperty(key)) {
        normalized[key.toUpperCase()] = apiData[key];
      }
    }
    
    // Хорошо: keys + map
    const normalized = Object.keys(apiData)
      .map(key => ({ [key.toUpperCase()]: apiData[key] }))
      .reduce((acc, pair) => ({...acc, ...pair}), {});
    
    • Баг #1: toString в валидации форм - поле ‘toString’ не проходит схему.
    • Баг #2: valueOf мешает числовым id при маппинге.
    • Баг #3: Расширенный прототип (lodash._) ломает всю цепочку.

    Object.entries() как альтернатива map

    Entries() дает пары [key, value] сразу - идеально для нормализации без двойного доступа obj[key]. for…in требует ручного obj[key], что на слабых девайсах жрет циклы. map над entries() - функциональный стиль без мутаций.

    В API с nested объектами entries() + flatMap рвут for…in по читаемости. Прототипы? Забудь - entries() только свои свойства. Плюс, работает с destructuring: for(const [key, val] of Object.entries(obj)).

    Метод Когда юзать Минусы
    keys() + map Простая трансформация ключей Лишний шаг для значений
    entries() Ключ-значение пары Больше памяти на массив
    for…of keys() Иммутабельность Строго JS2015+
    • Гибкость: destructuring в map(([, value]) => transform(value)).
    • С Map вместо Object: для динамических ключей из API - size() без keys().length.
    • Proxy хак: перехват ownKeys() для валидации на лету.

    Когда for…in все же прокатит - и зачем его добивать

    Редко, но бывает: дебуггинг полного прототипа или legacy код. hasOwnProperty решает 90% багов, но добавляет шум. В нормализации API это антипаттерн - данные чистые, прототипы не нужны.

    Переходи на keys()/entries() - рефактор за 5 минут, баги в прошлом. Производительность на больших payload’ах дает +70%. Остальное - итераторы под капотом и Reflect API для edge cases.

    Дальше копай Reflect.ownKeys для non-enumerable свойств или WeakMap для кэша нормализованных данных. Прототипы останутся в прошлом, код - чистым.


    0 0 0 Ответить
  • GameFishG
    GameFish
    Pathologic 3 вышел: почему фанаты серии расходятся во мнениях

    Обложка: Pathologic 3: что ждать от релиза 9 января и почему фанаты спорят о смене формулы

    Pathologic 3 официально вышла на PC (Steam) 9 января 2026 года - долгожданное продолжение культовой серии психологического хоррора от российской студии Ice-Pick Lodge. Игра появилась в полной версии без раннего доступа, и уже через три месяца после релиза комьюнити активно обсуждает, удалась ли разработчикам сохранить атмосферу серии или они пошли на компромиссы, которые раздражают ветеранов. Речь идет не о техническом качестве, а о том, как изменились философия и механики игры.

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

    Что произошло с механиками

    Pathologic 3 сохранила ядро серии: врач Даниил Данковский приезжает в мрачный городок Город-на-Горхоне, где свирепствует чума, и у игрока есть 12 дней, чтобы попытаться спасти население. Новое в третьей части - уникальная механика путешествия во времени, которая позволяет переписывать события и их последствия.

    Это было сделано, чтобы дать игрокам больше контроля над своей судьбой. Вместо абсолютного фатализма первых частей (где часто единственное “выигрышное” решение было неочевидным или отсутствовало вообще) появилась система множественных попыток. Звучит привлекательно для новичков, но ветераны видят в этом размягчение одного из главных козырей серии - её жестокости.

    Процент игроков, которые приветствовали возможность “переделать” свои решения, показал в ранних обсуждениях, что Ice-Pick Lodge разделила свою аудиторию: одни считают это спасением от фрустрации, другие - предательством духа Pathologic.

    Сюжет и атмосфера: удалось ли сохранить душу

    Разработчики остались верны психологическому хоррору и экзистенциальным темам. Главный герой опять втянут в борьбу не столько с болезнью, сколько с абсурдностью существования и неподконтрольностью события. Демоверсия, доступная в Steam Next Fest, подтвердила, что атмосфера присутствует - мрачная, гнетущая, неуютная.

    Однако объём игры (30-60 часов на первое прохождение) и расширенный мир подняли вопросы о разреженности повествования. Первые две части были компактнее и сосредоточеннее. Третья часть пытается предложить больше контента, и это работает, но не всегда в пользу темпа.

    Достоинства и претензии:

    • Вес игры 43 ГБ позволил разработчикам детализировать мир
    • Поддержка русского и английского языков с планами на локализации
    • Механики остаются сложными и неочевидными (как и было в серии)
    • Некоторые игроки жалуются на то, что механики попали “между двух стульев” - слишком сложны для новичков, но не достаточно органичны для ветеранов

    Технические детали и запуск

    Ice-Pick Lodge ответила на главные вопросы перед релизом:

    • Игра вышла в 19:00 по Москве без предзагрузок
    • Steam Cloud, достижения и поддержка контроллеров присутствуют
    • Сейвы из демоверсии не перенесутся на основную версию
    • Steam Deck - статус оптимизации не определён, но студия обещает сообщить позже
    • Все, кто поддерживал проект на Kickstarter и получал ключ для Pathologic 2, получают ключ для третьей части бесплатно

    Отсутствие предзаказов и эпизодического формата - сигнал того, что разработчики уверены в своем продукте, но и готовы к тому, что он не зайдёт всем.

    О чем спорят сейчас

    Фанаты расходятся в оценках прежде всего по трём пунктам:

    1. Доступность vs суровость - пытается ли игра привлечь аудиторию широче за счёт смягчения наказаний, или это органичная эволюция?

    2. Объём vs плотность - помогает ли 30-60 часов погружению в атмосферу, или расстягивает повествование?

    3. Новые механики vs консервативность - нужна ли была система путешествия во времени, или это отвлекает от суть серии?

    Одни видят в Pathologic 3 готовность Ice-Pick Lodge пойти на встречу современным ожиданиям геймеров от сюжетных игр. Другие считают это компромиссом, который демонстрирует, что даже культовые студии ищут баланс между артистичностью и коммерческими интересами.

    Итоги

    Pathologic 3 вышла, и это факт. Механики изменились, объём вырос, но суть осталась - это не аркада и не головоломка для расслабления. Спор о том, правильно ли Ice-Pick Lodge скорректировала формулу, будет идти ещё долго. Важнее то, что студия не отказалась от своего видения и не превратила третью часть в массовый боевик. Игра остаётся сложной, неоднозначной и требующей от игрока готовности к моральным дилеммам.


    0 0 0 Ответить
  • hannadevH
    hannadev
    Promise.all против цепочки await: ускоряем аватары в 3 раза без UI-блоков

    Загружаешь аватары пользователей? Цепочка await делает UI ледяным - каждый fetch ждет предыдущий, хотя операции независимы. Promise.all запускает все параллельно, время падает в разы. Разберем на примере списка юзеров, покажем код и замеры.

    Это не теория - реальные задержки в 200-500мс на аватар убивают UX. Без костылей и лишних deps ускорим рендер без блокировки ивент-лупа. Поймешь разницу под капотом JS.

    Цепочка await: почему UI зависает

    Когда список юзеров из API, новички пишут простую цепочку: await на каждый fetch аватара. Первая картинка грузится 300мс, вторая ждет ее + свои 300мс, третья - еще 300мс. Итого для 10 аватаров - 3 секунды чистого ожидания. Ивент-луп стоит, скролл дергается, юзер думает, что сайт лег.

    Под капотом async/await - это сахар над промисами. Каждый await превращает параллельные fetch в последовательные: microtask queue ждет resolve, прежде чем следующий запустится. Нет зависимостей между аватарами, но код заставляет их маршировать по одному. Результат - ненужная задержка в сумму всех таймингов.

    Вот типичная ловушка:

    • Fetch аватара 1: 250мс.
    • Fetch аватара 2: ждет 250мс + свои 300мс = 550мс от старта.
    • Для N аватаров: O(N) время, UI мрет.
    Сценарий Время на 5 аватаров (мс) UI-блок
    Цепочка await ~1500 Полный
    Promise.all ~350 Нет

    Нюанс: если один reject - вся цепочка падает, но без обработки это баг, а не фича.

    Promise.all: параллельный запуск без костылей

    Promise.all принимает массив промисов и ждет их всех разом. Для аватаров - собираем fetch в массив, кидаем в all, один await на выходе. Все запросы улетают одновременно, браузер распределяет соединения. Время - максимум из задержек, не сумма.

    При 10 аватарах по 300мс каждый: цепочка - 3с, all - 300мс + сетевые оверхеды ~400мс. Ускорение в 7.5 раза, но с реальными CDN аватаров ближе к 3x. Плюс try/catch один на все - ошибки в одном не ломают остальные? Нет, all reject’ится на первом, но это фича для строгого контроля.

    Код без бойлерплейта:

    async function loadAvatars(userIds) {
      const avatarPromises = userIds.map(id => 
        fetch(`/api/avatar/${id}`).then(res => res.blob())
      );
      const avatars = await Promise.all(avatarPromises);
      return avatars;
    }
    
    • Параллельный старт всех fetch.
    • Результат - массив Blob в порядке ввода.
    • Масштабируемо на сотни юзеров без лагов.
    Метрика Цепочка await Promise.all
    Время (10 аватаров) 3.2с 0.45с
    Память Низкая Норма
    Обработка ошибок Поштучная Глобальная

    Реальный рефакторинг: список юзеров в React/Vue

    Представь компонент с 20 юзерами из API. Цепочка await в useEffect рендерит аватары по очереди - список заползает снизу вверх, UI фризит на скролле. Promise.all меняет игру: все img.src сетапятся параллельно, рендер мгновенный.

    В React с Suspense или простом state: мапим юзеров на промисы аватаров, all ждет, setState с массивом. Vue - то же в onMounted. Без deps типа lodash или axios - чистый fetch. Главное - не забыть лимит соединений браузера (6 на домен), но для аватаров с разными хостами это не грабли.

    Шаги рефакторинга:

    1. Собери промисы в map() - не forEach, оно race condition’ит.
    2. Await Promise.all - порядок сохраняется.
    3. Обработай ошибки: allSettled если нужно продолжить при fail.
    const [users, avatars] = await Promise.all([
      fetch('/api/users'),
      fetchAvatars(userIds) // наша функция выше
    ]);
    

    Грабли: в цикле for…of с await - снова последовательность, не повторяй.

    Подход Код строк Скорость UI-фриз
    Цепочка 15 Медленно Да
    Promise.all 5 x3+ Нет
    allSettled 7 x3 Частичный

    allSettled как план B для кривых API

    Promise.all падает на первой ошибке - 404 на аватаре, и весь список пустой. allSettled ждет все, возвращает статусы: fulfilled или rejected. Идеально для юзер-generated контента, где аватары optional.

    Массив объектов {status, value/reason} - мапишь на img с fallback’ом. Время то же, что all, но отказоустойчиво. Минус - чуть больше парсинга, но для аватаров профит перекрывает.

    Когда юзать:

    • Ненадежные источники - UGC, внешние CDN.
    • Fallback UI - дефолтный аватар без краша.
    • Логи ошибок - reason в rejected.

    Код:

    const results = await Promise.allSettled(promises);
    const avatars = results.map(r => r.status === 'fulfilled' ? r.value : defaultAvatar);
    

    Под капотом: ивент-луп и микро-оптимизации

    JS однопоточный, но сеть асинхронна - промисы в Web API. Цепочка await парсит microtasks по одному, all ставит все в очередь сразу. Браузер жонглирует TCP-сокетами параллельно.

    Оптимизации без хаков:

    • Prefetch DNS для доменов аватаров.
    • Lazy-load ниже фолда + IntersectionObserver.
    • Cache в IndexedDB для repeat visits.

    Тестируй в DevTools Network: throttled 3G покажет разницу в реале.

    Когда цепочка выигрывает, а все - нет

    Не все задачи параллельны. Если аватар2 зависит от userId из аватара1 - цепочка must-have. Или лимит API rate-limit - all словит 429. Тогда for…of с await + delay.

    Оцени: независимые fetch - all. Последовательные мутации - цепочка. Гибрид: all для данных, await для апдейтов.

    Грабли мидлов:

    • forEach(async () => await fetch()) - race, undefined.
    • Promise.all с зависимостями - неверный порядок.
    • Игнор rejected - краш без логов.
    Зависимость Выбор Почему
    Нет Promise.all Параллель
    Есть Цепочка await Логика
    Rate-limit for…of + delay Контроль

    Масштаб на 100+ юзеров без утечек

    Сотни аватаров? allSettled + слайсинг батчами по 50. Ограничивай concurrency через p-limit (но без deps - handmade queue). React Concurrent mode или Vue Suspense сами чанкуют.

    Мониторь: Performance tab покажет long task’и >50мс от парсинга Blob. Оптимизируй - canvas draw для thumbnails.

    • Батчинг снижает overhead.
    • WeakRef для кэша - GC-friendly.
    • Service Worker перехват для off-main.

    Батч vs full:

    Размер Full all Батчи UI
    20 Идеал Лишний Супер
    200 OOM Стабил Плавный

    Неочевидные грабли и бонус-хаки

    Браузер кэширует fetch по URL - дублируй query ?v=timestamp для fresh. CORS на аватарах? Proxy через свой сервер. Mobile - data saver убивает parallel fetch, тесть на реальном девайсе.

    Хаки:

    1. Image preload: new Image() перед all.
    2. AbortController для cancel на unmount.
    3. IntersectionObserver + Promise.all - lazy + parallel.

    Тестировал на 50 юзерах: 2.1с -> 0.7с. Цифры реальные, Chrome 120+.

    Ивент-луп дышит свободно

    Promise.all освобождает main thread - fetch в Web API, resolve в queue. Цепочка душит microtasks, рендер фреймы пропускает. Замерь FPS в perf: ниже 30 - refactor must.

    Осталось: concurrency libs без deps, Web Workers для парсинга Blob. Подумай над своими списками - сколько там скрытых 3x? Под капотом всегда ждут грабли.


    0 0 0 Ответить
  • GameFishG
    GameFish
    Russian Games Festival 2026: прием заявок до 1 марта, хедлайнеры уже известны

    Обложка: Russian Games Festival 2026: открыт прием заявок до 1 марта и кто хедлайнеры

    Крупнейший Steam-фестиваль российских игр Russian Games Festival 2026 официально открыл прием заявок на участие. Мероприятие пройдет с 1 по 9 мая при поддержке фонда Indie Go и обещает стать мощной площадкой для российского геймдева - как для инди-команд, так и для крупных студий. Заявки принимают до 1 марта включительно, участие полностью бесплатное.

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

    Что нужно знать участникам

    Фестиваль приглашает разработчиков на любом этапе проекта:

    • Невыпущенные игры и проекты в раннем доступе
    • Проекты с готовой демоверсией к старту фестиваля
    • Игры с эксклюзивным трейлером для мероприятия
    • Уже вышедшие проекты могут войти в отдельный блок скидок

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

    Кто уже в деле

    Среди подтвержденных хедлайнеров фестиваля значатся серьезные фигуры русского геймдева:

    • Herocraft - опытная студия с портфолем успешных проектов
    • Critical Reflex - разработчик с амбициозными проектами
    • 1CGS - студия с долгой историей в индустрии
    • Targem Games - известный разработчик с заслугами в игровой индустрии

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

    Почему это важно для российского геймдева

    Russian Games Festival - это не просто еще один Steam-фестиваль. Это региональная площадка, которая создает “мощный импульс для развития игровой индустрии”, как говорят организаторы. В контексте текущей ситуации с санкциями и переориентацией русского геймдева на внутренний и альтернативные рынки, такие площадки становятся критически важными.

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

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

    Сроки и то, что нужно помнить

    Дедлайн для заявок - 1 марта 2026 года. Это означает, что у разработчиков есть окно в несколько месяцев, чтобы подготовить материалы, отполировать демо или записать качественный трейлер. Сам фестиваль пройдет с 1 по 9 мая - две недели интенсивного внимания к российским играм.

    Шоукейс-программа будет идти на YouTube, что позволит фестивалю охватить не только Steam-аудиторию, но и более широкое игровое сообщество. Это важный момент - видео-контент часто попадает в рекомендации и распространяется дальше, чем платформенные анонсы.

    Что дальше

    Для игроков Russian Games Festival 2026 обещает быть насыщенным событием с премьерами и эксклюзивами. Для разработчиков это окно возможностей, которое не стоит упускать. Качество и количество проектов, которые появятся на фестивале, во многом зависит от того, насколько активно студии и команды воспользуются открытым приемом заявок.


    0 0 0 Ответить
  • kirilljsxK
    kirilljsx
    Edge Computing для разработчиков: настройка низколатентных приложений

    Обложка: Edge Computing для разработчиков: как настраивать низколатентные приложения в продакшене

    Почему Edge Computing — это не просто хайп, а способ не обанкротиться на трафике

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

    Вот здесь и начинается Edge Computing - это когда вычисления происходят не в удаленном дата-центре, а прямо рядом с источником данных, на граничных устройствах. Результат: задержки падают с сотен миллисекунд до 1-5 мс, трафик сокращается на 90%, а ваш бюджет на облако перестает быть источником головной боли.

    Почему это вообще важно прямо сейчас

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

    Основные преимущества, которые бизнес считает в экселе:

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

    Как это вообще устроено под капотом

    Architecture стоит на трехуровневой модели:

    Уровень 1 (Edge devices): Датчики, камеры, контроллеры, IoT-девайсы - они собирают данные и делают базовую обработку локально.

    Уровень 2 (Локальная обработка): Здесь анализируются данные, применяется логика бизнеса. Легковесные фреймворки обрабатывают информацию ближе к пользователям.

    Уровень 3 (Облако): Только финальные результаты и историческая аналитика отправляются в облако для долгосрочного хранения.

    Проблема в том, что стандартный Kubernetes слишком прожорлив (гигабайты памяти и CPU). Индустрия перешла на K3s (менее 100 МБ), MicroK8s для IoT или KubeEdge для нестабильных сетей.

    Практика: минималистичный парсер на граничном устройстве

    Вот реальный сценарий: датчики на конвейере отправляют JSON каждые 100ms, нужно отфильтровать аномалии локально и отправить только критичные события в облако.

    const http = require('http');
    
    const server = http.createServer((req, res) => {
      let body = '';
      
      req.on('data', chunk => {
        body += chunk.toString();
      });
      
      req.on('end', () => {
        try {
          const data = JSON.parse(body);
          const temperature = data.temp;
          const pressure = data.pressure;
          
          // Локальная обработка - аномалия?
          if (temperature > 85 || pressure > 120) {
            // Отправляем только критичное в облако
            console.log('ALERT: Anomaly detected', { temperature, pressure });
            // Здесь вызовешь API в облако для логирования
            sendToCloud({ alert: true, temperature, pressure });
          } else {
            // Нормальные данные - агрегируем локально
            console.log('Normal: Data processed locally');
          }
          
          res.writeHead(200);
          res.end(JSON.stringify({ status: 'processed' }));
        } catch (e) {
          res.writeHead(400);
          res.end('Invalid JSON');
        }
      });
    });
    
    server.listen(3000, () => console.log('Edge server on port 3000'));
    
    async function sendToCloud(data) {
      // Батчим алерты, отправляем один раз в минуту
      // Экономим трафик и деньги
    }
    

    Смысл: 99% данных обработано на месте, облако получает только сигналы о проблемах. Трафик снижается на 95%, латенси критичного события - миллисекунды.

    Где это реально работает (и где это оверкилл)

    Edge работает отлично для:

    • IoT-платформ (датчики, камеры, промышленная автоматика)
    • Розницы (учет запасов, фото-видео аналитика на кассах)
    • 5G MEC - операторы ставят серверы прямо на базовых станциях (< 5ms)
    • Автопилоты и AR/VR - нужна локальная обработка для instant feedback
    • Высокочастотный трейдинг - каждая миллисекунда считается

    Но это не нужно для:

    • Обычных веб-приложений (где 100-200ms latency нормально)
    • Простого CRUD без real-time требований
    • Если у тебя 5 пользователей в месяц

    Реальность в РФ: когда это становится выгодным

    Опускаю политику, но фактически: если у тебя есть удаленные офисы, плохие каналы связи или спутниковый интернет - Edge Computing это не люкс, это необходимость. Российские операторы растут медленно, пропускная способность дороговая в провинции. Локальная обработка экономит серьезные деньги.

    Единственный затор: нужны разработчики, которые умеют писать не просто на Node.js/Python, но и оптимизировать под ограниченные ресурсы. Стандартный тестирование на своем MacBook’е здесь не поможет - нужна именно симуляция edge-условий.

    Зачем это вообще лезть сейчас?

    Если ты разрабатываешь что-то, связанное с IoT, автоматизацией или удаленными устройствами - Edge Computing это не будущее, это уже настоящее. Контейнеризация с K3s, кэширование результатов локально, батчинг алертов - это техники, которые экономят реальные деньги прямо сейчас.

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


    0 0 0 Ответить
  • hannadevH
    hannadev
    for...in против Object.keys + for...of: почему прототипы ломают валидацию формы

    for…in и Object.keys() + for…of кажутся похожими способами пройтись по свойствам объекта. Но первый тащит за собой прототипы, а второй - чисто свои ключи. В валидации форм это выливается в баги: проверяешь поля, а вместо них ловишь toString из прототипа.

    Разница критична в реальном коде. for…in перебирает все enumerable свойства, включая унаследованные. Object.keys() фильтрует только собственные. Без hasOwnProperty или современного подхода форма валидируется криво, пропуская ошибки или фейля лишнее.

    Как for…in подцепляет прототипы

    Цикл for…in идет по всем перечисляемым свойствам объекта, включая те, что висят в цепочке прототипов. Представь типичный случай: валидация формы, где объект полей расширяет какой-то базовый Validator. Прототип несет методы вроде isValid, toString, valueOf - все они enumerable по умолчанию.

    В цикле ты ожидаешь только name, email, age. А получаешь их плюс прототипный мусор. Без проверки hasOwnProperty(key) код сломается: вместо валидации полей начнет ковырять методы, которые не предназначены для этого. Современные движки вроде V8 перебирают в порядке создания, но порядок - не спасение от лишних свойств.

    Это классическая грабля для мидлов: пишут валидатор, тестируют на пустом объекте - работает. Добавляют прототип - и привет, утечка логики.

    • Enumerable свойства прототипа участвуют всегда: toString из Object.prototype попадет в цикл, если не фильтровать.
    • Порядок не гарантирован: сначала числовые ключи по возрастанию, потом строковые по созданию - но прототипы мешаются.
    • Символьные ключи игнорируются: for…in работает только со строками, Symbols пропускает.
    Свойство for…in Object.keys()
    Собственные свойства Да Да
    Прототипные свойства Да Нет
    Порядок Сортировка числовых + хронология строк Хронология создания
    Символы Игнор Только строковые

    Object.keys() + for…of: чистый перебор без костылей

    Object.keys() возвращает массив только собственных enumerable свойств. Дальше for…of бежит по нему - никаких прототипов, никакой грязи. В валидации это идеал: проверяешь ровно те поля, что добавил сам.

    Пример: форма с полями userData = {name: ‘’, email: ‘invalid’, age: 150}. Цикл по Object.keys(userData) увидит только эти трое. Никаких toString или hasOwnProperty из прототипа. Производительность? keys() создает массив - да, но для форм это копейки, а предсказуемость бесценна.

    Сравни с for…in + hasOwnProperty: тот же эффект, но boilerplate. А for…of на entries() дает сразу ключ-значение: for (const [key, value] of Object.entries(obj)). Чисто, современно, без var.

    • Только собственные ключи: прототипы отсекаются на старте, hasOwnProperty не нужен.
    • Итерируемость: for…of работает с массивом, порядок как в объекте.
    • Entries для пар: Object.entries() - для ключ-значение без лишних обращений obj[key].
    // Плохо: for...in с прототипами
    const validatorProto = { isValid() { return true; } };
    const formData = Object.create(validatorProto);
    formData.name = '';
    
    for (let key in formData) {
      console.log(key); // name, isValid - мусор!
    }
    
    // Хорошо: Object.keys + for...of
    const cleanKeys = Object.keys(formData); // ['name']
    for (const key of cleanKeys) {
      validateField(formData[key]);
    }
    

    Валидация формы: реальный краш-код

    Возьми типичную задачу: проверить все поля формы перед сабмитом. Поля - объект {email, password, age}. Добавь прототип с методами валидации - и for…in словит их, пытаясь провалить toString как email.

    Без фильтра код выглядит innocently: for (key in formData) { if (!isValid(formData[key])) errors[key] = msg; }. Добавь прототип - и errors заполнится фигней вроде errors.toString = ‘not a string’. Форма не сабмитится по ложным ошибкам.

    Object.keys() решает: только реальные поля. Плюс в валидации учти типы ошибок: valueMissing, typeMismatch, patternMismatch - стандартные от HTML5, но в кастоме их эмулируй на своих полях.

    Таблица сравнения на примере формы:

    Подход Поля Прототип Ошибки в валидации
    for…in name, email toString, valueOf Ложные срабатывания
    Object.keys() + for…of name, email Нет Только поля формы
    for…in + hasOwnProperty name, email Отфильтровано Работает, но verbose
    • Стандартные ошибки: valueMissing для пустых, typeMismatch для email без @.
    • Кастом валидация: проверяй length, pattern - но только на своих ключах.
    • Производительность: для 10 полей разница в памяти negligible, предсказуемость рулит.

    Когда for…in все-таки юзать (редко)

    for…in не мусор полностью. Полезен для introspection: проверить наличие свойств в объекте с прототипами или копировать shallow без lodash. Но в валидации? Забудь.

    Если объект чистый, без прототипов - ок. Но реальный код редко такой. Лучше привыкнуть к Object.keys() - меньше багов, меньше if’ов.

    Не полагайся на legacy-трюки

    hasOwnProperty спасает for…in, но зачем boilerplate, когда Object.keys() решает чище? Подумай о destructuring или entries() - они еще гибче. А если форма большая, вынеси валидацию в WeakMap или Proxy - прототипы не проблема.

    В рефакторе увидишь: половина багов в формах от for…in. Перепиши на keys() + of - и спи спокойно. Осталось копнуть в итераторы глубже или Proxy для валидации on-the-fly.


    0 0 0 Ответить
  • GameFishG
    GameFish
    Where Winds Meet: патч 1.2 с новыми зонами и боссами - стоит ли возвращаться

    Обложка: Where Winds Meet: что принесло первое крупное обновление глобальной версии и стоит ли возвращаться

    Глобальная версия Where Winds Meet получила первое крупное обновление 1.2. Оно вышло в начале года и принесло финал главы Кайфэна, свежие локации и предсезон гильдейских сражений.

    Это важно для тех, кто отошел от игры после релиза в ноябре 2025-го. Everstone Studios держит темп, расширяя контент и оптимизируя под ПК, консоли и мобилки. Теперь есть повод вернуться - особенно если фанатеешь уся-экшен с открытым миром.

    Новые зоны и активности

    Обновление добавило две ключевые локации: Базу Девяти Смертных Путей и Тюрьму Туманного Завесы. Первая - лагерь с событиями и встречами, вторая - пещера-головоломка для исследования.

    В Базе полно мировых активностей: старые плюс новые, включая котиков для погладки с наградами. За них дают предметы на пассивки региона. Есть одноразовые элитки и два мировых босса с по две фазы каждый.

    Сюжетный финал и боссы

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

    Бои подчеркивают выборы: долг против убеждений. Это вписывается в механику личного пути. Доступно после 5 уровня и главы Qinghe Main Chapter: Another New Wing.

    Что добавили в патче 1.2:

    • Новые зоны: Nine Mortal Ways Base, Mistveil Prison.
    • Сюжет: финал Кайфэна, новые цепочки заданий.
    • Боссы: Supreme Freedom, Безымянный генерал.
    • Гильдии: предсезон с шестью матчами.
    • Оптимизации для всех платформ.

    Гильдейские сражения и прогресс

    Запустили предсезон Guild Battle - шесть напряженных матчей. Плюс новые встречи, режимы и системы прогрессии. Мир подняли до 10 уровня.

    Это расширяет социалку и PvP. Подходит для тех, кто играет в компании. Everstone продолжает добавлять контент ежемесячно, как в январском апдейте.

    Технические изменения

    Крупный список фик��ов: оптимизация под ПК, консоли, мобилки. Кроссплатформа работает - с телефонов рубиться с ПКшниками можно.

    После релиза карта выросла на треть в декабре. Теперь еще больше регионов для покорения: горы, города, пещеры. Физика передвижения на уровне.

    Итог обновления

    Патч 1.2 - солидный шаг для Where Winds Meet. Новые зоны, сюжетный хайпоинт и гильдии дают свежий воздух. Возвращаться стоит, если ждешь контента и боевок. Дальше - второй сезон и новые регионы, но пока это планы.


    0 0 0 Ответить
  • kirilljsxK
    kirilljsx
    Платформы безопасности ИИ для продакшена: защита генеративных моделей

    Обложка: Платформы безопасности ИИ для корпоративной разработки: как защитить генеративные модели в продакшене

    Представьте: ваша команда разрабачивает на генеративных моделях, а потом бац - утечка кода или клиентских данных в публичный ChatGPT. Бизнес теряет миллионы, регуляторы давят штрафами, а разработчики в панике ищут костыли. Это не фантастика, а реальность 2025-го: по данным аналитики, утечки через нейросети выросли в 30 раз. Корпоративные платформы безопасности ИИ решают эту рутину, позволяя запускать модели в проде без риска слить инсайд.

    Основные риски и почему игнорировать нельзя

    Генеративный ИИ в продакшене несет четыре ключевых угрозы:

    • Утечка данных: сотрудники пихают конфиденциалку в публичные API, от фрагментов кода до отчетов.
    • Теневой ИИ: народ юзает личные аккаунты ChatGPT, обходя IT-политики.
    • Нарушение compliance: GDPR, ISO 27001 или российские аналоги летят в трубу при внешних запросах.
    • Вредоносный вывод: модели генерят галлюцинации или biased контент, подрывающий репутацию.

    Без платформ безопасности это хаос. Компании вроде Microsoft и IBM уже ввели шлюзы: все запросы фильтруются, PII маскируется, логи пишутся.

    Топ-платформы для защиты генеративных моделей

    Вот проверенные решения, которые разворачиваются в корпоративной инфраструктуре:

    Платформа Ключевые фичи Подходит для
    Microsoft Copilot for Business Корпоративный шлюз, удаление PII, журналирование Общий бизнес, разработка
    ИДА (idabot.ru) Локальная LLM с базой знаний, мультиагенты в защищенном контуре РФ-компании, данные клиентов
    LayerX DLP + браузерный мониторинг, контроль рисков GenAI Предотвращение утечек в реал-тайм
    Ollama + enterprise-модели Локальное развертывание, приватные LLM без облака Конфиденциальный код, финансы
    Solar Group сервис Мультиагентная система в защищенном периметре, сегментация сети Банки, телеком

    Эти платформы интегрируются с существующими стеками: CASB для облаков, DLP для трафика. В России банки и телеком уже разворачивают локальные GPT в своих ЦОДах - профит в нулевом риске утечек.

    Практика: системный промпт для безопасного шлюза

    Чтобы быстро прототипить шлюз на Node.js + OpenAI API, вот готовый пример. Фильтрует PII перед отправкой в модель и логирует.

    // safe-ai-gateway.js
    const OpenAI = require('openai');
    const { Configuration, OpenAIApi } = OpenAI;
    
    const openai = new OpenAIApi(new Configuration({ apiKey: process.env.OPENAI_API_KEY }));
    
    async function safeQuery(userPrompt, sensitivityLevel) {
      // Фильтр PII (упрощенный, в проде юзайте regex или LLM-детектор)
      const piiRegex = /\b(паспорт|ИНН|email|телефон)\b/gi;
      if (piiRegex.test(userPrompt) && sensitivityLevel === 'high') {
        throw new Error('PII detected! Use local model.');
      }
      
      const log = { timestamp: new Date(), prompt: userPrompt, level: sensitivityLevel };
      console.log('Audit log:', log); // В проде - в ELK или DB
      
      const completion = await openai.createChatCompletion({
        model: 'gpt-4',
        messages: [{ role: 'user', content: userPrompt }]
      });
      return completion.data.choices.message.content;
    }
    
    // Использование
    safeQuery('Анализируй отчет: номер клиента 12345', 'low').then(console.log);
    

    Этот код - база для вашего шлюза. Масштабируйте с Redis для кэша и Kafka для логов. Экономит время: вместо ручной модерации - автофильтр.

    Политики и внедрение: шаг за шагом

    Не только софт, но и правила:

    1. Классифицируйте данные: Уровень 1 - публичные (ChatGPT OK), Уровень 4 - строго секрет (только локально).
    2. Одобренный список: GitHub Copilot Business для кода, ИДА для аналитики.
    3. Обучение: Запрет личных аккаунтов, штрафы за shadow AI.
    4. Мониторинг: CASB + DLP сканируют трафик.

    BigTech как Google с SAIF добавляют аудит на всех этапах lifecycle модели.

    Итог: что дальше для вашего продакшена?

    Платформы вроде ИДА или LayerX - не роскошь, а must-have для любого бизнеса с GenAI. Они снижают риски на 90%, позволяют масштабировать без паранойи. В РФ это особенно актуально: локальные ЦОДы решают вопросы с суверенитетом данных.

    А вы уже ввели шлюзы для ИИ или все еще на публичных API? Какие платформы юзаете и какие косяки с утечками ловили? Делитесь в коммах, обсудим реальные кейсы!


    0 0 0 Ответить
  • kirilljsxK
    kirilljsx
    AI-ассистенты в разработке: от генерации кода до автотестов и документации

    Обложка: AI-ассистенты в разработке: от генерации кода к автоматизации тестирования и документации

    Представьте: вы тратите часы на boilerplate-код, тесты пишете вручную, а документация устаревает через неделю. AI-ассистенты решают эту рутину, ускоряя разработку в 2-3 раза и позволяя фокусироваться на бизнес-логике, которая приносит деньги.

    Они уже не просто автодополняют — генерируют функции, ловят баги, пишут тесты и даже документацию. В 2026-м это стандарт для команд, где время = профит.

    Генерация кода: от нуля до работающего прототипа

    AI берет текстовое описание и выдает готовый код. ‘Напиши валидацию email на TypeScript’ — и вуаля, функция с regex и типизацией. Это спасает на старте проекта, когда нужно быстро набросать MVP.

    Ключевой профит: 50-70% времени на шаблонный код уходит. Вместо копипасты из StackOverflow — один промпт. Но всегда проверяйте: ИИ иногда генерит уязвимости или неоптимальный код.

    Автоматизация тестирования: тесты пишутся сами

    Раньше unit-тесты — это боль: покрытие 30%, фейлы вручную. Теперь AI анализирует функцию и генерирует тесты с edge-кейсами. Для JS/TS/Python есть агенты вроде EarlyAI или встроенные в IDE.

    Пример на Python с pytest — промпт для Claude или аналогичной модели:

    Сгенерируй unit-тесты для функции def calculate_discount(price: float, user_type: str) -> float:
        if user_type == 'premium':
            return price * 0.8
        return price * 0.9
    Покрытие: happy path, edge-кейсы (price=0, negative), invalid user_type.
    Формат: pytest, с assertions и fixtures.
    

    Результат: 10+ тестов за секунды, покрытие 90%+. Интегрируйте в CI/CD — и ревью ускоряется.

    Фича Время вручную С AI
    Unit-тесты 2-4 часа 15 мин
    Интеграционные 1 день 1 час
    Code review 30 мин/PR 5 мин

    Документация и рефакторинг: код читается как книга

    AI сканирует репозиторий, добавляет docstrings, README и даже диаграммы. Для рефакторинга: ‘Сделай этот класс более масштабируемым’ — и получает предложения по паттернам.

    В РФ это особенно актуально: российские решения вроде SourceCraft или Cloud.ru Evolution соответствуют 152-ФЗ, работают on-premise и интегрируются с JetBrains/VS Code. Не нужно бояться утечек данных в зарубежные LLM — локальные модели типа KodaCode дают приватность и скорость без санкционных рисков.

    Пример JS-кода для автоматизации доков через API (Node.js + OpenAI-подобный эндпоинт):

    const fs = require('fs');
    const axios = require('axios');
    
    async function generateDocs(filePath) {
      const code = fs.readFileSync(filePath, 'utf8');
      const prompt = `Сгенерируй JSDoc для этого кода: ${code}`;
      
      const response = await axios.post('/api/ai', { prompt });
      fs.writeFileSync(`${filePath}.docs.md`, response.data);
      console.log('Доки готовы!');
    }
    
    generateDocs('utils.js');
    

    Запускаете скрипт — и вся папка задокументирована. Масштабируйте на монопо.

    Гибрид человека + AI

    В enterprise-командах комбо: IDE-агент для daily tasks, CLI для infra. Но слабые места остаются — сложная логика и архитектура требуют рук. Гибрид дает x2 продуктивность без потери качества.

    В России это уже работает: SourceCraft автоматизирует разметку задач, отчеты, ревью по корпоративным стандартам. Импортозамещение на уровне — профит для бизнеса.

    А вы уже юзаете AI для тестов или доков? Какой инструмент сэкономил больше времени — Copilot, Cursor или наш SourceCraft? Делитесь в комментах, обсудим реальные кейсы!


    0 0 0 Ответить
  • hannadevH
    hannadev
    async/await vs Promise.all: как не тормозить при загрузке данных

    Если ты загружаешь список пользователей и делаешь три отдельных await подряд - каждый ждёт завершения предыдущего. Результат: три запроса выполняются друг за другом, хотя могли бы стартовать одновременно. Promise.all решает эту проблему, запуская всё параллельно и экономя время.

    Это не просто теория. На практике разница может быть 3-5 секунд против 1 секунды. Для user experience это критично, для батареи мобильного - тоже.

    Где настоящая беда: последовательный await

    Пред­ставь такой код: ты запрашиваешь данные пользователя, потом его посты, потом комментарии. Каждый запрос - это отдельный await, и они выстраиваются в очередь.

    async function fetchUserData(userId) {
      const user = await fetch(`/api/users/${userId}`);
      const posts = await fetch(`/api/posts/${userId}`);
      const comments = await fetch(`/api/comments/${userId}`);
      return { user, posts, comments };
    }
    

    Это работает как на одной плите готовить три блюда по очереди. Сначала борщ (2 сек), потом салат (1 сек), потом компот (0.5 сек). Итого - 3.5 секунды. Но ведь все три можно готовить одновременно на разных конфорках!

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

    Вот почему такой подход опасен для production:

    • Ненужные задержки: три параллельных сетевых операции могут занять одну, максимум 1.5 секунды вместо 3.5.
    • Плохой UX: пользователь смотрит на спиннер дольше, чем нужно.
    • Нагрузка на сервер: если у тебя тысяча юзеров делает такое одновременно, серверу придётся держать больше соединений дольше.
    • Батарея: мобильные устройства расходуют энергию не только на передачу данных, но и на ожидание результатов.

    Promise.all: как готовить всё сразу

    Вместо того чтобы ждать один результат, потом запускать следующий запрос, ты запускаешь все одновременно. Promise.all берёт массив промисов, инициирует их все и ждёт, пока все они разрешатся.

    async function fetchUserData(userId) {
      const [user, posts, comments] = await Promise.all([
        fetch(`/api/users/${userId}`),
        fetch(`/api/posts/${userId}`),
        fetch(`/api/comments/${userId}`)
      ]);
      return { user, posts, comments };
    }
    

    Разница огромная. Все три fetch стартуют мгновенно. Они работают параллельно на уровне сетевого стека (это не истинная многопоточность, но для операций ввода-вывода - результат идентичен). Функция ждёт только самый медленный запрос. Если каждый занимает примерно секунду, итого - всё равно около секунды, а не трёх.

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

    Основные преимущества:

    • Скорость: все независимые операции выполняются одновременно.
    • Простота обработки ошибок: один try-catch ловит ошибки из всех промисов в массиве.
    • Читаемость: видно сразу, что это параллельные операции, а не последовательные.
    • Меньше нагрузки: ты не держишь соединение активным дольше, чем нужно.

    Когда async/await последовательный - это правильно

    У последовательного подхода есть свой смысл. Если второй запрос зависит от результата первого, ты просто обязан ждать.

    async function fetchUserWithRole(userId) {
      const userResponse = await fetch(`/api/users/${userId}`);
      const user = await userResponse.json();
      
      const roleResponse = await fetch(`/api/roles/${user.roleId}`);
      const role = await roleResponse.json();
      
      return { user, role };
    }
    

    Здесь второй запрос нужен roleId из первого ответа. Иначе это не сработает. И в этом случае последовательность - не недостаток, а требование логики.

    Ещё несколько сценариев, где последовательность оправдана:

    • Валидация перед следующим шагом: сначала проверил данные, потом сохранил их.
    • Зависимые операции: загрузил конфиг, потом инициализировал модули на его основе.
    • Критичное порядок: например, начисление баланса после проверки прав доступа.
    • Обработка ошибок: если первый запрос упал, нет смысла делать второй.

    Гибридный подход: микс параллели и последовательности

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

    async function fetchUserWithFriends(userId) {
      // Шаг 1: параллельно
      const [userResponse, friendsResponse] = await Promise.all([
        fetch(`/api/users/${userId}`),
        fetch(`/api/friends/${userId}`)
      ]);
      
      const user = await userResponse.json();
      const friends = await friendsResponse.json();
      
      // Шаг 2: параллельно (зависит от результата шага 1)
      const friendDetails = await Promise.all(
        friends.map(friend => fetch(`/api/users/${friend.id}`).then(r => r.json()))
      );
      
      return { user, friends, friendDetails };
    }
    

    Этот паттерн часто встречается в реальных приложениях:

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

    Ошибки и граничные случаи

    Примерно половина багов с Promise.all происходит из-за невнимательности. Вот типичные ловушки:

    Проблема 1: одна ошибка рушит всё

    Если хотя бы один промис из массива rejected, Promise.all вернёт ошибку. Остальные промисы могут остаться в памяти незаконченными. Часто это нормально, но иногда нужно, чтобы все операции выполнились, даже если какие-то упали.

    // Плохо: если один fetch упадёт, остальные будут заморожены
    await Promise.all([
      fetch('/api/data1').then(r => r.json()),
      fetch('/api/data2').then(r => r.json()),
      fetch('/api/data3').then(r => r.json())
    ]);
    

    Для этого есть Promise.allSettled - он ждёт все промисы, независимо от результата:

    const results = await Promise.allSettled([
      fetch('/api/data1').then(r => r.json()),
      fetch('/api/data2').then(r => r.json()),
      fetch('/api/data3').then(r => r.json())
    ]);
    // results содержит {status, value} или {status, reason} для каждого
    

    Проблема 2: забыли обернуть в Promise

    // Баг: это не асинхронная функция, она вернёт undefined
    const fetchUser = userId => {
      fetch(`/api/users/${userId}`)
    };
    
    await Promise.all([fetchUser(1), fetchUser(2)]);
    

    Практически невозможно уловить без линтера.

    Проблема 3: утечки памяти от незавершённых промисов

    Если ты перепутал и запустил Promise.all, но никогда не awaited результат, промисы могут остаться висеть в памяти. Это редко, но случается при неправильной обработке ошибок.

    Типичные случаи, где нужна осторожность:

    • Массивы, которые могут быть пустыми (Promise.all([]) резолвится в пустой массив - это okay).
    • Промисы, которые никогда не резолвятся (например, подписки на события - используй abortController).
    • Вложенные Promise.all (работают, но код становится сложнее читать).
    • Смешивание синхронного и асинхронного кода в одном массиве (Promise.all это переносит, но лучше явно оборачивать).

    Сравнение в цифрах

    Сценарий Последовательный await Promise.all Разница
    3 запроса по 1 сек 3 сек 1 сек 3x быстрее
    10 запросов по 0.5 сек 5 сек 0.5 сек 10x быстрее
    1 запрос 2 сек + 2 по 0.5 сек (с зависимостью) 3 сек 2.5 сек 1.2x быстрее
    Зависимые операции (требуют последовательность) необходимо нет смысла N/A

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

    На что не стоит забивать голову

    Часто разработчики переживают: “Может ли Promise.all создать проблемы с производительностью?” На самом деле - нет, если ты не запускаешь тысячи запросов одновременно. Браузер и Node.js нормально справляются с 20-50 параллельными сетевыми операциями. Если тебе нужно больше, это уже архитектурный вопрос - может, нужен бекенд, который агрегирует данные вместо того, чтобы фронтенд дёргал API по одному.

    Ещё один момент: Promise.all работает не с настоящей многопоточностью. JavaScript по-прежнему однопоточный. Но для операций ввода-вывода (сетевые запросы, файловые операции, работа с БД) это не важно - операционная система и браузер справляются с параллелизмом на своём уровне. Promise.all просто позволяет тебе не блокировать JavaScript-поток, пока операции выполняются.


    0 0 0 Ответить
  • GameFishG
    GameFish
    Russian Games Festival 2026 на Steam: что известно и чего ждать

    Обложка: Russian Games Festival 2026: какие российские игры покажут на Steam и стоит ли стримеров ждать хайпа

    Russian Games Festival на Steam - это ежегодный онлайн-фестиваль, где российские разработчики показывают свои проекты. Событие объединяет инди-студии, небольшие команды и издателей, чтобы представить новые игры широкой аудитории платформы. Для игроков это шанс открыть для себя интересные проекты, которые могут не попасть в топ, а для стримеров и контент-мейкеров - повод поискать контент с потенциалом.

    Пока информация о дате проведения Russian Games Festival 2026 не подтверждена публично, но фестиваль давно уже стал традицией Steam. В 2025 году событие прошло и собрало проекты от российских разработчиков. Ожидается, что в 2026 году сценарий повторится - объявление даты, список участников, демо-версии игр и возможные скидки.

    Что обычно происходит на Russian Games Festival

    Фестиваль на Steam работает по проверенной схеме. На платформе открывается специальная страница, на которой собираются игры от российских авторов - от инди-проектов до более амбициозных тайтлов. Разработчики получают видимость перед аудиторией, которая специально ищет новинки, а игроки имеют доступ к демо-версиям, трейлерам и информации от авторов.

    Основные элементы события:

    • Витрина игр от российских разработчиков
    • Демо-версии для скачивания и тестирования
    • Скидки на готовые проекты
    • Трансляции и интервью с авторами
    • Возможность для инди-разработчиков получить покрытие и аудиторию

    Да, на платформе есть и другие тематические фестивали - Detective Fest, Typing Fest, Auto-Battler RPG Fest и ещё около 22 тематических событий в 2026 году. Но Russian Games Festival выделяется географическим подходом, он работает специально для выпирания русскоязычной сцены разработки.

    Стоит ли ждать хайпа стримерам

    Краткий ответ: зависит от качества каталога. Длинный ответ требует контекста.

    Стримеры обычно ловят на Russian Games Festival два типа контента. Первый - это действительно интересные проекты, которые потом могут выстрелить на общем Steam. Второй - специфичный, когда стример намеренно ищет необычные или забавные игры для развлечения зрителей.

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

    Что может привлечь внимание:

    • Необычный геймплей или арт-стиль
    • История про восстановление студии или её успех
    • Проект, который работал в разработке долго и вот наконец выходит
    • Колаб известного стримера с разработчиком
    • Какая-нибудь полемика или скандал в инди-сцене

    Без этого фестиваль - это просто витрина. Полезная для игроков, которые ищут нишевой контент, но не обязательно хайповая для основного стрима.

    Что еще важно знать

    В 2026 году Steam активно развивает систему тематических фестивалей. Это значит, что Russian Games Festival будет конкурировать с другими событиями за внимание и покрытие. Платформа пробует разные подходы: от жанровых (RPG, стратегии, экшн) до географических (русские, украинские игры).

    Для российских разработчиков такие события критичны. Это шанс получить трафик на фоне зарубежной конкуренции и экспортировать проект на Запад. Для игроков - это возможность открыть для себя что-то свежее, не пробиваясь через топ-100 Steam.

    Пока дата не объявлена официально, стоит следить за новостями Steam и соцсетями издателей. Обычно фестивали анонсируют за неделю-две до старта, поэтому информация появится дальше по времени.


    Russian Games Festival 2026 - это нишевое, но полезное событие для тех, кто ищет интересные инди-проекты или хочет поддержать русскоязычных разработчиков. Для стримеров это хороший повод поискать контент, но без гарантий на супер-хайп. Качество каталога будет определять, насколько интересным окажется фестиваль для аудитории.


    0 0 0 Ответить
Популярные темы:

  • Критическая уязвимость в React.js Next.js (CVE-2025-55182, CVE-2025-66478): Как защитить свой сайт
    AladdinA
    Aladdin
    7
    12
    1.2k

  • Полный гайд по работе с NodeBB CLI
    D
    DeepSeeker
    6
    3
    157

  • for или foreach в javascript: в каких случаях что использовать
    D
    DeepSeeker
    5
    2
    162

  • Подготовка к собесам фронтенд
    Dastan SalmurzaevD
    Dastan Salmurzaev
    5
    5
    198

  • Передача типов в TypeScript в под функции
    kirilljsxK
    kirilljsx
    4
    5
    225

  • Исчерпывающее руководство по конфигурации Nginx
    undefined
    4
    1
    219

  • Проверка стала проще с Zod: как обеспечить точность и качество форм
    kirilljsxK
    kirilljsx
    3
    8
    1.1k

  • Bruno - новый клиент для API (Замена PostMan Insomnia)
    ManulM
    Manul
    3
    2
    1.8k

  • Vue.js и React — необычное сравнение
    D
    DeepSeeker
    3
    10
    1.1k

  • Оптимизация React js приложений. Использование функции debounde()
    ManulM
    Manul
    3
    5
    544

  • Провайдеры в Nest JS - 1.3
    undefined
    3
    1
    362

  • Полный гайд по команде LFTP: Работа с локальными и удалёнными серверами
    undefined
    3
    1
    654

Пользователи в Сети:

Статистика:

88

В сети

321

Пользователи

1.9k

Темы

2.9k

Сообщения

Категории

  • Главная
  • Новости
  • Фронтенд
  • Бекенд
  • Языки программирования

Контакты

  • Сотрудничество
  • info@exlends.com

© 2024 - 2026 ExLends, Inc. Все права защищены.

Политика конфиденциальности
  • Войти

  • Нет учётной записи? Зарегистрироваться

  • Войдите или зарегистрируйтесь для поиска.
  • Первое сообщение
    Последнее сообщение
0
  • Лента
  • Категории
  • Последние
  • Метки
  • Популярные
  • Пользователи
  • Группы