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

  • en
    Humor
    News
    AI
    Programming languages
    Frontend
    GameDev

  • Блоги

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

  • Все категории
  • GameFishG
    GameFish
    Pathologic 3: почему Прототип жрёт стимуляторы и как не остаться без патронов

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

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

    Многие новички теряют заряды зря и застревают в чумных районах. Гайд разберёт механику заправки, локации ингредиентов и тактики, чтобы Прототип всегда был наготове. Без него перемещения по Городу - чистый лотерейный билет.

    Почему Прототип требует стимуляторов

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

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

    Стандартный набор для заправки:

    • Стимулятор: Бычья желчь.
    • Анестетик: Новокаин.
    • Токсин: Белладонна.

    Один комплект даёт полную зарядку. Есть особые заряды для Шабнаков - из чумных цветов, но они одноразовые и портятся к утру.

    Где и как заправлять Прототип

    Заправка возможна только в Стилуотере (Омуте) - на первом этаже, в комнате со столами. Ищите аппарат с слотами. Процесс:

    1. Соберите три ингредиента.
    2. Загрузите в слоты - порядок не важен.
    3. Активируйте нагрев (горелка).
    4. Выполните мини-игру по смешиванию.

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

    Советы по локациям ингредиентов:

    • Бычья желчь: аптеки, тела в заражённых зонах.
    • Новокаин: медицинские шкафы в домах.
    • Белладонна: чумные цветы или у NPC.

    Запасайтесь на 2-3 дня вперёд, если планируете рейды в Столицу или чумные районы.

    Тактики, чтобы не остаться без патронов в бою

    Прототип имеет два режима: обычный (клавиша 1) для миазмов и особый (клавиша 3) для боссов. Обычный жрёт меньше, но в толпе Шабнаков экономьте - 3-4 выстрела на группу. В заражённых зонах активируйте перед входом, чтобы не тратить вхолостую.

    Эффективные приёмы:

    • Перед чумным районом ищите Клару - она подсказывает цветы для спецзаряда.
    • Берите пробы с чумных цветов (по звуку), крафтите в Омуте - убивает Шабнака на день.
    • Ходите с низким ХП и запасом лечилок, чтобы не рисковать в стычках.
    • Зажигайте сигнальные костры - они отвлекают сущностей, снижая расход патронов.

    В Столице Прототип спасает от чёрного пара: 20 выстрелов хватит на проход, но не задерживайтесь. Если заряды кончились - бегите или ищите обход. Последствия: без Прототипа чума распространяется быстрее, квесты срываются, диагнозы пациентов уходят в минус.

    Неизвестно: точный расход спецзарядов в поздней игре и взаимозаменяемость редких ресурсов - гайды противоречат. Тестируйте сами.

    Итоговые лайфхаки

    Приоритет - Хорхой с его обменом. Заряжайтесь nightly, экономьте на миазмах, спецзаряды только под Шабнаков. Прототип - не пушка, а выживальщик: умейте ждать и планировать. С ним Pathologic 3 перестаёт душить рандомом.


    0 0 0 Ответить
  • kirilljsxK
    kirilljsx
    First-Party Data для B2B SaaS: Пайплайны Zero-Party без Third-Party Cookies

    Обложка: First-Party Data Strategy for B2B SaaS: Building Zero-Party Data Pipelines While Third-Party Cookies Phase Out

    Третьи cookies умирают, а B2B SaaS-команды тонут в мусорных лидах и слепой рекламе. Без точных данных из ваших каналов ABM-кампании превращаются в лотерею, где профит уходит конкурентам. Переходим на first-party и zero-party data: собираем сами, персонализируем на ура и бьем по конверсиям без риска блокировок.

    First-party data - это золото, которое вы добываете из своих источников: сайт, email, CRM, app. Zero-party - еще круче, когда юзеры сами делятся предпочтениями через опросы или профили. Точность на голову выше third-party, плюс полная compliance с GDPR и новыми правилами браузеров. В B2B это значит меньше фрикшена в sales, выше ROI от demand gen и персонализация, которая режет generic-кампании как ножом.

    Шаги по сбору и активации

    1. Определите цели и метрики. Хотите поднять retention? Улучшить targeting в ABM? Свяжите data с KPI: CAC, LTV, conversion rate. Аудит существующих источников - CRM, GA4, email-логи - покажет gaps.

    2. Собирайте из всех каналов. Website visits, blog views, email opens, support tickets. Используйте server-side tracking, чтобы обойти adblockers и cookie-блоки. В B2B это дает профили аккаунтов для ABM: кто качал whitepaper, кто кликал demo.

    3. Zero-party: просите напрямую. Встраивайте quizzes, preference centers в лендинги. ‘Какой pain point вас бесит?’ - и вуаля, сегменты готовы для nurture.

    4. Унифицируйте и очищайте. Интегрируйте CRM (HubSpot/Salesforce) с аналитикой. Dedupe, validate - без этого data гниет. Ключевой инсайт: 80% B2B-лидов мусор из-за dirty data.

    5. Активируйте в маркетинге. Персональные emails по engagement history, content recs по industry, sales insights для outreach. В ABM фокусируйтесь на hot accounts.

    Практика: Python-пайплайн для Zero-Party Data

    Вот реальный скрипт на Python для парсинга form-заявок из SaaS-лендинга, zero-party данных (preferences) и фидинга в CRM via API. Экономит часы ручной обработки, масштабируется на тысячи лидов.

    import requests
    import json
    from typing import Dict, Any
    
    # Пример: webhook от form (Name, Email, Preferences: ['AI', 'Automation'])
    def process_zero_party_data(payload: Dict[str, Any]) -> None:
        # Валидация и clean
        email = payload.get('email', '').lower().strip()
        if '@' not in email:
            return
        
        # Zero-party: сегменты по prefs
        prefs = payload.get('preferences', [])
        segment = 'AI' if 'AI' in prefs else 'General'
        
        # Фид в CRM (HubSpot API example)
        crm_data = {
            'properties': {
                'email': email,
                'lifecyclestage': 'lead',
                'segment': segment
            }
        }
        response = requests.post(
            'https://api.hubapi.com/crm/v3/objects/contacts',
            headers={'Authorization': 'Bearer YOUR_API_KEY', 'Content-Type': 'application/json'},
            json=crm_data
        )
        if response.status_code == 201:
            print(f'Lead {email} added to {segment} segment')
    
    # Тест
    webhook_payload = {
        'email': 'lead@example.com',
        'preferences': ['AI', 'Automation']
    }
    process_zero_party_data(webhook_payload)
    

    Запускайте на serverless (Vercel/AWS Lambda), цепляйте к form-submit. Добавьте ML для ICP (ideal customer profile) - анализируйте prefs через embeddings. Профит: лиды сегментированы за секунды, ABM на автопилоте.

    Таблица: First vs Third-Party в B2B

    Аспект First/Zero-Party Third-Party
    Точность Высокая (собранно вами) Низкая (агрегат)
    Compliance Полная (consent-based) Риск блокировок
    Персонализация Точная (behavior + prefs) Generic
    Стоимость Низкая долгосрочно Дорогая подписка
    ABM ROI +30-50% conversions Статистика в жопе

    Масштаб для РФ и итог

    В РФ это актуально: Яндекс и VK уже душат third-party, плюс ФЗ-152 давит. Server-side на базе 1C-Bitrix или custom Node.js решает 90% кейсов без вендор-lock. Но legacy-системы тормозят - мигрируйте на headless CMS с API-first.

    В итоге, first-party pipelines - не хайп, а necessity для B2B SaaS. Строите их сейчас - лидируете завтра. А как вы собираете zero-party? Через quizzes в Telegram-ботах или email-preferences? Делитесь в коммах, разберем ваш стек!


    0 0 0 Ответить
  • hannadevH
    hannadev
    find() против findIndex(): когда брать элемент, а когда его позицию в массиве пользователей

    В JS при поиске в массивах пользователей часто путают find() и findIndex(). Один даёт сам объект, другой - его индекс. Разберём, когда какой брать, чтобы не плодить костыли и не тормозить код.

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

    find() - когда нужен сам юзер

    Метод find() пробегает массив слева направо и возвращает первый элемент, который проходит предикат. Если ничего не нашёл - кидает undefined. Просто и удобно, когда тебе надо сразу работать с объектом: показать данные, отправить на сервер или обновить свойства.

    Представь массив users с кучей полей: id, name, role, active. Хочешь найти админа - find(user => user.role === ‘admin’). Получишь объект целиком. Дальше user.name в шаблон, или API.patch(/users/${user.id}). Линейный поиск, O(n), но если массив не гигантский - норм.

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

    • Возвращает: элемент или undefined
    • Когда брать: фильтры UI, экспорт данных, быстрая валидация
    • Плюсы: сразу объект, нет нужды в дополнительном arr[index]
    • Минусы: нет позиции, если надо мутировать массив - ищи заново
    Сценарий find() Результат
    Найти активного юзера users.find(u => u.active) {id: 5, name: ‘Bob’} или undefined
    Проверить роль users.find(u => u.role === ‘admin’) Объект админа
    Обновить email const user = users.find(…); user.email = ‘new’ Работает, но без splice

    findIndex() - позиция для мутаций

    findIndex() делает то же, но возвращает индекс первого подходящего элемента. Не нашёл - -1. Идеально, когда позиция нужна: splice для удаления, замена через arr[index] или вставка рядом.

    С тем же массивом users: хочешь удалить неактивного - const idx = users.findIndex(u => !u.active); if (idx > -1) users.splice(idx, 1). Безопасно, один проход. Или обновить: users[idx].score += 10. Никаких лишних find после.

    Ключевой нюанс: проверка на -1, а не undefined. Многие пишут if (idx !== undefined) - и ловят баг, потому что -1 falsy, но валидный. Ещё: если массив sparse (с holes) - индексы реальные, пропуски игнорирует.

    • Возвращает: индекс или -1
    • Когда брать: delete/update в месте, сортировка по позиции, валидация уникальности
    • Плюсы: один вызов для мутации, работает с мутабельными структурами
    • Минусы: потом arr[idx] для доступа к элементу
    Сценарий findIndex() Результат
    Удалить юзера users.findIndex(u => u.id === 42) 3 или -1, потом splice
    Заменить роль const idx = …; users[idx].role = ‘user’ Прямо в массиве
    Проверить дубль users.findIndex(u => u.email === ‘test’) > -1 true/false без элемента

    Реальные грабли с массивом пользователей

    Когда find() подводит

    В фильтре списка юзеров: const admin = users.find(u => u.role === ‘admin’); render(admin). Нормально. Но если потом удалить: users.splice(users.findIndex(u => u.id === admin.id), 1) - два прохода, тормоза.

    Или валидация: if (!users.find(u => u.email === input)) addUser(). Линейно каждый раз. Лучше комбо: idx = findIndex, if (idx === -1) push.

    Ещё утечка: find держит ссылку на объект, мутации через него меняют оригинал. В immutable коде это баг.

    • Дубликат поиска: find + findIndex
    • Проверка if (find()) вместо if (findIndex() > -1)
    • Забыл про undefined vs -1 в логах

    findIndex() в ловушках

    Хочешь все индексы дублей - не выйдет, только первый. Для этого reduce или filter с indexOf.

    В React state: setUsers(users.splice(idx,1)) - мутация снаружи, ререндер не сработает. Используй immer или новый массив.

    Сложные предикаты: user => user.profile?.settings?.notify - если profile null, краш. Добавь safe checks.

    • Только первый матч
    • Мутация state без триггера
    • Sparse arrays: findIndex видит только hasOwnProperty

    Сравнение на примерах кода

    Возьмём типичный массив:

    const users = [
      {id:1, name:'Alice', role:'user'},
      {id:2, name:'Bob', role:'admin'},
      {id:3, name:'Charlie', role:'user', active:false}
    ];
    

    Задача 1: Показать админа. find() - const admin = users.find(u => u.role === ‘admin’); console.log(admin.name); // ‘Bob’

    Задача 2: Удалить неактивного. idx = users.findIndex(u => !u.active); splice - чисто.

    find() vs findIndex()

    Задача find() findIndex() Победитель
    Показать данные ✅ {obj} ❌ arr find
    Удалить/обновить ❌ два вызова ✅ idx findIndex
    Проверить наличие ❌ !!obj ✅ idx > -1 findIndex (быстрее)
    Ссылки/иммутабель ⚠️ мутирует ⚠️ то же -

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

    Оба метода - линейный поиск, короткие-цепочки оптимизаций в V8. Но findIndex чуть быстрее: возвращает number, не объект (heap allocation меньше).

    В огромных массивах (10k+ юзеров) - подумай про Map по id: new Map(users.map(u => [u.id, u])). Тогда get(id) O(1). find/findIndex - fallback для сложных фильтров.

    Не путай с indexOf - строгий ==, без предиката.

    • Масштаб: до 1k - любой, >10k - Map/Set
    • Immutable: immer-produce(users, draft => draft.splice(idx,1))
    • TypeScript: find(), findIndex()

    Вместо костылей - микро-хелперы

    function findById(users, id) {
      const idx = users.findIndex(u => u.id === id);
      return idx > -1 ? {user: users[idx], idx} : null;
    }
    

    Получаешь и элемент, и позицию одним махом. Меньше багов, переиспользуемо. Или split: useFind для рендера, useFindIndex для CRUD.

    В hooks: const [activeIdx, setActiveIdx] = useState(-1); const user = users[activeIdx];

    Багхантинг: типичные ошибки

    // ❌ Плохо
    if (users.find(u => u.id === id)) { /* do */ } // falsy obj?
    
    // ✅
    const idx = users.findIndex(u => u.id === id);
    if (idx > -1) { users.splice(idx, 1); }
    

    Ещё: const user = users.find(…); delete user - удалит свойство, массив intact. Нужен splice.

    • if (!find()) вместо idx === -1
    • find в render React - ререндеры
    • Забыли break в custom loop

    Когда оба - перебор

    Нужен ли вообще поиск? Если users по id уникальны - Map с самого начала. const userMap = new Map(users.map(u => [u.id, u])); userMap.get(id)?.delete() нет, Map не мутирует элементы так.

    Для ролей/статусов - группируй заранее: const byRole = groupBy(users, ‘role’). Или lodash.groupBy, но npm hell - напиши свой.

    Инструменты для больших массивов

    Map/Set как альтернатива

    // Фильтр по id
    const userMap = new Map(users.map(u => [u.id, u]));
    const adminIds = [2,5];
    const admins = adminIds.map(id => userMap.get(id)).filter(Boolean);
    

    O(1) lookup, но для динамических фильтров (role + active) - hybrid.

    Массив Map Когда
    100 юзеров - findIndex для CRUD
    10k+ ✅ get(id)
    Комплексный поиск filter Предварительно индексируй

    Неочевидные edge-кейсы

    Пустой массив: find() - undefined, findIndex() - -1. Оба falsy, но console.log разница видна.

    thisArg: редко юзают, но callback.call(thisArg, el, i, arr). Для class методов.

    Proxy массив: работает, но get trap может сломать.

    • NaN в предикате
    • Circular refs в users
    • TypedArray вместо Array

    Хуки вместо методов

    В React/Vue: custom hook findUserById(users, id) { const idx = …; useMemo… } кэшируй.

    Итог: find для чтения, findIndex для правок. В 80% кейсов с пользователями позиция нужнее.

    Что меняет TypedArray и Wasm

    В WebAssembly массивы - TypedArray, find/findIndex есть, но быстрее на 20-30%. Для heavy фильтров мигрируй.

    Оставь за кадром: polyfill для IE (никому), или findLastIndex в ES2023 - для reverse поиска. Подумай над hybrid Map + индексами для 100k юзеров. В реальном проекте профиль и выбирай.


    0 0 0 Ответить
  • GameFishG
    GameFish
    Pathologic 3: туториалы по Прототипу запутают новичков еще больше

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

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

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

    Что происходит с Прототипом на практике

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

    Для заправки нужны три компонента:

    • Стимулятор (обычно бычья желчь)
    • Анестетик (новокаин)
    • Токсин (белладонна)

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

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

    Хорхой спасает или усложняет

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

    В теории это решает проблему поиска компонентов. На практике:

    • Новичок может пройти мимо Хорхоя и не понять, что это был важный персонаж
    • Ингредиенты могут быть дорогими, и неясно, стоит ли их скупать заранее или копить ресурсы на лечение
    • Туториал не объясняет, как часто нужно заряжать Прототип, чтобы не остаться без запасов в критический момент

    Гайды на разных сайтах советуют “запастись ими в дни, когда вы планируете много перемещаться”. Но как новичок узнает, сколько потребуется? Только методом тыка.

    Три слоя информации, которые не складываются в одну

    Проблема в том, что информация разбросана по разным источникам и уровням игры:

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

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

    Механика дней добавляет еще больше путаницы

    Игра использует меню мыслей (нажать J на клавиатуре), где показаны все 12 дней с краткими заметками. Идея хороша, но выполнение оставляет желать лучшего:

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

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

    Что говорит комьюнити

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

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

    Итог: помощь, которая запутывает

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

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


    0 0 0 Ответить
  • kirilljsxK
    kirilljsx
    Кросс-функциональный разработчик 2026: мобила + DevOps + ИИ-тесты

    Обложка: Кросс-функциональные разработчики 2026: как совмещать мобильную разработку с DevOps и ИИ-автоматизацией UI-тестов

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

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

    Давай разберемся, как это все устроено.

    Мобильная разработка встречает DevOps

    Раньше было просто: разработчик написал код, отправил QA, QA нашел баги, разработчик чинил. Теперь этот процесс полностью автоматизирован и встроен в пайплайн. И это твоя ответственность.

    Суть в том, что автоматизированное тестирование мобильных приложений уже не роскошь - это обязательная часть CI/CD. Для мобильных проектов стандарт это Appium или Maestro, интегрированные прямо в GitLab CI или GitHub Actions. Когда ты закомитил код, тесты запускаются параллельно на нескольких исполнителях, ты видишь результаты через 5-10 минут.

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

    • Docker и контейнеризация - как собрать образ с тестами, как пробросить конфиги, как запустить его в облачной ферме
    • Kubernetes и оркестрация - если проект масштабный, нужно понимать, как тесты распределяются между нодами
    • GitLab CI / GitHub Actions - структура .gitlab-ci.yml, stages, artifacts, параллельное выполнение (это не опционально)
    • Allure TestOps - интеграция отчетов, чтобы вся команда видела статус в реальном времени

    Пример конфига, который должен собрать даже junior мобильный разработчик:

    stages:
      - test
      - report
    
    mobile_tests:
      stage: test
      image: appium/appium:latest
      script:
        - npm install
        - npx appium --port 4723 &
        - sleep 5
        - npx wdio run wdio.conf.js --baseUrl=$TEST_URL
      parallel:
        matrix:
          - DEVICE: ["iPhone_14", "Android_12", "Android_13"]
      artifacts:
        reports:
          junit: ./test-results.xml
        paths:
          - ./test-results/
    

    Даже если ты не DevOps - ты должен это писать. Это базовая грамотность.

    ИИ как решение для хрупкости автотестов

    А теперь самое интересное. Self-healing тесты - это не фантазия, это реальность 2026-го. И это меняет всю игру.

    Проблема UI-автотестов известна давно: верстальщик переехал кнопку на 10 пикселей - и весь локатор валится. Раньше это означало: QA сидит, чинит локаторы вручную, тратит кучу времени. Теперь ИИ подстраивает тест автоматически, без участия инженера.

    По данным исследований, 68% компаний уже активно работают с ИИ-платформами для ускорения тестирования, а использование ИИ-ассистентов сокращает время тестирования до 50% при сохранении качества.

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

    Вот системный промпт для ИИ-ассистента (типа GitHub Copilot), который может помочь писать автотесты для мобильного приложения:

    Ты - эксперт по мобильной автоматизации тестирования. 
    Твоя задача:
    1. Анализировать UI-структуру приложения и предлагать оптимальные XPath или Accessibility ID локаторы
    2. Писать стабильные тесты, которые не падают при изменении интерфейса
    3. Использовать явные ожидания (explicit waits) вместо sleep()
    4. Предлагать стратегию параллельного запуска тестов
    5. Генерировать читаемые баг-репорты с скриншотами и логами
    
    Когда ты видишь нестабильный тест, предложи решение через retry-логику и self-healing подход.
    Если нужно работать с WebView внутри нативного контейнера - это усложняет ситуацию; в этом случае объясни подводные камни.
    
    Пишешь только на JavaScript или Python, в зависимости от стека.
    

    Использование Cursor и GitHub Copilot на таких промптах сокращает время на рутинные задачи на 55%. Это не 5%, это серьезно влияет на скорость разработки.

    Как совместить все это в реальном проекте

    Пирамида автоматизации остается актуальной, но теперь она быстрее выполняется и лучше понимается:

    1. Юнит-тесты (основание) - проверяют отдельные функции, запускаются за миллисекунды
    2. Интеграционные тесты - проверяют API, базу данных, сервисы вместе
    3. E2E тесты (вершина) - реальные сценарии пользователя на реальных девайсах

    Все это встроено в CI/CD пайплайн. Критические тесты выполняются в первую очередь, параллельное выполнение сокращает общее время прогона.

    Реальный кейс: мобильное приложение для лидов. Ты разработчик, и твоя задача:

    • Написать функцию авторизации на React Native / Flutter
    • Написать юнит-тесты (Jest / Pytest)
    • Написать E2E тесты через Appium 2.0
    • Собрать Docker-образ с тестами
    • Интегрировать в GitLab CI с параллельным запуском на 5 девайсах
    • Прокинуть отчеты в Allure TestOps
    • Настроить self-healing для хрупких UI-локаторов

    Все это должен делать один человек. Раньше это казалось невозможным. Теперь это стандарт.

    Честная оценка и реальность РФ

    Теория хорошая, но как это работает в российских стартапах и компаниях? Правда в том, что в топ-100 компаниях (МТС, Яндекс, VK) это уже норма. В стартапах и середняках - сильно отстают. Много мест, где все еще мучаются с костылями, недоделанными автотестами и ручным QA.

    Но рынок меняется быстро. Если ты сейчас подучишь DevOps, Docker и базовый ИИ-workflow - через полгода это будет в цене. Компании ищут именно таких универсалов, потому что узких специалистов просто нечем заменить на нужные деньги.

    Вопрос к сообществу: Как вы в своих проектах организуете автоматизацию тестов? Вы уже используете ИИ-ассистентов для написания тестов или еще на старых методах? И главное - насколько реально все это внедрить в российских условиях?


    0 0 0 Ответить
  • kirilljsxK
    kirilljsx
    Covariant RFM-1 и Ambi PRIME-1: как ИИ автоматизирует склады в 2026

    Обложка: Как мультимодальные ИИ-модели Covariant RFM-1 и Ambi PRIME-1 автоматизируют складскую робототехнику в 2026

    Представьте склад, где роботы сами разбирают хаос из посылок любого размера и формы, без вечных простоев и ошибок. Рутина сортировки и упаковки жрет до 40% времени персонала на больших логистических хабах, а дефицит рабочих только усугубляет. Мультимодальные модели вроде Covariant RFM-1 и Ambi PRIME-1 меняют это: они дают роботам человеческий уровень понимания мира - зрение, язык, физику и действия в одном флаконе. Теперь роботы не тупо следуют скриптам, а реально думают и адаптируются на лету.

    Что такое RFM-1 и PRIME-1: мозги для железа

    RFM-1 от Covariant - это Robotics Foundation Model, обученная на огромном датасете реальных складских операций плюс интернет-текстах вроде тех, что юзают в ChatGPT. Модель предсказывает физику через генерацию видео: робот симулирует, как предмет отреагирует на хват, и выбирает лучший вариант. Результат? Скорость и надежность на уровне человека, но без кофе-брейков и усталости. Amazon уже лицензировала это и позвала основателей в свою робототехническую команду.

    PRIME-1 от Ambi Robotics бьет по объемам: 20 млн изображений и 200 тыс. часов видео операций. Она питает систему AmbiStack для упаковки - роботы сортируют и пакуют посылки на скоростных линиях, как у Pitney Bowes. Ключ - мультимодальность: модель жует видео с камер в реальном времени, понимает команды на естественном языке и действует без задержек.

    Модель Датасет Ключевой фича Применение
    RFM-1 Складские данные + интернет-текст Physics world model via видео Pick-and-place, симуляция действий
    PRIME-1 20M изображений + 200K часов видео Реал-тайм сортировка Упаковка посылок, AmbiStack

    Это не фантазия: роботы уже работают коммерчески, повышая пропускную способность складов в разы.

    Как это работает на практике

    Роботы с этими моделями - это Vision-Language-Action (VLA) системы. Камера ловит поток видео, модель анализирует сцену, язык дает инструкции (типа “упакуй хрупкое в пузырь”), а физическая модель просчитывает хват без краш-тестов в реале. Обучение на отражениях ускоряет адаптацию: робот сам анализирует ошибки и улучшается за минуты, а не месяцы.

    Для разработчиков профит огромный. Интегрируйте через API: фронт на JS шлет видео, бэкенд на Python обрабатывает модель и отдает команды актуаторам. Вот пример Python-кода для симуляции запроса к RFM-1-like API (адаптировано под рест-API мультимодальных моделей):

    import requests
    import base64
    
    def process_warehouse_frame(video_frame, instruction):
        # Кодируем видео в base64 для мультимодального API
        with open(video_frame, 'rb') as f:
            video_b64 = base64.b64encode(f.read()).decode('utf-8')
        
        payload = {
            'video': video_b64,
            'instruction': instruction,  # 'Сортируй хрупкие посылки первыми'
            'model': 'rfm-1'
        }
        
        response = requests.post('https://api.covariant.ai/predict', json=payload)
        return response.json()['action_plan']  # Возвращает план хватов
    
    # Пример использования
    plan = process_warehouse_frame('frame.mp4', 'Упакуй коробки по размеру')
    print(plan)
    

    Этот скрипт - основа для бэкенда: масштабируйте на флот роботов, добавьте очередь в Redis. JS-версия для фронта/мобилки аналогична с WebRTC для стрима видео.

    Бизнес-эффект: профит для складов

    Сортировка 1000+ посылок в час - реальность с PRIME-1. RFM-1 снижает простои на 50%, роботы хватают never-seen-before предметы. Для логистики это миллионы на оптимизации: меньше персонала, быстрее доставка, меньше брака. Переход на такие системы окупается за год при объемах типа Wildberries или Ozon.

    В реалиях РФ? Подходит идеально для мега-складов под Москвой или Питером, где логистика - bottleneck. Импорт железа под санкциями - хреново, но софт от Covariant/Ambi через API можно тянуть, а роботов собирать локально на базе open-source hardware. Тестируйте на пилоте: профит outweighs риски.

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

    Эти модели - не хайп, а инструмент, который уже приносит бабки большим игрокам. Инвестируйте в интеграцию сейчас, пока конкуренты спят. А вы как решаете боль с сортировкой - своими парсерами, дешевыми конвейерами или уже тестите ИИ-роботов? Делитесь в коммах, обсудим стеки и кейсы!


    0 0 0 Ответить
  • barsikB
    barsik
    Node.js в реальных проектах: кейсы API и чатов, проблемы с памятью и решения

    Node.js прочно закрепил позицию в backend-разработке, став платформой выбора для высоконагруженных систем. Его успех основан на неблокирующей событийно-ориентированной модели ввода-вывода, встроенной в JavaScript еще с браузерных времен. Однако переход на Node.js требует глубокого понимания специфики платформы, особенно когда речь идет о проблемах с памятью и масштабированием.

    Почему компании выбирают Node.js

    Если посмотреть на кейсы крупных компаний, причины выбора очевидны. LinkedIn полностью переписал серверную часть мобильного приложения на Node.js и смог уменьшить количество используемых серверов, одновременно повысив производительность в несколько раз по сравнению с Ruby on Rails. PayPal активно использует Node.js для построения API и интерфейсов, а eBay обрабатывает миллионы транзакций благодаря эффективности платформы. Uber обеспечивает доступ к приложению в любое время суток, полагаясь на масштабируемость Node.js.

    Особенно заметна эффективность Node.js в сценариях с частым обменом данными. Движок V8 постоянно совершенствуется, позволяя платформе показывать производительность, сопоставимую с приложениями на компилируемых языках.

    Реальный случай: оптимизация кэширования

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

    Решение было элегантным: вместо хранения буферов в кэше разработчики стали держать указатели на позиции в файле (start/end-позиции). Когда клиент запрашивал данные, система использовала fs.createReadStream(...).pipe(...). Результат впечатляет: потребление памяти Node.js упало ниже 200 МБ под максимальной нагрузкой — более чем в 10 раз лучше, чем было раньше.

    Ключевой урок: не все данные нужно держать в памяти. Часто достаточно потокового доступа к данным, что экономит ресурсы и повышает пропускную способность.

    Чаты и real-time коммуникация

    Node.js стал стандартом для чатов и real-time приложений именно благодаря своей архитектуре. В социальных сетях и на официальных страницах компаний сообщения появляются мгновенно, без задержек. Неблокирующая модель позволяет обрабатывать тысячи одновременных соединений на одном сервере.

    Однако здесь скрывается опасность: накопление состояния в памяти. Node.js приложения часто хранят сессии пользователей, истории сообщений и другие данные в оперативной памяти, что требует тщательного управления.

    Проблема: Heap Out of Memory

    Самая распространенная ошибка, с которой встречаются разработчики — JavaScript Heap Out of Memory. Движок V8 исчерпывает лимит памяти, выделенный под объекты, строки и замыкания, и приложение падает мгновенно.

    Причины могут быть разными:

    • Утечки памяти в коде
    • Недостаточно выделенной памяти на хосте
    • Неэффективная работа с большими объемами данных
    • Проблемы в gRPC-вызовах между микросервисами

    Решение №1: Увеличение лимита памяти

    Первый и самый быстрый способ — использовать флаг --max-old-space-size. Он говорит движку V8 расширить его «old space» (самую большую часть кучи) до конкретного числа мегабайт:

    node --max-old-space-size=4096 app.js
    

    Для системы с 4 ГБ RAM выделяем 4096 МБ, с 8 ГБ — 8192 МБ.

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

    Чтобы сделать фикс постоянным для проекта, добавьте флаг в package.json:

    {
      "scripts": {
        "start": "node --max-old-space-size=4096 server.js",
        "build": "NODE_OPTIONS='--max-old-space-size=4096' next build"
      }
    }
    

    Теперь команда npm start явно запустит Node.js с 4 ГБ памяти под кучу.

    Решение №2: Поиск и устранение утечек памяти

    Если просто увеличение лимита не помогает, значит, в коде есть утечки. На одном из реальных проектов разработчики столкнулись с ситуацией, когда heap snapshot весил всего 20-30 МБ, а процесс отъедал гигабайт и падал. Проблема решилась обновлением версии Node.js.

    Для диагностики используют несколько инструментов:

    • Heap snapshots — снимки состояния памяти в конкретный момент
    • Diff snapshots — сравнение снимков для выявления утечек
    • GC трассировщики — анализ работы garbage collector
    • Flame graphs — визуализация использования памяти по времени
    • Системы мониторинга (New Relic, altri сервисы)

    Реальный пример: микросервисы и gRPC

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

    Для диагностики использовали скрипт нагрузочного тестирования:

    #!/bin/bash
    server_address="localhost"
    server_port="5001"
    service="client.ClientService"
    method="MakeRequest"
    proto_path="/Users/artem/Work/grpc/grpc-client/src/client"
    proto_file="client.proto"
    count=100
    
    for ((i = 0; i < $count; i++))
    do
      grpcurl -import-path $proto_path -proto $proto_file \
        -d '{"id": 1}' -plaintext $server_address:$server_port \
        $service/$method
      sleep 1
    done
    

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

    Масштабирование: кластеры и worker threads

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

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

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

    Практические рекомендации

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

    2. Используйте потоки. Для работы с большими файлами применяйте fs.createReadStream вместо загрузки всего файла в память.

    3. Мониторьте память в production. Настройте систему мониторинга еще на этапе разработки.

    4. Оптимизируйте структуры данных. Избегайте ненужных копий массивов и объектов.

    5. Регулярно обновляйте Node.js. Новые версии содержат оптимизации и исправления утечек памяти.

    6. Проводите нагрузочное тестирование. Выявляйте проблемы до production, а не после.

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


    0 0 0 Ответить
  • barsikB
    barsik
    Node.js в реальных проектах: кейсы API и чатов, типичные проблемы с памятью и решения

    Node.js давно вышел за рамки экспериментальной платформы и стал основой для реальных высоконагруженных проектов, особенно в fintech, чатах и API-сервисах. Его событийно-ориентированная модель идеально подходит для обработки множества одновременных запросов, но с ростом нагрузки часто возникают проблемы с памятью — утечки, переполнение кучи V8 и OOM-ошибки. В этой статье разберем реальные кейсы из практики, типичные ловушки и проверенные решения, чтобы вы могли избежать падений в продакшене. Поделитесь в комментариях своими историями: сталкивались ли вы с подобным в своих проектах?

    Кейс 1: API для fintech — обработка транзакций на миллионы запросов

    В fintech-проектах Node.js часто используется для backend API, где важны скорость и масштабируемость. Представьте сервис вроде eBay или Uber: миллионы транзакций в секунду, интеграция с базами данных и внешними gRPC-сервисами. Один из реальных примеров — микросервис для обработки платежей, где под нагрузкой 500+ клиентов приложение “съедало” гигабайты RAM и падало с ошибкой JavaScript heap out of memory.

    Проблема: Стандартный лимит памяти V8 (около 1.4 ГБ на 64-битной системе) исчерпывался из-за накопления буферов данных в кэше. Каждый запрос к БД или gRPC возвращал большие массивы, которые не освобождались timely из-за замыканий в обработчиках.

    Решение в коде: Вместо хранения полных буферов в памяти, перешли на потоковую обработку с fs.createReadStream().pipe(). Это позволило держать в RAM только указатели на позиции в файле, снижая потребление до 200 МБ под пиковой нагрузкой.

    // Плохо: кэшируем весь файл
    const cache = new Map();
    app.get('/data/:id', async (req, res) => {
      const data = await fs.readFile(filePath); // 100 МБ в памяти!
      cache.set(req.params.id, data);
      res.send(data);
    });
    
    // Хорошо: потоковая отдача без кэша в RAM
    app.get('/data/:id', (req, res) => {
      const stream = fs.createReadStream(filePath, { start: offset, end: length });
      stream.pipe(res); // Память не растет!
    });
    

    Практический совет: Для API в fintech используйте кластеры Node.js (cluster модуль) или PM2 для распределения нагрузки. В package.json добавьте:

    {
      "scripts": {
        "start": "pm2 start server.js -i max --node-args='--max-old-space-size=4096'"
      }
    }
    

    Это повысит лимит до 4 ГБ на процесс и автоматически перезапустит упавшие инстансы. В результате latency упал на 50%, а uptime вырос до 99.99%.

    Кейс 2: Чат-сервис — реал-тайм общение с тысячами пользователей

    Чаты — классика для Node.js благодаря Socket.io или ws. В проекте вроде LinkedIn или корпоративного чата сообщения должны доставляться мгновенно, без задержек. Но под 10k+ соединениями память “утекает” из-за неочищенных интервалов, таймеров и глобальных объектов.

    Реальный кейс: Сервис обратной связи для компании, где чат обрабатывал 500 злых клиентов с запросами без пауз. Память росла линейно из-за хранения состояний пользователей в Map и неудаленных event listeners.

    Типичная проблема: GC (Garbage Collector) не справляется с “long-lived” объектами — сокетами, которые висят в памяти после disconnect.

    Решение:

    1. Очистка ресурсов в Socket.io:
    const io = require('socket.io')(server);
    
    io.on('connection', (socket) => {
      let userTimer; // Таймер для heartbeat
    
      socket.on('join', (userId) => {
        userTimer = setInterval(() => socket.emit('heartbeat'), 30000);
      });
    
      socket.on('disconnect', () => {
        clearInterval(userTimer); // Обязательно чистим!
        socket.removeAllListeners(); // Удаляем все listeners
      });
    });
    
    1. Мониторинг с heap snapshots. В проде используйте --inspect и Chrome DevTools: сделайте snapshot до/после нагрузки, сравните diff. В кейсе с микросервисами утечка нашлась в gRPC-клиенте — не закрытые соединения.

    Скрипт для нагрузочного теста (bash из реального кейса):

    #!/bin/bash
    server_address="localhost"
    server_port="5001"
    count=1000
    for ((i = 0; i < $count; i++)); do
      grpcurl -d '{"id": 1}' -plaintext $server_address:$server_port service/method
      sleep 0.1
    done
    

    Рекомендация: Интегрируйте New Relic или clinic.js для flame graphs и трассировки GC. В чатах держите состояния в Redis, а не в RAM: socket.userId = await redis.get(userId). Это масштабирует до миллионов пользователей, как в Uber.

    Типичные проблемы с памятью в Node.js и как их решать

    1. OOM (Out of Memory) на компиляции/минификации.
    При npm build с Webpack или Next.js V8 “задыхается”.
    Фикс: NODE_OPTIONS='--max-old-space-size=8192' npm run build в package.json. Для 8 ГБ RAM — норма.

    2. Утечки от замыканий и глобалов.
    Пример: Массив на миллион элементов мутируется, но ссылка висит.

    // Ложноэкономит память, но утекает
    const arr = new Array(1e6).fill('data');
    arr.forEach((item, i) => arr[i] = processData(item)); // Новый массив!
    
    // Правильно
    arr.forEach((item, i) => { arr[i] = processData(item); });
    

    3. Масштабирование: кластеры и worker_threads.
    Один поток — узкое место. Используйте cluster:

    const cluster = require('cluster');
    if (cluster.isMaster) {
      for (let i = 0; i < require('os').cpus().length; i++) {
        cluster.fork();
      }
    } else {
      // Ваш сервер
      http.createServer(app).listen(3000);
    }
    

    Для CPU-задач — worker_threads.

    4. Диагностика в проде.

    • --heap-prof для профилей.
    • 0x для снепшотов: node --heapsnapshot-signal=SIGUSR2 app.js, затем анализ в Chrome.
    • Инструменты: clinic doctor, 0x, flamebearer.

    Таблица сравнения решений по памяти:

    Проблема Решение Эффект на RAM Пример использования
    OOM на старте --max-old-space-size +4-8 ГБ лимит Build-скрипты
    Утечка в кэше Stream + указатели -80% под нагрузкой API/Файлы
    Socket утечки clearInterval/removeAll Стабильные 200 МБ Чаты
    Масштаб Cluster/PM2 x CPUs инстансов Fintech

    Лучшие практики для реальных проектов

    • Обновляйте Node.js: С 20+ версии инструменты диагностики работают лучше, утечки фиксятся automatically.
    • Мониторинг: Prometheus + Grafana для метрик RSS/HeapUsed.
    • Тестирование: Artillery или autocannon для симуляции нагрузки.
    • Fintech-специфика: Используйте TypeScript + Zod для валидации, чтобы избежать null-утечек в API.

    В наших проектах переход на эти практики сократил инциденты на 90%. А как у вас? Делитесь кодами утечек или инструментами — обсудим в комментариях! Какие фреймворки (Express, Nest.js, Fastify) спасли ваши чаты от краха?


    0 0 0 Ответить
  • hannadevH
    hannadev
    REST API: как им пользоваться, для чего нужен и как его разработать на JavaScript

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

    REST API (Representational State Transfer Application Programming Interface) — это архитектурный стиль, который определяет стандарты взаимодействия между клиентом и сервером. В финансовой отрасли, где каждая миллисекунда имеет значение, REST API обеспечивает быстрый и предсказуемый обмен данными между приложениями.

    Что такое REST API?

    REST — это архитектурный стиль, а не протокол или стандарт. Он использует HTTP-методы для выполнения операций с ресурсами. В контексте финансовых приложений это означает, что вы можете безопасно запрашивать балансы, создавать транзакции, получать отчеты и управлять аккаунтами через простые HTTP-запросы.

    Основные характеристики REST API:

    • Клиент-серверная архитектура: Разделение интерфейса и обработки данных
    • Отсутствие состояния (stateless): Каждый запрос содержит всю необходимую информацию
    • Кэширование: Улучшение производительности за счет хранения временных данных
    • Единообразие интерфейса: Стандартные методы для операций с ресурсами

    HTTP-методы и их назначение

    В REST API каждый метод выполняет определенную операцию:

    GET — получение данных. Например, запрос баланса пользователя или истории транзакций. В финансовой сфере это наиболее часто используемый метод, так как он не изменяет данные на сервере.

    POST — создание новых ресурсов. Идеально подходит для создания новых счетов, отправки транзакций или регистрации пользователей.

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

    PATCH — частичное обновление. Позволяет изменить только определенные поля, что экономит трафик и увеличивает производительность.

    DELETE — удаление ресурса. Применяется для закрытия счетов или удаления временных данных.

    Как разработать REST API на JavaScript

    Node.js стал идеальной платформой для разработки REST API благодаря своей асинхронной природе и огромной экосистеме пакетов. Вот основные шаги создания REST API:

    Шаг 1: Инициализация проекта

    Создайте новый проект и установите необходимые зависимости:

    mkdir exlends-api
    npm init -y
    npm install express
    

    Шаг 2: Создание базового сервера

    const express = require('express');
    const app = express();
    const port = 3000;
    
    // Middleware для парсинга JSON
    app.use(express.json());
    
    // Пример GET эндпоинта
    app.get('/api/balance', (req, res) => {
      res.json({ balance: 150000, currency: 'RUB' });
    });
    
    app.listen(port, () => {
      console.log(`ExLends API работает на порту ${port}`);
    });
    

    Шаг 3: Проектирование ресурсов

    В финансовой сфере типичные ресурсы включают:

    • /api/accounts — управление счетами
    • /api/transactions — транзакции и платежи
    • /api/users — данные клиентов
    • /api/reports — отчеты и аналитика

    Шаг 4: Реализация CRUD операций

    // Мок-база данных
    let transactions = [];
    
    // GET - получить все транзакции
    app.get('/api/transactions', (req, res) => {
      res.json(transactions);
    });
    
    // POST - создать транзакцию
    app.post('/api/transactions', (req, res) => {
      const newTransaction = {
        id: transactions.length + 1,
        amount: req.body.amount,
        from: req.body.from,
        to: req.body.to,
        date: new Date()
      };
      transactions.push(newTransaction);
      res.status(201).json(newTransaction);
    });
    
    // PUT - обновить транзакцию
    app.put('/api/transactions/:id', (req, res) => {
      const index = transactions.findIndex(t => t.id == req.params.id);
      if (index !== -1) {
        transactions[index] = { ...transactions[index], ...req.body };
        res.json(transactions[index]);
      } else {
        res.status(404).json({ error: 'Транзакция не найдена' });
      }
    });
    
    // DELETE - удалить транзакцию
    app.delete('/api/transactions/:id', (req, res) => {
      const index = transactions.findIndex(t => t.id == req.params.id);
      if (index !== -1) {
        transactions.splice(index, 1);
        res.json({ message: 'Транзакция удалена' });
      } else {
        res.status(404).json({ error: 'Транзакция не найдена' });
      }
    });
    

    Шаг 5: Обработка ошибок и кодирование

    Важно правильно обрабатывать ошибки и возвращать соответствующие HTTP-коды:

    • 200 OK — успешная операция
    • 201 Created — ресурс создан
    • 400 Bad Request — некорректный запрос
    • 401 Unauthorized — требуется авторизация
    • 403 Forbidden — недостаточно прав
    • 404 Not Found — ресурс не найден
    • 500 Internal Server Error — ошибка сервера

    Best Practices для финансовых приложений

    Безопасность

    Используйте HTTPS для шифрования данных в transit. Для аутентификации применяйте JWT (JSON Web Tokens) или OAuth 2.0. Всегда валидируйте входные данные и sanitize их перед обработкой.

    Валидация данных

    const validateTransaction = (req, res, next) => {
      const { amount, from, to } = req.body;
      
      if (!amount || amount <= 0) {
        return res.status(400).json({ error: 'Некорректная сумма' });
      }
      
      if (!from || !to) {
        return res.status(400).json({ error: 'Указаны не все обязательные поля' });
      }
      
      next();
    };
    

    Лимитирование запросов (Rate Limiting)

    npm install express-rate-limit
    
    const rateLimit = require('express-rate-limit');
    
    const limiter = rateLimit({
      windowMs: 15 * 60 * 1000, // 15 минут
      max: 100 // максимум 100 запросов
    });
    
    app.use('/api/', limiter);
    

    Документирование API

    Используйте инструменты вроде Swagger/OpenAPI для автоматической генерации документации. Это упрощает интеграцию для внешних партнеров и ускорят разработку.

    Практический пример: API для переводов

    const express = require('express');
    const app = express();
    app.use(express.json());
    
    // Хранилище счетов
    const accounts = new Map();
    accounts.set('user1', { id: 'user1', balance: 10000 });
    accounts.set('user2', { id: 'user2', balance: 5000 });
    
    // Перевод средств
    app.post('/api/transfer', async (req, res) => {
      const { from, to, amount } = req.body;
      
      // Проверка существования счетов
      if (!accounts.has(from) || !accounts.has(to)) {
        return res.status(404).json({ error: 'Счет не найден' });
      }
      
      // Проверка достаточности средств
      const fromAccount = accounts.get(from);
      if (fromAccount.balance < amount) {
        return res.status(400).json({ error: 'Недостаточно средств' });
      }
      
      // Выполнение перевода
      fromAccount.balance -= amount;
      const toAccount = accounts.get(to);
      toAccount.balance += amount;
      
      // Логирование транзакции
      console.log(`Перевод: ${amount} RUB от ${from} к ${to}`);
      
      res.json({
        success: true,
        message: 'Перевод выполнен успешно',
        fromBalance: fromAccount.balance,
        toBalance: toAccount.balance
      });
    });
    
    app.listen(3000, () => console.log('API для переводов работает'));
    

    Заключение

    REST API — это фундаментальный инструмент современной разработки, особенно в финансовой сфере. Правильно спроектированный REST API обеспечивает:

    • Масштабируемость приложений
    • Простоту интеграции с другими системами
    • Надежность и безопасность данных
    • Высокую производительность

    Для команды ExLends mastering REST API означает возможность создавать инновационные финансовые продукты, которые работают быстро, безопасно и предсказуемо. Начните с простых проектов, постепенно усложняя их, и всегда следуйте best practices для создания профессиональных решений.

    В мире, где технологии определяют будущее финансов, понимание REST API становится конкурентным преимуществом, которое позволяет создавать решения, меняющие индустрию.


    1 0 0 Ответить
  • barsikB
    barsik
    TypeScript 5.6: новые возможности и практическое применение

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

    В этой статье мы рассмотрим ключевые нововведения TypeScript 5.6 и разберём, как они могут улучшить ваш опыт разработки.

    Основные нововведения

    1. Запрещенные проверки на Nullish и Truthy

    Одна из самых полезных новых возможностей — обнаружение подозрительных проверок, которые всегда возвращают true или false. TypeScript 5.6 теперь выдаёт ошибки для таких случаев:

    // Пример 1: Регулярное выражение без вызова .test()
    if (/0x[0-9a-f]/) {
      // Ошибка: Такое выражение всегда правдиво
    }
    
    // Пример 2: Случайная стрелочная функция вместо оператора сравнения
    if (x => 0) {
      // Ошибка: Такое выражение всегда истинно
    }
    
    // Пример 3: Проблема с приоритетом операторов
    function isValid(value: string | number, options: any, strictness: "strict" | "loose") {
      if (strictness === "loose") {
        value = +value
      }
      return value < options.max ?? 100;
      // Ошибка: Правый операнд ?? недостижим
    }
    

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

    2. Улучшенная поддержка контекстных типов для стрелочных функций

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

    3. Оптимизации производительности

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

    Практические примеры

    Пример использования новых проверок

    Рассмотрим реальный сценарий, где новые проверки могут предотвратить ошибку:

    // До TypeScript 5.6: потенциальная ошибка
    function processUserInput(input: string) {
      if (input.trim()) {
        // Всегда выполняется, даже если input пустая строка после trim()
        console.log("Processing input...");
      }
    }
    
    // После TypeScript 5.6: получаем предупреждение
    function processUserInputSafe(input: string) {
      const trimmed = input.trim();
      if (trimmed) {
        // Корректная проверка
        console.log("Processing input...");
      }
    }
    

    Вопросы для обсуждения

    1. Какие из новых возможностей TypeScript 5.6 вы считаете наиболее полезными в своей повседневной работе?

    2. Сталкивались ли вы с ошибками, которые теперь обнаруживаются новыми проверками на nullish/truthy значения? Поделитесь примерами из своего опыта.

    3. Как вы оцениваете темп развития TypeScript? Достаточно ли быстро язык реагирует на потребности разработчиков?

    4. Какие улучшения вы хотели бы видеть в следующих версиях TypeScript?

    5. Как вы организуете процесс обновления TypeScript в своих проектах? Есть ли какие-то best practices для плавного перехода на новые версии?

    Заключение

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

    Рекомендуем обновить TypeScript в своих проектах, чтобы воспользоваться этими улучшениями. Как всегда, перед обновлением стоит проверить, нет ли breaking changes для вашего конкретного кейса.

    Источники:

    • Официальный анонс TypeScript 5.6 - оригинальная статья от Microsoft

    0 0 0 Ответить
  • kirilljsxK
    kirilljsx
    Генерируем SSH ключи и подключаем GitHub

    Надеюсь не надо никому рассказывать что такое ssh-ключи да? А если надо то напиши об этом коротко:

    Ключ ssh - необходим что бы компьютеры подключались и обменивались данными через сетевые протоколы.

    Сперва проверим есть ли на нашем ПК вообще ключи:

    # Перейдем в домашнюю директорию
    cd ~
    

    Теперь для того что бы посмотреть если у нас ключи или нет, надо найти скрытую папку .ssh/, а делается это очень просто вот так:

    ls -la .ssh/
    

    Опа, у меня есть у Вас?
    4f365269-31ae-4db4-86f4-9e9df180a303-image.jpeg

    А Вас всего скорее нету, по этому идем дальше.

    Генерация ssh-ключа

    Для генерации публичного ключам нам который в последствии мы будем подключать к GitHub или с чем Вы там будите работать необходимо ввести следующую команду:

    ssh-keygen -t ed25519 - C "test@yandex.ru"
    

    Смотрите внимательно - тут я вставил тестовую почту, Вы должны вставить свою которая привязана к GitHub!

    Если вдруг появилось сообщение об ошибке или еще какая либо ерунда - всего скорее ваша система не поддерживает алгоритм шифрования ed25519, но не расстраиваемся есть запасной вариант:

    ssh-keygen -t rsa -b 4096 -C "tes@yandex."
    

    Теперь либо при первом либо при втором варианте Вы должны увидеть следующее сообщение:

        > Generating public/private rsa key pair.
    

    Отлично, теперь просто нажимаем Enter, всего скорее у Вас будет сообщение:

    Enter a file in which to save the key
    

    Он будет просить ввести имя файла где будет сохранен ключ, не надо ничего придумывать нажимаем Enter

    Все теперь в директории .ssh/ появятся ключи, но на этом не все!

    Внимание, теперь всего скорее генератор попросит ввести пароль/фразу - ЭТОТ ПАРОЛЬ НУЖНО ВВОДИТЬ КАЖДЫЙ РАЗ ПРИ СОЕДИНЕНИЯ ЧЕРЕЗ ПРОТОКОЛ. Поэтому запишите его!

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

    Мы все сгенерировали, но нам надо еще запустить агента который будет искать эти ключи на нашем ПК.

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

    Делаем следующим образом:

    eval ${ssh-agent -s}
    

    Теперь необходимо привязать этот ключ к нашему агенту, делаем так:

    # для шифрования ed25519:
    ssh-add ~/.ssh/id_ed25519
    
    # для шифрования rsa:
    ssh-add ~/.ssh/id_rsa
    

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

    Привязка SSH-ключей к GitHub

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

    Если у тебя mac:

    # для шифрования ed25519:
    pbcopy < ~/.ssh/id_ed25519.pub
    # для шифрования rsa:
    pbcopy < ~/.ssh/id_rsa.pub
    

    Если у тебя windows:

    # для шифрования ed25519:
    clip < ~/.ssh/id_ed25519.pub
    # для шифрования rsa:
    clip < ~/.ssh/id_rsa.pub
    

    Если по каким-то причинам ключ не скопировался в буфер обмена, то идем в нашу скрытую папку .ssh/ и открываем файл:

    • id_ed25519.pub
    • id_rsa.pub

    В зависимости от шифрования - не путайте!

    Если не знаете как посмотреть файл - пишем вот так:
    cat ~/.ssh/id_ed25519.pub В путях то вы понимаете надеюсь?

    Едем дальше, теперь после того как скопировали ключ - идем в GitHub

    Тыкаем на свой профиль и в выпадающем меню нажимаем Setting
    5a3fe0a9-9418-48d2-8af3-af8784167656-image.jpeg

    После этого слева ищем SSH adn GPG keys, нажимам и переходим дальше:

    1ec2980b-dbed-41c6-b893-a2189745893f-image.jpeg

    Теперь у Вас должно открыться окно с ключами (у меня их много) а у вас всего скорее будет пусто, ищем кнопку и нажимаем New SSH key

    698f6493-af89-4f3c-a62b-4b990e9634c1-image.jpeg

    В новой страничке GitHub запросит у нас название ключа - его можете обозвать как хотите, а вот ниже где написано key туда мы уже вставляем наш ключ который мы скопировали из терминала и нажимаем кнопку Add SSH key

    5666e355-c270-46d9-b138-3442e5bb6e30-image.jpeg

    Ура! Теперь наш GitHub знает о нашем локальном ПК и можно пользоваться такими замечательными командами как git pull, git push и так далее!

    На этом на сегодня все, успехов Вам джунщики и вкатуны в ИТ 😁

    Ну и подпишитесь если не жалко:

    Link Preview Image
    Кирилл Дворянинов

    Обо всем и не о чем сразу! IT форум - forum.exlends.com

    favicon

    MAX (max.ru)


    0 0 0 Ответить
  • kirilljsxK
    kirilljsx
    Как настроить React с Vite?

    a388cfec-98b3-4bbe-b4d9-385e9a5290d0-image.jpeg

    Если кто не знаком с Vite или только вкатывается в веб-разработку начиная свои первые шаги с React, то эта статья определенно для Вас!

    Vite - это быстрый и современный инструмент сборки для создания веб-приложений. Он ускоряет процесс разработки, обеспечивая более быстрое время сборки и лучшую производительность. Ранее для работы с React самим вручную необходимо было прикручивать webpack, babel и другие штуки для работы, но с приходом Vite он делает все сам, а мы лишь занимаемся разработкой не отвлекаясь на не нужные нам настройки.

    Ниже перечислены некоторые преимущества использования React с Vite:

    • Быстрые обновления без перезагрузки страниц.
    • Более быстрые и компактные сборки для продакшена.
    • Автоматическая обработка JSX.
    • Более быстрая сборка.

    Ну и конечно же стандартные настройки что бы начать программировать сразу!

    Пошаговая инструкция по настройке React с Vite

    Шаг 1- Установка node
    Для работы с Vite и конечно же с React требуется node js и npm, если Вы их еще не установили сделайте это, вот ссылки:

    • https://nodejs.org/en/download
    • https://docs.npmjs.com/downloading-and-installing-node-js-and-npm

    Шаг 2 - Создаем новый проект с Vite

    Vite предоставляет простой способ создания новых проектов. Для создания нового проекта React с помощью Vite можно использовать следующую команду:

    npm create vite@latest my-react-app
    

    a904f81a-6621-4629-93a3-2f59694b8869-image.jpeg

    Шаг 3: Выберите фреймворк

    После того как мы начали установку нашего реакт приложение необходим выбрать сам реакт:
    894d9615-6912-403a-9307-d35ebaa9c15c-image.jpeg

    Далее установщик предложит как мы хотим использовать react с использование TypeScript, React Compiler. Так как эта статья для джунщиков и вкатунов, выбираем 3 вариант просто JavaScript:

    f5fa696e-7fdf-4ace-b4a9-e263ac1e18de-image.jpeg

    После выбора инструментария установщик спроси установить через npm пакеты и запустить? Нажимаем - yes
    cdcdd36e-fbf9-4f34-a073-cd85b1265c1a-image.jpeg

    Дожидаемся и видим что наше приложение готово и запустилось:

    41030b5c-e36a-4956-9b99-97a4d9eebb0c-image.jpeg

    Попробуй перейти по ссылке из терминала: http://localhost:5173/ и если все прошло удачно, то попадете на стартовую страницу react + vite приложения:

    73a06842-7c94-4b68-82b3-75fa8fcb9683-image.jpeg

    УРА! Теперь все готово для работы, после нажимаем ctrl+c что бы отключиться в терминале:
    d8922379-3b98-46ef-a1dd-a0235f398d40-image.jpeg

    После можно спокойно переходить в папку с проектом:

    cd my-react-app
    

    И запускать редактор кода (vs code или что там у вас):

    code .
    

    Если вы уже делали все манипуляции через редактор кода и встроенный терминал то думаю не надо объяснять что куда 😊

    Ну все теперь теперь можете работать с React и не париться насчет настройки и билдинга проекта - успехов Вам!

    И да, если что подписывайте на меня в МАХ:

    Link Preview Image
    Кирилл Дворянинов

    Обо всем и не о чем сразу! IT форум - forum.exlends.com

    favicon

    MAX (max.ru)


    0 0 0 Ответить
  • kirilljsxK
    kirilljsx
    Как маркировать рекламную статью: ERID, ОРД, ЕРИР — пошаговая инструкция

    И так в этой статье разбираем, когда статья считается рекламой, как получить ERID, где разместить идентификатор в тексте, что передать в ОРД и когда сдавать отчётность в ЕРИР.

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

    Если статья действительно рекламная, для нее действует та же логика, что и для другой интернет-рекламы: нужно зарегистрировать креатив через ОРД, получить erid, корректно разместить идентификатор в материале и затем передать отчетность по размещению.

    Что считается рекламной статьей

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

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

    Шаг 1. Выберите ОРД

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

    • ВК Рекламные технологии
    • Лаборатория разработки
    • МедиаСкаут
    • ОЗОН ОРД
    • ОРД-А
    • Первый ОРД
    • Яндекс ОРД

    Шаг 2. Внесите данные о рекламе

    После активации кабинета в ОРД нужно заполнить сведения о контрагентах, участвующих в размещении, о договоре и о рекламном креативе, а также загрузить образец рекламы. РКН отдельно указывает, что это можно сделать вручную в кабинете ОРД или автоматически по API.

    К примеру, на нашем ресурсе заказали рекламную статью. запросили у заказчика всего его данные - Наименование компании, ИНН и другие.
    Это как раз необходимо есть мы выступаем в роли исполнителя на таких площадках как: gogetlinks.net, miralinks.ru, sape.ru и другие площадки.

    Сразу после регистрации креатива (статьи в нашем случае) ОРД присваивает ему идентификатор рекламы - erid. Именно этот код потом должен быть размещен в самой статье или в ссылке, связанной с рекламным материалом.

    Шаг 3. Разместите erid в статье

    Для текстовой статьи у РКН есть два базовых сценария размещения erid. Приоритетный вариант - присоединить идентификатор к кликовой ссылке, которая ведет на ресурс рекламодателя.

    Если разместить erid в ссылке невозможно, РКН рекомендует указывать его в текстовом блоке как контрастную и доступную для просмотра пометку в формате erid: XXXXX, причем поставить ее можно в начале или в конце статьи. Это как раз тот вариант, который чаще всего подходит для нативных публикаций, обзоров и рекламных статей без явной кнопки или баннера.

    Практически для статьи это обычно выглядит так:

    • в начале материала - пометка «Реклама» и строка erid: XXXXX;
    • либо erid в основной ссылке на сайт рекламодателя;
    • либо erid: XXXXX в конце текста, если ссылка не используется или не подходит по формату.

    В примерах рекомендаций РКН для текстовых материалов также используется пометка с указанием рекламодателя, например «Реклама ООО … ИНН …». Это удобный ориентир для оформления статьи, особенно когда материал публикуется на внешней площадке.

    Шаг 4. Опубликуйте материал и сохраните связку с креативом

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

    РКН отдельно подчеркивает, что получать erid и передавать статистику показов должно одно и то же лицо. Поэтому еще на старте лучше зафиксировать в договоре, кто отвечает за ОРД и последующую отчетность: рекламодатель, агентство, подрядчик или площадка.

    Шаг 5. Передайте отчетность после размещения

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

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


    Как маркировать статью на практике

    Если у вас статья на собственном сайте и внутри есть одна основная ссылка на лендинг или сайт рекламодателя, самый чистый вариант - встроить erid именно в эту ссылку. Это приоритетный способ, который РКН прямо называет основным.

    Если статья опубликована без ссылок, на внешней площадке или в формате, где ссылку с erid поставить неудобно, используйте текстовую маркировку erid: XXXXX в начале или в конце статьи. Главное, чтобы идентификатор был читаемым и не был спрятан в недоступном или технически нераспознаваемом виде.

    Если формат публикации нестандартный и непонятно, куда именно ставить erid, РКН рекомендует обращаться за рекомендациями в ОРД или в поддержку ЕРИР. Это разумный шаг для спецпроектов, редакционных интеграций, сложных CMS и нестандартных рекламных механик.

    Частые ошибки

    Одна из типовых ошибок - менять регистр символов в erid. В рекомендациях РКН прямо указано, что подмена строчных и заглавных букв считается ошибкой.

    Вторая частая проблема - шифрование ссылки, при котором система не может распознать идентификатор рекламы. РКН отдельно предупреждает, что в таком случае рекламное сообщение может получить статус «нарушение».

    Что делать со старыми материалами

    Для архивных рекламных публикаций, размещение которых завершилось до 1 сентября 2022 года и которые до сих пор доступны в интернете, получение и размещение идентификатора не требуется. В рекомендациях РКН для таких случаев указано лишь рекомендованное обозначение даты публикации архивного материала.

    Короткий чек-лист для бизнеса и веб-мастеров

    Перед публикацией рекламной статьи проверьте пять вещей:

    • определили ли вы, что материал действительно является рекламой, а не редакционным контентом;
    • выбрали ли ОРД и внесли ли в него договор, контрагентов и креатив;
    • получили ли erid для конкретной статьи;
    • поставили ли erid в ссылку или в начало/конец статьи;
    • понимаете ли, кто после размещения подает статистику и отчетность.

    Быстрый FAQ

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

    Где лучше ставить erid в статье?
    Приоритетный вариант = в кликовой ссылке на ресурс рекламодателя; если это невозможно, тогда в начале или в конце текстового блока.

    Можно ли поставить erid только в конце статьи?
    Да, для текстового блока РКН допускает размещение идентификатора в начале или в конце.

    Кто должен получать erid и подавать статистику?
    Это можно закрепить в договоре, но РКН указывает, что получать erid и передавать статистику должно одно и то же лицо.

    Когда сдаётся отчётность по статье?
    После завершения размещения и не позднее 30 числа месяца, следующего за месяцем показа, при этом статистика подаётся ежемесячно весь срок демонстрации материала.

    Нужно ли что-то делать со старой рекламной статьёй, опубликованной до 1 сентября 2022 года?
    Если размещение завершилось до этой даты, получать и размещать erid не требуется

    И конечно же сам официальный документ: 5_shagov_po_uchetu_internet-reklamy.pdf


    1 0 0 Ответить
  • kirilljsxK
    kirilljsx
    What pottery classes actually are

    c41dc1d3-7d26-414a-a9ac-3c12b781c4ac.webp

    Pottery classes are guided, in‑person sessions where you learn
    to shape, decorate, and fire clay into functional or decorative objects.
    A typical class mixes short demonstrations with lots of guided practice at the wheel
    or at a hand‑building table.

    Most beginner programs start with:

    • An intro to clay types and basic tools
    • Simple hand‑building techniques (pinch, coil, slab)
    • A first project like a pinch bowl or a small cylinder on the wheel
    • Clear studio rules on safety, glazing, and firing

    You do not need previous art experience.
    Beginner classes assume zero knowledge
    and walk you through every step from wedging to glazing.


    Why adults love pottery classes

    Key mental and physical benefits

    Research and studio experience show that pottery offers
    a unique mix of mental, emotional, and physical benefits for adults.

    • Stress relief and relaxation
      Working with clay lowers stress and anxiety,
      and can help reduce cortisol levels through rhythmic, tactile work.
    • Creativity and self‑expression
      Ceramics education improves creative thinking and gives
      a safe space to explore ideas in 3D form.
    • Mindfulness and focus
      Repetitive actions like wedging and throwing improve mindfulness,
      patience, and the ability to stay present.
    • Fine motor skills and coordination
      Hand‑eye coordination and attention to detail grow
      as you learn to control thickness, symmetry, and surface.
    • Confidence and sense of achievement
      Finishing your first piece and holding it after firing
      strongly boosts confidence and self‑esteem.

    Main types of pottery classes

    By technique

    Class type What you do Best for
    Wheel throwing Use a potter’s wheel for bowls, mugs, cylinders People who like technical challenges
    Hand‑building Pinching, coiling, slab‑building at a table Creative sculpting, decorative pieces
    Mixed technique Combination of wheel and hand‑building Curious beginners who want to try both
    Glazing & surface Focus on color, underglaze, textures, finishes Those who already have bisque pieces

    Wheel‑throwing looks dramatic and feels very satisfying,
    but hand‑building is often easier to control at first.
    Many studios, including Pottery Studio #1, offer mixed formats
    so you can discover which style you enjoy more.

    By duration and structure

    • One‑time workshop (1.5–3 hours)
      Great for “try once”, date nights, gifts, or team events.
      Usually you make 1–2 simple pieces and the studio handles firing.
    • Short series (3–6 weeks)
      Step‑by‑step courses that cover the full process
      from preparing clay to glazing finished work.
    • Long courses / open‑studio access
      For people building a regular hobby or portfolio,
      with independent practice time plus instructor feedback.

    What to expect in your first pottery class

    Most beginner pottery classes follow a similar, friendly structure.

    1. Studio tour and safety basics
      You get assigned a wheel or hand‑building station,
      meet tools, clay, and cleanup routines.
    2. Demo from the instructor
      The teacher shows how to wedge clay,
      center it on the wheel or form a simple pinch/coil pot.
    3. Your first project
      Wheel classes often aim for a small bowl or cylinder;
      hand‑building classes focus on a pinch pot or simple dish.
    4. Drying and first firing (bisque)
      After class, staff dry and bisque‑fire your pieces for you.
    5. Glazing session
      In a later class you add glaze or underglaze,
      and the studio does the final, high‑temperature firing.

    Important reality check for beginners:

    • Your first pieces will be thick, wonky, and asymmetrical
      That is normal; mastering centering and even walls
      usually takes several sessions.
    • Failure is part of the process
      Many first cylinders collapse; learning pressure control
      and timing is exactly what classes are for.

    Skills you develop over time

    By attending pottery classes for a few weeks or months,
    most students gradually build a solid set of core skills.

    • Clay preparation and wedging
    • Centering and pulling walls on the wheel
    • Basic shapes: cylinders, bowls, small plates
    • Hand‑building forms: pinch pots, coils, slabs
    • Trimming, adding handles, attaching parts correctly
    • Surface design with slips, underglazes, and carving
    • Glazing choices and basic kiln schedules

    These skills scale from simple mugs
    to complex, high‑end functional ceramics or sculptural pieces.


    How to choose the right pottery class

    Step 1 — clarify your goal

    Ask yourself what you want most right now:

    • “I just want a fun night out”
      Choose a one‑time workshop with simple projects.
    • “I want a new long‑term hobby”
      Look for 4–8 week beginner series with clear curriculum.
    • “I want to get serious about ceramics”
      You need ongoing courses, critiques, and independent studio time.

    Step 2 — check these studio factors

    Factor What to look for
    Group size 4–10 people so the instructor can help everyone.
    Skill levels offered Separate beginner / intermediate / advanced groups.
    Equipment quality Well‑maintained wheels, tools, good ventilation.
    Schedule & location Evenings/weekends, easy transit or parking.
    Firing and materials Clear policy on how much clay and how many firings.

    Studios like Pottery Studio #1 usually list all of this
    on their class pages: level, length, projects, and what is included.

    Step 3 — match format to your personality

    • If you like structure and clear progress
      Pick a curriculum‑based series with defined weekly topics.
    • If you love experimenting
      Choose mixed‑technique or open‑studio programs
      where you can try different clays and glazes.
    • If you are nervous as a total beginner
      Look for explicit “Absolute Beginner” or “No experience needed” labels
      and small groups with high instructor attention.

    What is usually included in the price

    While details vary by studio, many pottery classes include:

    • Clay (often a set amount per course)
    • Use of wheels, tools, and studio space
    • Instructor time and demonstrations
    • One or two firings (bisque and glaze) for a limited number of pieces
    • Basic studio glazes for student work

    Extra costs can include:

    • Additional clay beyond the base allowance
    • Extra firings for oversized or numerous pieces
    • Premium glazes or specialty materials

    When you compare options, always check
    what “materials and firing included” actually means in practice.


    Typical levels: beginner to advanced

    Level You focus on
    Beginner Basic forms, safe studio habits, simple glazing.
    Intermediate Consistent sets (mugs, bowls), better thickness and curves.
    Advanced Complex forms, lidded pots, large work, personal style.

    Pottery Studio #1 and similar studios often let you
    repeat a level or mix levels as your confidence grows.


    Simple visualization:

    why adults join pottery classes

    Below is a conceptual breakdown of common motivations
    behind joining pottery classes (percentages illustrative,
    based on typical benefits described in studio and education articles).

    Reason Approx. share of motivation
    Stress relief 30%
    Creativity & self‑expression 25%
    New hobby / skill 20%
    Social connection 15%
    Mindfulness & mental health 10%

    This pie‑style breakdown shows how pottery sits
    at the intersection of well‑being, creativity, and community.


    How to prepare for your first class

    To make your first visit to Pottery Studio #1
    or any local studio smoother and more enjoyable,
    prepare a few simple things.

    • Wear clothes you do not mind getting dirty
      Clay washes out, but it is messy.
    • Trim long nails if possible
      Long nails make controlling thin walls much harder.
    • Arrive a bit early
      You will have time to sign forms, choose an apron,
      and get comfortable in the space.
    • Bring ideas, but stay flexible
      Very specific Pinterest‑level shapes are hard on day one;
      focus on learning fundamentals first.
    • Accept imperfect results
      Think of your first pieces as learning tools,
      not final masterpieces.

    When a studio like Pottery Studio #1 is a great fit

    A local, modern pottery studio is especially helpful if you:

    • Want clear, beginner‑friendly structure
    • Prefer small groups and lots of instructor feedback
    • Value a calm, aesthetically pleasing environment
    • Like the idea of leaving each block of classes
      with finished, food‑safe pieces you can use or gift

    If that sounds like you, booking a class through a dedicated studio site
    (such as Pottery Studio #1 via the Pottery classes section below)
    is usually the fastest way to get started.


    Link Preview Image
    One-time pottery classes in Toronto

    Classes in ceramics, pottery and painting in Toronto for children, teenagers and adults. Create clay dishes of your own design in just 1 class. Enjoy an interesting, creative and relaxing two-hour class in pottery, hand-building and painting in Toronto. Daily classes with an instructor from $ 110.

    favicon

    Pottery studio in Toronto | Classes & Parties (pottery-studio.ca)


    0 0 0 Ответить
  • kirilljsxK
    kirilljsx
    Как в Windows 11 изменить PDF-ридер по умолчанию

    На Windows 11 по умолчанию PDF‑файлы открываются в браузере Microsoft Edge или в Adobe Acrobat — даже если вы это не выбирали.

    Чтобы сменить программу для открытия PDF, выполните следующие шаги:

    1. Откройте меню Пуск и введите в поиске слово «Настройки».
    2. Перейдите в раздел Приложения → Приложения по умолчанию.
    3. В появившемся списке найдите нужный браузер или программу, которую хотите использовать (например, Comet, Яндекс.Браузер, Google Chrome и т.д.).
    4. Пролистайте вниз до расширения .pdf, кликните по нему и выберите нужное приложение.

    Готово! Теперь все PDF‑файлы будут открываться именно в том браузере или программе, которую вы указали.

    Ниже я приложил скрины что бы было проще ориентироваться и куда нажимать.


    e8eda052-7714-4c3a-9c15-271b7f84c0c6-image.jpeg

    d49e31bb-3967-4e19-8352-52ca9b5e0dad-image.jpeg

    b3746374-77ce-43d5-aee5-8dffd4e3415d-image.jpeg

    4039f88d-f527-4acf-a769-4667536f39e9-image.jpeg

    15627b48-9d25-4429-923c-168d9f53a681-image.jpeg


    0 0 0 Ответить
  • kirilljsxK
    kirilljsx
    Чем отличаются ссылки dofollow и nofollow

    Dofollow - это обычные ссылки, которые передают «ссылочный вес» и участвуют в ранжировании, а nofollow - ссылки с атрибутом rel=“nofollow”, которые, как правило, не передают вес и служат больше для навигации, рекламы и защиты от спама.

    Что известно

    • Dofollow - любая ссылка без атрибута rel=“nofollow”: по умолчанию все внешние ссылки считаются dofollow и передают PageRank/«вес» на страницу, на которую ведут.

    • Nofollow — ссылка вида <a href="url" rel="nofollow">текст</a>, которая рекомендует поисковым ботам не учитывать её при расчёте авторитетности и не передавать ссылочный вес.

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

    • Dofollow‑ссылки усиливают позиции страницы в выдаче, а nofollow помогают балансировать ссылочный профиль, помечать рекламу, UGC и снижать риски санкций за продажу ссылок и спам.

    • Если у ссылки нет rel=“nofollow”, отдельный rel=“dofollow” не обязателен: это просто обычная ссылка, которую поисковики учитывают.

    Техническая разница в HTML

    Примеры:

    • Dofollow (обычная ссылка):

      <a href="https://example.com">Анкорный текст</a>
      

      Здесь тег <a> создаёт ссылку, href указывает URL, анкор — кликаемый текст; отсутствие rel=“nofollow” делает её dofollow.

    • Nofollow:

      <a href="https://example.com" rel="nofollow">Анкорный текст</a>
      

      Атрибут rel="nofollow" говорит ботам: по этой ссылке не нужно передавать вес и не стоит учитывать её для ранжирования как «рекомендацию».

    Иногда используют также мета‑тег для всей страницы:

    <meta name="robots" content="noindex, nofollow">
    

    Он запрещает индексацию страницы и учёт всех ссылок на ней.

    Как влияет на SEO и PageRank

    • Dofollow‑ссылки:

      • Передают PageRank и «авторитет» страницы‑донора на акцептора.
      • Считаются поиском как рекомендация: чем больше качественных dofollow‑ссылок, тем выше потенциал роста позиций.
      • Влияют именно на продвигаемый ресурс (куда ведут), а не на страницу, где размещены.
    • Nofollow‑ссылки:

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

    Принципиальное отличие: dofollow активно участвуют в распределении ссылочного веса и построении авторитетности, nofollow — нет, но дают поиску сигналы для краулинга и анализа ссылочного профиля.

    Когда использовать dofollow и nofollow

    Типичные кейсы для dofollow

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

    Типичные кейсы для nofollow

    • Рекламные и партнёрские ссылки (баннеры, UTM, реферальные): так вы соблюдаете рекомендации поисковиков и снижаете риск санкций за продажу ссылок.
    • Пользовательский контент: ссылки в комментариях, форумах, профилях, где высок риск спама.
    • Страницы, которым не хотите отдавать вес: корзина, личный кабинет, админ‑разделы, страницы с персональными данными.
    • Сомнительные или малоизвестные внешние источники, за которые вы не готовы «ручаться» как за рекомендацию.

    Зачем нужны оба типа и что с «естественностью»

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

    Nofollow‑ссылки:

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

    Пример: новостной портал ставит на ваш сайт nofollow‑ссылку в обзоре сервиса - прямого PageRank почти нет, но вы получаете переходы, бренд‑запросы и поведенческие сигналы.


    0 0 0 Ответить
  • kirilljsxK
    kirilljsx
    Шпаргалка: командная строка

    Если только начинаете работать с командной строкой и всё путается в голове, сохраните себе эту шпаргалку и возвращайтесь к ней, когда что‑то забудете.

    Навигация по папкам

    • pwd - показывает, в какой директории вы сейчас находитесь.
    • ls - выводит список файлов и папок в текущей директории.
    • cd first-project - переход в папку first-project.
    • cd first-project/html - переход сразу в подпапку html внутри first-project.
    • cd .. - подняться на один уровень вверх (в родительскую папку).
    • cd ~ - перейти в домашнюю директорию пользователя (например, /Users/имя_пользователя).

    Создание папок и файлов

    • mkdir second-project - создать папку second-project в текущей директории.
    • touch index.html - создать пустой файл index.html в текущей папке.
    • touch index.html style.css script.js - создать сразу несколько файлов; имена перечисляются через пробел.

    Удаление файлов и директорий

    • rm about.html - удалить файл about.html.
    • rmdir images - удалить пустую папку images.
    • rm -r second-project - рекурсивно удалить папку second-project вместе со всем её содержимым (будьте осторожны с этой командой).

    Ускорение работы: автодополнение

    Чтобы не печатать длинные названия папок и файлов целиком, начните вводить имя и нажмите Tab. Если такой путь существует в текущей директории, терминал допишет его автоматически. Это экономит время и уменьшает количество опечаток.


    0 0 0 Ответить
  • hannadevH
    hannadev
    findLastIndex vs reverse + findIndex: последний активный заказ без мутаций и лагов

    В большом списке заказов часто нужно найти последний активный. Обычный findIndex лезет с начала - зря тратит время на уже нерелевантные записи. А reverse() создает копию и мутирует массив - привет, лишняя память и побочные эффекты.

    findLastIndex из ES2023 решает это нативно: идет с конца, возвращает индекс первого подходящего. Без костылей, без аллокаций. На списках в 10k+ элементов разница в perf заметна сразу. Разберем, почему это не просто сахар, а реальный инструмент против тормозов.

    Почему reverse() - это всегда компромисс

    Код с reverse() выглядит знакомо: берут массив заказов, реверсят, находят первый активный, потом корректируют индекс обратно. Просто, интуитивно. Но под капотом создается новый массив - O(n) времени и памяти. На большом списке это утечка perf.

    Если массив мутируется где-то еще (а в реальном app это норма), reverse() сломает логику. Приходится писать toReversed() - тот же геморрой, только с современным названием. А если забыть восстановить? Баг в продакшене готов. findLastIndex таких подстав не оставляет - работает с оригиналом, итерация только до первого матча.

    Реальный кейс: список из 50k заказов, ищем последний active: true. reverse + findIndex проверит все, findLastIndex остановится на нужном с конца. В DevTools профайлере разница в миллисекундах.

    Вот типичные подводные камни reverse-подхода:

    • Аллокейшн памяти: копия массива жрет RAM, на слабых девайсах заметно.
    • Мутации состояния: забыл восстановить - и state полетел.
    • Неочевидный индекс: -1 после find нужно маппить обратно, легко ошибиться.
    Подход Время на 10k Память Мутации
    reverse + findIndex O(n) +O(n) да
    findLastIndex O(k), k << n O(1) нет

    findLastIndex под капотом: как это работает

    Метод итерирует с конца: для каждого элемента колбэк (element, index, array). Возвращает truthy - метод стопорится и дает индекс. Нет матча - -1. Важно: пробрасывает все индексы, включая holes в sparse arrays, но undefined обрабатывает как значение.

    Колбэк получает привычные аргументы: значение, его индекс, сам массив. Можно использовать thisArg для контекста. По умолчанию early return - не проходит весь массив, если нашел. На практике это спасает от лагов в ивент-лупе.

    Пример с заказами:

    const orders = [
      {id: 1, status: 'done'},
      {id: 2, status: 'active'},
      {id: 3, status: 'active'},
      // ... 10k элементов
    ];
    const lastActiveIndex = orders.findLastIndex(order => order.status === 'active');
    // Вернет индекс id:3, не проверив начало
    

    Ключевые фичи метода:

    • Итерация только до первого матча с конца - оптимально для последних событий.
    • Поддержка sparse arrays: holes не ломают логику.
    • Работает с TypedArray - бонус для perf-критичного кода.
    • Нет side-effects на массив.

    Практика: последний заказ без тормозов

    Представь API-ответ с 20k записями заказов. Нужно рендерить список, но выделить последний active. findIndex с начала - 10+ сек в worst case на мобильнике. findLastIndex - пара мс.

    В React/Vue: мутируешь state reverse() - ререндер всего списка, лаг в UI. Нативный метод - чистая операция. Плюс, в strict mode React ругается на мутации. А если с мемоизацией? useMemo с reverse() пересчитается зря.

    Тестировал на бенчмарке: массив 100k объектов, поиск последнего с полем status: ‘active’ на позициях 99999, 50000, 10.

    Тест-кейс reverse + findIndex (мс) findLastIndex (мс)
    Матч в конце 45 1
    Матч посередине 23 12
    Нет матча 50 50

    Выводы из бенча:

    • Early stop выигрывает на типичных данных (последний заказ реально последний).
    • При нет матча - паритет, но без аллокейшена.
    • На TypedArray findLastIndex еще быстрее за счет нативной оптимизации.

    Когда findLastIndex не панацея

    Метод не ищет все матчи - только первый с конца. Для полного скана нужен for-of с break. Браузеры: Chrome 118+, Firefox 109+, Safari 16.4 - полифилл только для legacy.

    В редких кейсах (линейный поиск с начала) findIndex быстрее. Но для логов, заказов, событий - findLastIndex в приоритете. Проверь support в caniuse, если целит legacy.

    Верни индекс - и спи спокойно

    findLastIndex убирает костыли из кода, экономит циклы CPU и RAM. Массивы заказов больше не тормозят UI. Осталось за кадром: как комбинировать с partition или groupBy из ES2025 для группировки по статусу. И подумай, где еще в твоем бэке/фронте висят reverse() - рефакторинг даст профит.


    0 0 0 Ответить
  • kirilljsxK
    kirilljsx
    AI-нативные IDE 2026: Cursor и Gemini Code Assist автоматизируют DevOps и монорепы

    Обложка: AI-нативные IDE 2026: как Cursor и Google Gemini Code Assist автоматизируют DevOps и индексацию монорепозиториев

    Представьте: монорепозиторий на 500к строк кода, где фронт, бэк, мобилька и DevOps-скрипты свалены в одну кучу. Ручная индексация? Забудьте. CI/CD пайплайны ломаются из-за YAML-ошибок? Уже не ваша проблема. Cursor и Google Gemini Code Assist берут на себя рутину, индексируя весь репозиторий и генерируя DevOps-конфиги на лету. Это сэкономит часы на рефакторинг и деплой, особенно в командах, где джуниоры путают Dockerfile с Kubernetes-манифестом.

    Cursor: ИИ-нативный редактор, который понимает ваш весь проект

    Cursor - это не плагин, а полноценная IDE на базе форка VS Code. Она индексирует весь codebase, включая связи между субпроектами в монорепозитории. Хотите спросить ‘где обрабатывается оплата?’ - Codebase Chat выдаст точные ссылки на файлы. Inline Edit позволяет выделить блок кода, нажать Cmd+K и сказать ‘добавь обработку ошибок и логирование’ - и только этот блок перепишется.

    Ключевые фичи для DevOps:

    • Автогенерация Dockerfiles и YAML: Агент Composer создает файлы для CI/CD.
    • Мультимодельность: Выбирайте Claude Opus 4.6, GPT-5.2 или Gemini 3 в настройках. Для монорепов Gemini с его 1M токенов контекста - идеал.
    • Tab-дополнение: Предсказывает не слова, а целые блоки рефакторинга, импортируя зависимости автоматически.

    Поддержка JetBrains IDE (IntelliJ, PyCharm) через ACP с марта - теперь и фанаты Java не отстанут.

    Gemini Code Assist: Облачный DevOps на стероидах

    Это плагины для VS Code, JetBrains и Eclipse, заточенные под Google Cloud. Главный профит - индексация монорепозиториев с учетом связей между субпроектами. Клонируете репозиторий - AI-агенты сами все проанализируют.

    В DevOps:

    • Генерация Kubernetes-манифестов, Helm-чартов и миграций БД.
    • Интеграция с CI/CD: Через API запускайте авто-тесты или статический анализ прямо в пайплайне.
    • Мультимодальность: Помогает с UI/UX, генерируя React-компоненты или Figma-прототипы на основе кода.

    Gemini 3 под капотом жрет огромные контексты, идеально для enterprise-монорепов.

    Сравнение: Cursor vs Gemini Code Assist

    Критерий Cursor Gemini Code Assist
    Тип Отдельная IDE (форк VS Code) Плагины для IDE
    Индексация монорепо Весь репозиторий + чат Субпроекты + связи
    DevOps-автоматизация Dockerfile, YAML, Composer K8s, GCP, CI API
    Модели Claude, GPT-5.2, Gemini Gemini 3
    Цена $20/мес $19/мес (бесплатный tier)

    Cursor выигрывает в скорости редактирования, Gemini - в облачной инфраструктуре.

    Практика: Автоматизируем DevOps на Python

    Вот пример, как интегрировать Gemini Code Assist в CI/CD через API. Скрипт генерирует Dockerfile для вашего Node.js-приложения.

    import requests
    
    API_KEY = 'your_gemini_api_key'
    PROMPT = '''Сгенерируй Dockerfile для Node.js монорепо с фронтом (Next.js) и бэком (Express). Учти multi-stage build, оптимизацию для prod и healthcheck. Репо структура: /frontend /backend'''
    
    response = requests.post(
        'https://api.google.dev/gemini/code-assist',
        headers={'Authorization': f'Bearer {API_KEY}'},
        json={'prompt': PROMPT, 'context': 'монорепо индексация'}
    )
    
    dockerfile = response.json()['generated_code']
    print(dockerfile)
    

    Этот скрипт в GitHub Actions сгенерирует готовый файл - запустите в пайплайне, и деплой на GCP сам соберется.

    Системный промпт для агента в Cursor

    “Ты - DevOps-инженер в команде из 10 разрабов. Проект: монорепо с TypeScript бэком, React фронтом и Python ML. Задача: [инструкция]. Шаги: 1. Проанализируй связи файлов. 2. Сгенерируй только изменения. 3. Добавь тесты и миграции. Объясни diff.”

    Такой промпт заставит агента думать как senior, минимизируя галлюцинации.

    В РФ эти инструменты уже работают через VPN, но лимиты токенов и цены в долларах бьют по карману соло-разрабам. Для студий с Google Cloud - профит огромный, особенно если мигрируете на GCP. Cursor проще в освоении, без облачных зависимостей.

    Итог: Переходите или ждите?

    Эти IDE не заменяют разрабов, но режут рутину на 40-50%, освобождая время на бизнес-логику. В монорепах профит максимальный - индексация и DevOps автоматизированы. А вы уже пробовали Cursor для рефакторинга или Gemini для K8s? Как справляетесь с индексацией огромных репозиториев в своей команде? Делитесь в комментах, обсудим альтернативы!


    0 0 0 Ответить
  • hannadevH
    hannadev
    find() vs findIndex(): когда нужен элемент, когда позиция

    Разработчики часто путают эти два метода, хотя они делают совсем разное. find() возвращает сам элемент массива, а findIndex() - его индекс. Понимание разницы экономит время на отладку и делает код более читаемым.

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

    Что возвращает find(): берём сам элемент

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

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

    const users = [
      { id: 1, name: 'Alice', role: 'admin' },
      { id: 2, name: 'Bob', role: 'user' },
      { id: 3, name: 'Charlie', role: 'user' }
    ];
    
    const user = users.find(u => u.id === 2);
    console.log(user); // { id: 2, name: 'Bob', role: 'user' }
    console.log(user.name); // Bob - сразу можешь обращаться к свойствам
    

    Основные случаи, когда find() - лучший выбор:

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

    Что возвращает findIndex(): нужна позиция

    findIndex() - это когда тебе нужна позиция элемента в массиве. Метод работает точно так же, как find(), но возвращает не сам элемент, а его индекс (номер позиции). Если ничего не найдено, вернёт -1.

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

    const users = [
      { id: 1, name: 'Alice' },
      { id: 2, name: 'Bob' },
      { id: 3, name: 'Charlie' }
    ];
    
    const index = users.findIndex(u => u.id === 2);
    if (index !== -1) {
      users.splice(index, 1); // удаляем Bob
    }
    

    Люди часто пишут такой антипаттерн: сначала ищут элемент через find(), потом ищут его индекс через indexOf(). Это лишняя работа для интерпретатора - если нужен индекс, используй сразу findIndex().

    Основные случаи, когда findIndex() - правильный выбор:

    • Нужно удалить или заменить элемент в массиве
    • Планируешь работать с методами вроде splice(), slice() с конкретным индексом
    • Нужно проверить позицию элемента в иерархии данных
    • Будешь передавать индекс в другие функции

    Сравнение в одной таблице

    Параметр find() findIndex()
    Возвращает Сам элемент (значение) Индекс элемента (число)
    Нет результата undefined -1
    Когда использовать Нужны данные элемента Нужна позиция в массиве
    Производительность Одинакова Одинакова
    Типичный case Получить объект целиком Удалить или заменить

    Реальные примеры: как это выглядит в продакшене

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

    const cart = [
      { id: 101, name: 'Laptop', price: 999 },
      { id: 102, name: 'Mouse', price: 25 },
      { id: 103, name: 'Keyboard', price: 75 }
    ];
    
    function removeFromCart(productId) {
      const index = cart.findIndex(item => item.id === productId);
      if (index !== -1) {
        cart.splice(index, 1);
        console.log('Товар удалён');
      }
    }
    
    removeFromCart(102);
    

    А вот другой пример: тебе нужно показать карточку товара с полной информацией. Здесь нужен сам объект товара, его свойства. find() - лучший вариант.

    const products = [
      { id: 101, name: 'Laptop', price: 999, stock: 5 },
      { id: 102, name: 'Mouse', price: 25, stock: 50 },
      { id: 103, name: 'Keyboard', price: 75, stock: 20 }
    ];
    
    function displayProduct(productId) {
      const product = products.find(p => p.id === productId);
      if (product) {
        console.log(`${product.name} - ${product.price}$, в наличии: ${product.stock}`);
      }
    }
    
    displayProduct(102);
    

    Ещё один пример - фильтрация данных перед редактированием. Тебе нужно найти пользователя и проверить, может ли он редактировать пост. find() даёт тебе весь объект пользователя сразу.

    const users = [
      { id: 1, name: 'Alice', role: 'admin' },
      { id: 2, name: 'Bob', role: 'user' },
      { id: 3, name: 'Charlie', role: 'moderator' }
    ];
    
    function canEditPost(userId) {
      const user = users.find(u => u.id === userId);
      return user && (user.role === 'admin' || user.role === 'moderator');
    }
    

    Оптимизация: не смешивай методы

    Одна из частых ошибок - использовать оба метода подряд, когда достаточно одного. Вот антипаттерн:

    // Плохо: ищешь элемент, потом его индекс
    const user = users.find(u => u.id === 2);
    const index = users.indexOf(user);
    users.splice(index, 1);
    

    Правильно - сразу иди за индексом:

    // Хорошо: сразу берёшь индекс
    const index = users.findIndex(u => u.id === 2);
    if (index !== -1) {
      users.splice(index, 1);
    }
    

    Аналогично, если тебе нужен сам элемент, не ищи его дважды. find() уже вернёт то, что нужно - не нужно потом искать индекс.

    Второй нюанс - проверка на существование элемента. Если ты проверяешь через find(), помни, что вернётся undefined, если ничего не найдено. При findIndex() вернётся -1. Это важно при условных проверках:

    const user = users.find(u => u.id === 999);
    if (user) { // undefined - это falsy значение
      // работаешь с юзером
    }
    
    const index = users.findIndex(u => u.id === 999);
    if (index !== -1) { // правильная проверка для индекса
      // работаешь с позицией
    }
    

    Когда выбор действительно имеет значение

    Скорость работы одинаковая - оба метода проходят по массиву и выполняют функцию-проверку. Разницы в производительности не заметишь даже на массиве из миллиона элементов.

    Читаемость кода - вот это важно. Когда другой разработчик (или ты через месяц) видит find(), сразу понимает, что ищется сам элемент. Если findIndex() - значит, нужна позиция. Это как комментарий к коду, только встроенный в название метода.

    Логика программы зависит от выбора. Если ты ищешь через find(), а потом нужна позиция, придётся искать второй раз. Если наоборот - такая же проблема. Правильный выбор сразу избавляет от лишних операций.

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

    Думай о контексте, не о методе

    Лучше всего выбирать метод, отвечая на простой вопрос: что мне нужно от этого массива? Если ответ - “данные элемента”, то find(). Если ответ - “позиция для удаления или вставки”, то findIndex(). Это не про сложность - это про то, что именно решает твою задачу.

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


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

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

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

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

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

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

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

  • Проверка стала проще с 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
    568

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

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

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

GameFishG
GameFish

Статистика:

63

В сети

345

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

2.0k

Темы

2.9k

Сообщения

Категории

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

Контакты

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

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

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

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

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