<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/">
  <channel>
    <language>ru</language>
    <title>Библиотеки</title>
    <description/>
    <link>https://tproger.ru/tag/biblioteki</link>
    <atom:link href="https://tproger.ru/tag/biblioteki/feed" rel="self" type="application/rss+xml"/>
    <lastBuildDate>Sat, 03 Oct 2026 11:25:07 GMT</lastBuildDate>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>12</sy:updateFrequency>
    <image>
      <title>Библиотеки</title>
      <link>https://tproger.ru</link>
      <url>https://tproger.ru/apple-touch-icon.png</url>
    </image>
    <item>
      <title>В Excelize нашли DoS: файл в 3 КБ занимает OpenFile на минуту</title>
      <link>https://tproger.ru/news/v-excelize-nawli-dos-fajl-v-3-kb-zanimaet-openfile-na-minutu</link>
      <comments>https://tproger.ru/news/v-excelize-nawli-dos-fajl-v-3-kb-zanimaet-openfile-na-minutu?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/v-excelize-nawli-dos-fajl-v-3-kb-zanimaet-openfile-na-minutu</guid>
      <description><![CDATA[<p>GHSA-jrfj-fhj2-jjvm: Excelize 2.3.1–2.11.0 без ограничений выполняет spinCount итераций из файла. 3 072 байта держат OpenFile 58,65 с, отмены нет, патча нет.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/v-excelize-nawli-dos-fajl-v-3-kb-zanimaet-openfile-na-minutu">В Excelize нашли DoS: файл в 3 КБ занимает OpenFile на минуту</a>»</p>]]></description>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Уязвимость]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 07 Sep 2026 09:30:24 GMT</pubDate>
      <content:encoded><![CDATA[<p>В Excelize, Go-библиотеке для чтения и записи файлов Excel (около 21 тысячи звёзд на GitHub), <a href="https://github.com/qax-os/excelize/security/advisories/GHSA-jrfj-fhj2-jjvm">опубликована уязвимость</a> отказа в обслуживании. Файл размером 3 072 байта заставляет OpenFile крутить цикл выработки ключа столько раз, сколько указано в самом файле: при значении 100 000 000 вызов на версии 2.11.0 занимает 58,65 секунды и только потом возвращает ошибку «zip: not a valid zip file». Уязвимы все версии с 2.3.1 по 2.11.0, исправления на момент публикации нет, оценка CVSS 7,5.</p><p>Под угрозой сервисы, которые открывают недоверенные файлы через Excelize: импорт таблиц, конвертеры и обработчики отчётов. Ограничение размера загрузки само по себе не устраняет проблему, поскольку приведённый исследователем файл занимает всего 3 072 байта. До исправления отчёт предлагает отсеивать неподдерживаемые зашифрованные контейнеры или изолировать обработку по времени.</p><ul><li>Причина: если первые восемь байт файла совпадают с сигнатурой OLE, Excelize идёт по ветке расшифровки независимо от того, задан ли пароль.</li><li>Функция convertPasswdToKey выполняет spinCount итераций хеширования до проверки верификатора, а spinCount берётся из XML-потока EncryptionInfo без ограничений.</li><li>Стоимость линейная, около 0,6 микросекунды на итерацию: 1e8 даёт около минуты, 1e9 около десяти минут; память при этом держится на 24 МБ.</li><li>На пути нет context.Context, поэтому вызывающий код не может отменить операцию; после ответа HTTP-обработчика по таймауту горутина продолжит вычисление.</li><li>Excel и LibreOffice обычно записывают spinCount 100 000; в отчёте такой вызов занимает 61 миллисекунду. Автор предлагает ограничить счётчик при разборе файла. Сообщил исследователь arpitjain099; уведомление опубликовано 6 сентября, идентификатора CVE и патча пока нет.</li></ul><h2>Как файл на три килобайта занимает библиотеку на минуту</h2><p>Зашифрованные паролем книги Excel хранятся в OLE-контейнере, внутри которого лежит поток EncryptionInfo с параметрами шифрования и сам зашифрованный пакет. Excelize определяет такой файл по первым восьми байтам: функция openReaderAt ветвится только по заголовку и не смотрит, передал ли вызывающий код пароль в опциях. Дальше agileDecrypt вызывает convertPasswdToKey, где ключ выводится из пароля повторным хешированием; число повторов задаёт поле spinCount, и проверка хеша-верификатора идёт уже после этого цикла.</p><p>Само поле spinCount в коде объявлено как обычный int и заполняется голым xml.Unmarshal из потока файла. Никакой верхней границы нет, поэтому атакующий сам выбирает, сколько времени займёт вызов. Автор отчёта проверил это на выпущенных версиях с proxy.golang.org без директив replace:</p><p>Цикл появился вместе с файлом crypt.go в версии 2.3.1 и с тех пор не менялся. Память во время атаки остаётся плоской, около 24 МБ, поэтому её нельзя отловить ни лимитом памяти, ни OOM-киллером: процесс просто занимает ядро на выбранное атакующим время. Автор отмечает, что уязвимость касается только доступности и не угрожает программам, которые открывают файлы, созданные их же оператором.</p><h2>Чем защититься, пока нет патча</h2><p>Самый простой фильтр стоит на границе: если сервис не поддерживает зашифрованные книги, отбрасывайте файлы, которые начинаются с OLE-сигнатуры D0 CF 11 E0 A1 B1 1A E1, до вызова Excelize. Обычный XLSX это ZIP-архив и начинается с 50 4B 03 04. Такая проверка занимает одну строку и полностью закрывает вектор для сервисов без паролей.</p><p>Проверьте используемую версию Excelize в зависимостях проекта. В сохранённом advisory уязвимыми названы версии с 2.3.1 по 2.11.0 включительно, поле исправленных версий пусто. Следить за появлением патча следует по тому же advisory и релизам проекта; отсутствие предупреждения отдельного сканера само по себе не подтверждает безопасность зависимости.</p><p>Если зашифрованные файлы нужны, разбор стоит вынести в отдельный процесс или воркер с жёстким лимитом времени: context.Context на этом пути Excelize не поддерживается; остановить горутину снаружи невозможно. Полезно также разобрать EncryptionInfo самостоятельно и отклонить файлы, где spinCount больше, скажем, миллиона: Excel и LibreOffice обычно используют 100 000. Автор отчёта предлагает мейнтейнерам такой потолок на этапе парсинга.</p><p>Таймаут должен ограничивать именно вычисление. Возврат ошибки клиенту по истечении времени ожидания не останавливает цикл в уже запущенной горутине: в описанном пути нет механизма отмены. Изоляция в отдельном процессе позволяет завершить обработчик целиком, если он вышел за лимит. Это временное ограничение последствий; проверка недоверенного счётчика внутри библиотеки остаётся предлагаемым исправлением причины.</p><h2>Почему это типовой класс ошибок для парсеров</h2><p>Схема одна и та же: формат позволяет файлу самому объявить, сколько работы предстоит парсеру, а парсер верит. Вышло исправление libheif 1.23.4, где файл с неограниченным числом элементов давал квадратичное время разбора и полтора гигабайта памяти. У Excelize ситуация проще: нет ни рекурсии, ни аллокаций, только счётчик из недоверенного XML. Следить за исправлением стоит в <a href="https://github.com/qax-os/excelize">репозитории проекта</a>: в advisory должна появиться исправленная версия, после чего можно будет обновить зависимость и проверить импорт. О диагностике горутин в работающем сервисе рассказывает <a href="https://tproger.ru/news/go-1-27-nahodit-utechki-gorutin-v-rabotayushhem-servise-cherez-pprof">новый профиль в Go 1.27</a>, а о девяти уязвимостях в curl того же класса мы <a href="https://tproger.ru/news/curl-8-22-0-zakryl-devyat-uyazvimostej-i-otkazalsya-ot-tls-srp">писали на прошлой неделе</a>.</p><p>Источники: <a href="https://github.com/qax-os/excelize/security/advisories/GHSA-jrfj-fhj2-jjvm">GHSA-jrfj-fhj2-jjvm: Unbounded spinCount in agile decryption burns CPU during OpenFile</a>, <a href="https://github.com/qax-os/excelize">Репозиторий qax-os/excelize</a></p><p>Изображение на обложке: Excelize, логотип проекта</p>]]></content:encoded>
    </item>
    <item>
      <title>Polars 2.0 RC переводит LazyFrame на потоковый движок и ломает тихие касты</title>
      <link>https://tproger.ru/news/polars-2-0-rc-perevodit-lazyframe-na-potokovyj-dvizhok-i-lomaet-t</link>
      <comments>https://tproger.ru/news/polars-2-0-rc-perevodit-lazyframe-na-potokovyj-dvizhok-i-lomaet-t?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/polars-2-0-rc-perevodit-lazyframe-na-potokovyj-dvizhok-i-lomaet-t</guid>
      <description><![CDATA[<p>Первый release candidate Polars 2.0: LazyFrame.collect() идёт через streaming-движок, порядок строк в join и group_by не гарантирован, is_in и concat больше не молчат об ошибках типов. Как проверить свой код.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/polars-2-0-rc-perevodit-lazyframe-na-potokovyj-dvizhok-i-lomaet-t">Polars 2.0 RC переводит LazyFrame на потоковый движок и ломает тихие касты</a>»</p>]]></description>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Rust]]></category>
      <category><![CDATA[Анализ данных]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 03 Sep 2026 06:53:04 GMT</pubDate>
      <content:encoded><![CDATA[<p>Команда Polars 2 сентября <a href="https://pola.rs/posts/announcing-polars-2/">выпустила</a> первый release candidate версии 2.0 библиотеки для работы с таблицами на Python и Rust. Финальный релиз обещан «в ближайшие недели». Главное изменение одно: любой вызов collect() у LazyFrame теперь по умолчанию выполняется потоковым движком, который обрабатывает промежуточные данные порциями и, по словам авторов, заметно снижает расход памяти. Автор библиотеки Ричи Винк пишет, что новых функций в 2.0 почти нет, а мажорная версия нужна, чтобы избавиться от старых архитектурных решений и поменять дефолты.</p><p>Для тех, кто гоняет Polars в пайплайнах, это значит два дела на сегодня. Во-первых, после обновления часть запросов может вернуть строки в другом порядке: потоковый движок не гарантирует порядок для join, group_by и unpivot, если явно не попросить. Во-вторых, код, который годами «работал» на неявных приведениях типов и молчаливом заполнении пропусков, начнёт падать с ошибкой. Разработчики называют это осознанной политикой: ошибка сразу лучше неверного результата через двадцать минут работы пайплайна.</p><ul><li>RC ставится командой pip install polars==2.0rc1; финальный 2.0 выйдет в ближайшие недели, точной даты нет.</li><li>LazyFrame.collect() по умолчанию идёт через streaming-движок; по ожиданиям авторов, в совокупности он «легко в 5 раз быстрее» старого in-memory и заметно экономит память; независимых замеров RC нет.</li><li>Порядок строк после join, group_by и unpivot больше не гарантирован; для join и group_by порядок возвращает параметр maintain_order, для unpivot нужен явный sort; старый движок включается через pl.Config.set_engine_affinity("in-memory") или collect(engine="in-memory").</li><li>is_in с разными типами, горизонтальный concat с разной высотой, касты строк в даты и целых в Enum теперь бросают исключение вместо тихого приведения.</li><li>Большинство удалённых методов и параметров отвечают типизированными ошибками AttributeRemovedError и ArgumentRemovedError с подсказкой, чем заменить.</li></ul><h2>Почему потоковый движок потребовал мажорной версии</h2><p>Polars давно развивает два движка. Классический in-memory собирает результат каждой операции целиком в памяти. Потоковый разбивает данные на куски и прогоняет их через план запроса конвейером, поэтому промежуточные результаты не раздуваются. До 2.0 потоковый движок нужно было включать явно; теперь режим engine="auto" выбирает именно его.</p><p>Цена такого дефолта в порядке строк: потоковый движок для ряда операций его не гарантирует. Старый движок порядок сохранял, и на это молча полагалось много кода: например, брали первую строку после группировки и считали её «самой ранней». В 2.0 такие места нужно найти и явно попросить порядок (у join и group_by есть параметр maintain_order, после unpivot остаётся явный sort):</p><p>Заявление о скорости стоит читать как оценку вендора: «в сумме мы ожидаем, что потоковый движок будет легко в 5 раз быстрее», со ссылкой на <a href="https://pola.rs/posts/benchmarks/">собственные бенчмарки</a> Polars. Независимых замеров на RC пока нет, и выигрыш зависит от запроса: на маленьких таблицах, которые целиком помещаются в кеш, разница будет меньше, чем на группировках по десяткам гигабайт.</p><h2>Где код перестанет молчать об ошибках</h2><p>Вторая тема релиза сформулирована в посте так: ошибки должны подниматься заранее, а не через 20 минут работы пайплайна, и неявное поведение при несовпадении данных должно включаться явно, а не быть дефолтом. Авторы отдельно отмечают, что строгость стала ценнее с приходом ИИ-агентов: агент может вызвать collect_schema(), проверить типы без чтения данных и быстро получить обратную связь. Примеры из поста и <a href="https://docs.pola.rs/releases/upgrade/2/">руководства по миграции</a>:</p><ul><li>is_in с разными типами. Раньше Int64 и Float64 приводились к общему супертипу, даже если это теряло точность. В примере из поста идентификатор 9007199254740993 при касте в float64 округлялся до 9007199254740992 (граница, до которой float64 представляет все целые точно), и проверка по списку «помеченных» аккаунтов давала ложное совпадение. В 2.0 это InvalidOperationError: кастовать нужно самому и осознанно.</li><li>Горизонтальный concat. Таблицы высотой 5 и 4 раньше склеивались, а недостающая ячейка молча становилась null; типичный сценарий из поста: тихо упавшая задача за один из дней. Теперь ShapeError, а старое поведение включается через how="horizontal_extend".</li><li>Касты заменены специализированными методами. Целые в Enum или Categorical и обратно: вместо cast() нужны .cat.to() и .cat.physical(). Строка в дату: вместо cast(pl.Date) методы .str.to_date() и .str.to_datetime(), которым можно явно задать формат. Кастовать плоскую колонку в List через cast(pl.List(...)) тоже нельзя, для этого есть pl.list().</li><li>Булевы операторы между Boolean и целыми числами теперь ошибка; std() и var() для Duration удалены, сначала переводите в микросекунды через .dt.total_microseconds().</li><li>Каст между Struct с разным числом полей при strict=True (дефолт) падает, а не обрезает лишние поля; руководство помечает это отдельным предупреждением, потому что раньше данные терялись молча.</li></ul><p>Отдельный набор изменений касается чтения CSV. При сканировании набора файлов схема теперь выводится по первым 10 файлам, а не по всем (параметр infer_schema_files). Автоматические имена колонок для файлов без заголовка начинаются с column_0, а не column_1; это же касается read_excel и read_ods. Пользовательская схема в scan_csv сопоставляется с файлом по именам колонок, а не по позиции: раньше первая запись схемы молча получала данные первой колонки файла, даже если имена не совпадали. Для лишних и недостающих колонок появились параметры extra_columns и missing_columns, по умолчанию оба бросают ошибку.</p><h2>Что будет со старым кодом</h2><p>Для большинства удалений библиотека получила два типизированных исключения (документация предупреждает, что часть удалённого по-прежнему даёт обычные AttributeError и TypeError): polars.exceptions.AttributeRemovedError для удалённых методов и атрибутов и polars.exceptions.ArgumentRemovedError для удалённых параметров. Оба сообщения указывают на замену:</p><p>По словам Винка, большая часть удалённого давно помечена как deprecated, и у тех, кто обновлялся регулярно, пайплайны пострадать не должны. Команда просит сообщать, если из библиотеки убрали что-то, на что реально полагались. Смена движка не затрагивает eager-API DataFrame: выигрыша в скорости там не будет, потому что дефолт меняется только у LazyFrame. Остальные несовместимости на eager распространяются полностью: строгий concat, новые правила read_csv, убранные касты и удалённые методы.</p><h2>Как проверить свой проект до финального релиза</h2><ol><li>Поставьте RC в отдельное окружение: pip install polars==2.0rc1. В прод его тащить рано, это кандидат в релиз.</li><li>Прогоните тесты и посмотрите на исключения AttributeRemovedError, ArgumentRemovedError, InvalidOperationError и ShapeError: каждое сообщение содержит подсказку с заменой.</li><li>Найдите места, где код полагается на порядок строк после join, group_by или unpivot: сортировки «по умолчанию», head(1) после группировки, сравнение с эталоном по позициям. Добавьте maintain_order (join, group_by) или явный sort (unpivot).</li><li>Если результат обязан совпадать со старым до байта, зафиксируйте старый движок на время миграции: pl.Config.set_engine_affinity("in-memory").</li><li>Проверьте чтение CSV без заголовка (сдвиг нумерации колонок на единицу) и scan_csv с явной схемой (сопоставление по именам).</li></ol><p>В планах ветки 2.x, о которых команда, по её словам, «недостаточно говорила публично»: полноценная out-of-core обработка для потокового движка, новая архитектура IO-плагинов, собственный читатель S3, расширенное покрытие SQL, планировщик на основе оценки стоимости с переупорядочиванием join и отказ от mmap, после которого конвейер станет асинхронным от начала до конца. Сроков по этим пунктам нет. Замечания по RC команда принимает в <a href="https://github.com/pola-rs/polars/issues">issues на GitHub</a>.</p><p>Источники: <a href="https://pola.rs/posts/announcing-polars-2/">Pre-release of Polars 2.0 (блог Polars, Ritchie Vink)</a>, <a href="https://docs.pola.rs/releases/upgrade/2/">Руководство по переходу на Polars 2.0</a>, <a href="https://pola.rs/posts/benchmarks/">Бенчмарки Polars</a></p><p>Изображение на обложке: Логотип: Polars</p>]]></content:encoded>
    </item>
    <item>
      <title>Разработка TypeScript-библиотеки для построения реактивных графов распространения и обработки данных</title>
      <link>https://tproger.ru/articles/razrabotka-typescript-biblioteki-dlya-postroeniya-reaktivnyh-grafo</link>
      <comments>https://tproger.ru/articles/razrabotka-typescript-biblioteki-dlya-postroeniya-reaktivnyh-grafo?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Сморен Фрилайт]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/razrabotka-typescript-biblioteki-dlya-postroeniya-reaktivnyh-grafo</guid>
      <description><![CDATA[<p>Как построить гибкий реактивный граф обработки данных, где узлы изолированы друг от друга, а связи между ними строятся автоматически на основе их возможностей? Рассказываю о разработке Transferum — легковесной TypeScript-библиотеки для реактивных потоков. Внутри: разбор системы вычислимых типов для проверки контрактов в compile-time, управление маршрутизацией данных в графе и примеры построения динамических пайплайнов для IoT-датчиков и панелей управления.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/razrabotka-typescript-biblioteki-dlya-postroeniya-reaktivnyh-grafo">Разработка TypeScript-библиотеки для построения реактивных графов распространения и обработки данных</a>»</p>]]></description>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Функциональное программирование]]></category>
      <category><![CDATA[Архитектура ПО]]></category>
      <category><![CDATA[TypeScript]]></category>
      <category><![CDATA[Реактивное программирование]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 23 Jul 2026 15:14:02 GMT</pubDate>
      <content:encoded><![CDATA[<h2>Предыстория</h2><p>Все началось с рабочей задачи по реализации весьма специфичной web-панели мониторинга и управления различным оборудованием, в которой нужно было получать данные и отправлять команды по разнообразным сценариям (периодический опрос, подписка на websocket-события, https-запросы и т.д.), а также выводить состояние и графики в реальном времени, динамически комбинируя различные источники данных в разных виджетах.</p><p>Кроме того, у панели было предусмотрено несколько настраиваемых режимов работы, которые переключались по запросу пользователя, что требовало массового управления маршрутами потоков данных внутри системы.</p><p>В первой итерации с использованием RxJS получилось много неструктурированного и сложно поддерживаемого кода, так как архитектура на RxJS вынуждала императивно описывать перестроение топологии при изменении правил маршрутизации «на лету». В нашем специфичном кейсе с динамическими виджетами это приводило к сайд-эффектам и сложностям в отладке. Кроме того, местами размывалась строгая типизация и мы лишались compile-time гарантий. Так появилась идея разработать собственное решение на основе альтернативной концепции — модели графа потоков данных.</p><p>В результате получившаяся модель продемонстрировала предсказуемое поведение и низкую связность компонентов, а кодовая база сократилась на ~30% и приобрела более декларативный вид. Убедившись в эффективности решения, мы решили оформить его в виде отдельной библиотеки с открытым исходным кодом — <b>Transferum</b>.</p><h2>И что, получилась просто еще одна реактивная библиотека?</h2><p>Не совсем. Классические FRP-библиотеки (RxJS, Bacon, Most) построены вокруг единственного примитива (Observable<i></i>). Transferum же основан на композиции различных типов узлов с явно определенным поведением.</p><p>Каждый узел в графе потоков распространения данных явно декларирует свои способности: может ли он принимать данные через push, отдавать через pull, распространять полученный сигнал подписчикам, опрашивать источник, фильтровать, блокировать поток и т.д.</p><p>Объявленные узлом возможности являются одновременно <b>флагами для использования в runtime</b> и <b>compile-time гарантиями</b> наличия соответствующих методов, определяющих его поведение.</p><p><b>Ключевая идея:</b> поведение системы описывается как композиция независимых возможностей, которые одновременно определяют тип, реализацию и правила взаимодействия.</p><h2>Transferum предоставляет четыре слоя абстракции:</h2><ol><li>Трансферы — узлы графа (каналы, поллеры, мапперы, буферы, разветвители и концентраторы, реализации debounce, throttle, switchMap и т.д.).</li><li>Мосты — ребра графа — управляемые вентили между узлами с динамической маршрутизацией и гейтингом.</li><li>Операторы — stateless-трансформаторы и фильтры данных (используются трансферами, отвечающими за конвертацию данных).</li><li>Билдеры — fluent-конструкторы композитных трансферов из цепочек трансферов-примитивов.</li></ol><p>Концептуальная и архитектурная основа — <b>capability flags system</b>. Каждый трансфер реализует CommunicationContractInterface<i></i> — набор булевых флагов, определяющих его возможности.</p><p>Флаги isPushable, isPullable, isSubscribable, isGate и другие — это не просто свойства объекта. Это метаданные, которые:</p><ul><li>Определяют TypeScript-интерфейс трансфера на этапе компиляции.</li><li>Управляют стратегией связывания с другими трансферами в рантайме (с помощью функции linkTransfers()).</li><li>Обеспечивают совместимость в билдерах без приведений типов.</li></ul><p>Один набор флагов — три потребителя. Это единый источник истины для всей системы.</p><p>Когда флаг равен true, соответствующий метод входит в TypeScript-интерфейс трансфера. Это позволяет предоставлять трансфер пользователю вот так:</p><p>Или вот так:</p><p>Именно в таком формате типов фабрики в библиотеке возвращают трансферы. Например:</p><p>Эта <i>«магия»</i> работает в compile-time благодаря несколько замысловатой системе вычислимых типов:</p><h2>Архитектурные инварианты</h2><h2>1. Трансферы не знают своих соседей</h2><p>Трансфер определяет своё поведение (push, pull, subscribe и др.), но никогда не ссылается и не проверяет класс другого трансфера. Он не знает, что является upstream или downstream — лишь выполняет свой контракт. Пользователь может создать свой трансфер, объявить и реализовать его возможности — и он органично и бесшовно впишется в экосистему.</p><h2>2. Мосты не знают конкретных реализаций</h2><p>Мост инспектирует capability flags, а не имена классов. Нет цепочки instanceof, нет переключения по имени класса. Любой output-трансфер может быть соединен с любым input-трансфером — при условии совместимости их флагов, о чем мы поговорим чуть ниже. Это применимо и к тем узлам, которые еще не существуют и будут созданы пользователем.</p><h2>3. Значение undefined никогда не распространяется</h2><p>В Transferum undefined означает «нет данных», а не «пустое значение». Оно подавляется на уровне внутренней реализации менеджера подписок — подписчики никогда не уведомляются с undefined. При этом для явных маркеров пустых значений можно использовать null. <i>Мы сознательно пошли на этот компромисс, чтобы избежать runtime-оверхеда и сохранить нативную скорость работы на плотных потоках данных.</i></p><h2>Связывание трансферов</h2><p>Функция linkTransfers(lhs, rhs) соединяет output-трансфер (lhs) с input-трансфером (rhs) с автоматическим выбором стратегии связывания на основе возможностей этих трансферов:</p><ul><li>isSubscribable → isPushable (реактивная подписка);</li><li>isPullable → isPollingProxy (активный опрос);</li><li>isSubscribable → isAsyncPushable (реактивная подписка + асинхронный push);</li><li>isAsyncPullable → isAsyncPollingProxy (активный асинхронный опрос асинхронного pull-источника);</li><li>isPullable → isAsyncPollingProxy (активный асинхронный опрос синхронного pull-источника).</li></ul><p><b>Protocol-oriented design:</b> механизм не спрашивает <b>«какой это класс?»</b> — он выясняет, <b>какие у него есть возможности</b>. Любая пара трансферов с совместимыми возможностями является <b>linkable</b>. Добавление нового класса трансфера требует только объявления его флагов и реализации соответствующих методов — как связать его с другим трансфером, связующий алгоритм разберется сам.</p><h2>Sync и async в одной экосистеме</h2><p>Синхронные и асинхронные трансферы сосуществуют и могут быть связаны между собой. linkTransfers() предпочитает sync-связывание, когда это возможно, а async-стратегии применяет только когда sync неприменим. Нет отдельного «асинхронного мира».</p><h2>Поддержка backpressure</h2><p>Ряд асинхронных трансферов (AsyncSinkTransfer, AsyncWriteTransfer, AsyncConvertTransfer, AsyncConditionTransfer) поддерживают необязательные поля в конфигурации: maxConcurrency, bufferSize и onBufferOverflow — для ограничения параллельных async-операций, очереди избыточных данных и graceful-обработки переполнения. По умолчанию — неограниченная обработка, без буферизации.</p><h2>Локальная обработка ошибок</h2><p>Transferum использует единую модель обработки ошибок для всех трансферов. Каждый трансфер, который может столкнуться с runtime-ошибкой, принимает опциональный onError-хэндлер в своей конфигурации.</p><h2>А теперь — к примерам использования</h2><p>Вот так можно просто и декларативно описать опрос и агрегирование данных из нескольких источников:</p><p>А вот как можно организовать динамический роутинг:</p><p>Пример организации игровой механики:</p><h2>Когда имеет смысл попробовать Transferum</h2><p>Библиотека подойдет для:</p><ul><li>TypeScript-first проектов — благодаря максимально строгой типизации и compile-time вычислению доступных методов любого трансфера на основе объявленных у него флагов возможностей.</li><li>Работы с pull-based источниками данных — polling API, датчиков, хранилищ с PollingProxy.</li><li>Смешанных sync/async пайплайнов — в единой модели без ручного преобразования.</li><li>Явного flow control — gates, bridges, selectors для runtime-маршрутизации.</li><li>Game development / IoT — frame-aligned tickers, idle polling, sensor aggregation.</li><li>Устойчивой обработки ошибок — локальная, non-fatal обработка: одна стадия не убивает пайплайн при условии переданного в конфиге обработчика ошибок, ничего не подавляется молча.</li></ul><h2>Результаты и планы</h2><ul><li>Библиотека уже используется в двух наших внутренних проектах и показывает свою эффективность. Код доступен на GitHub под лицензией MIT, библиотека не имеет внешних зависимостей и поставляется с подробной документацией (README + API Reference).</li><li>В одном из проектов граф состоит из ~80 узлов и стабильно обрабатывает несколько сотен событий в секунду без деградации. На основе этих данных в том числе рендерится 3D-сцена в Babylon.js со стабильным фреймрейтом ~60 FPS без микрофризов.</li><li>Тесты библиотеки покрывают не только отдельные трансферы, но и поведение системы в динамике: переподключение мостов, обработку ошибок в длинных асинхронных цепочках, а также разнообразные граничные случаи. Покрытие — 100%.</li><li>В дальнейшем планируем реализовать хуки и утилиты для более удобного и нативного использования Transferum с Vue и React. Если они окажутся в достаточной мере переиспользуемыми, оформим в отдельные пакеты-адаптеры.</li></ul><p>Буду рад, если вы заглянете в <a href="https://github.com/Smoren/transferum-ts" rel="noopener noreferrer nofollow">репозиторий</a>, попробуете библиотеку в деле и поделитесь замечаниями — обратная связь поможет сделать Transferum лучше.</p><p>P. S. Если вы сталкивались с похожими задачами и решили их как-то иначе — буду рад прочитать о вашем опыте в комментариях.</p>]]></content:encoded>
    </item>
    <item>
      <title>Один фреймворк для Android и iOS: звучит круто, работает?  Нет</title>
      <link>https://tproger.ru/articles/odin-frejmvork-dlya-android-i-ios-zvuchit-kruto-rabotaet-net</link>
      <comments>https://tproger.ru/articles/odin-frejmvork-dlya-android-i-ios-zvuchit-kruto-rabotaet-net?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Роман Новохацкий]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/odin-frejmvork-dlya-android-i-ios-zvuchit-kruto-rabotaet-net</guid>
      <description><![CDATA[<p>Почему единый кроссплатформенный фреймворк для автотестов Android и iOS не работает на практике и когда стоит разделить его на два отдельных проекта.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/odin-frejmvork-dlya-android-i-ios-zvuchit-kruto-rabotaet-net">Один фреймворк для Android и iOS: звучит круто, работает?  Нет</a>»</p>]]></description>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Тестирование]]></category>
      <category><![CDATA[Android]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Распознавание]]></category>
      <category><![CDATA[iOS]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Swift]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[GitLab]]></category>
      <category><![CDATA[Kotlin]]></category>
      <category><![CDATA[Финтех]]></category>
      <category><![CDATA[QA]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Инфраструктура]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 23 Jul 2026 13:20:45 GMT</pubDate>
      <content:encoded><![CDATA[<p>Я сделал автотесты на Appium для Android и iOS в одном проекте. Один репозиторий, общий фреймворк, общие Page Objects, общие steps. Красота.</p><p>Потом проект вырос, в команду пришли ещё люди, и стало понятно: этот красивый монолит пора разделять.</p><p>Это было взвешенное решение. В какой-то момент общий фреймворк превратился в поле мерж-конфликтов, где ты уже не тесты пишешь, а разбираешься, кто чей page object сломал и почему Android отвалился после правки для iOS.</p><p>Appium тут ни при чём, как и скорость тестов. Проблема была в архитектуре: один общий слой для двух разных платформ начал мешать сильнее, чем помогать.</p><p>Как говорил один мой коллега, перефразируя классическое “вам шашечки или ехать”:</p><blockquote>Ты сюда страдать пришёл или тесты писать?</blockquote><p>После этого решение разделить Android и iOS на два проекта стало очевидным.</p><p>Сейчас у меня два отдельных проекта: mb-android-tests и mb-ios-tests. И знаете что? Это лучшее архитектурное решение за всё время на этом проекте. Серьёзно.</p><p><b>Контекст: что за проект и почему это важно</b></p><p>Финтех. Нативное приложение. Отдельные кодовые базы, Kotlin на Android, Swift на iOS. И UI там не «три кнопки и список», формы с десятками полей, кастомные контролы, WebView-вставки, платежи, валютные операции, бюджетные переводы. Ну вы поняли.</p><p>Стек: Java 21, TestNG, Appium 2.x, Selenide, Allure, Maven. CI на GitLab, крутится на Mac Mini. 5 Android-эмуляторов, 4 iOS-симулятора, 9 Appium-серверов — по одному на устройство.</p><p>Но это сейчас. А начиналось всё с одного жирного монолита.</p><p><b>Старый проект: 8 модулей и конструктор-монстр</b></p><figure><img src="https://media.tproger.ru/user-uploads/139426/2026-07-07/54be52bb-7e50-4e11-b624-86cc1ce0766b.webp" alt="" /></figure><p>Идея была «как в книжке»: один репозиторий, модульная структура, переиспользование. DRY во все поля. Ну а чё, красиво же.</p><p>8 модулей. Один mvn clean install. Все зависят от mobile-automation-framework, в котором живут DriverFactory, BaseTest, общие Page Objects и слой Steps.</p><p>А DriverFactory принимал <b>11 параметров</b>. Одиннадцать, Карл.</p><p>Половина нужна только Android, другая только iOS. Но метод один. Потому что так более по программистцки, как написано в каждой второй статье про архитектуру автотестов.</p><p>Когда я работал один, было норм. Ты сам знаешь, от куда что идет.</p><p>А потом пришли люди.</p><p><b>Почему с людьми всё навернулось</b></p><p><b>Мерж-конфликты каждый божий день</b></p><p>Вот конкретная ситуация. Один человек правит LoginPage в общем фреймворке, добавляет метод для iOS, меняет локатор. Второй в тот же момент рефакторит этот же LoginPage под новую версию Android-приложения.</p><p>Мерж. Конфликт.</p><p>И тут начинается самое весёлое: какой локатор правильный? Для Android? Для iOS? Для обоих? Кто будет разбираться? Тот, кто мёрджит? А он вообще контекст понимает?</p><p>Это не единичный случай. Это было <b>каждый</b> день. Потому что mobile-automation-framework получился общим модулем, от которого зависят все. И все туда лезут. Постоянно.</p><figure><img src="https://media.tproger.ru/user-uploads/139426/2026-07-07/3866002d-86c5-4894-a441-2522f48dcab1.webp" alt="" /></figure><p><b>Обновление одной библиотеки = блокировка всех</b></p><p>Решил обновить java-client с 7.x на 8.x. Нормальное желание — API поменялся, MobileElement удалили, capabilities переехали на типизированные Options.</p><p>Вот что произошло в реальности:</p><ol><li>Меняю версию в parent pom.xml</li><li>MobileElement удалён → compilation error в DriverFactory, во всех DriverManager’ах</li><li>DesiredCapabilities → UiAutomator2Options / XCUITestOptions → переписываю все менеджеры</li><li>selenide-appium 1.x несовместим с java-client 8.x → обновляю до 2.x</li><li>selenide-appium 2.x требует Selenide 6.x → обновляю Selenide</li><li>Selenide 6.x ломает API page objects → переписываю page objects во всех модулях</li><li>А Selenide 6.x ещё и Java 8 не поддерживает → обновляю Java</li></ol><p>Одна библиотека.</p><p>Задача «обновить одну библиотеку» превратилась в 50+ файлов, 4-5 каскадных обновлений, 2-3 недели работы. И всё это время develop нестабилен. Все заблокированы. Тесты не запускаются.</p><p>Две недели.</p><p>Из-за одной строчки в pom.xml.</p><p><b>Page Objects с if/else — это два page object в одном файле</b></p><p>Общие Page Objects звучат красиво на бумаге: пишем один раз, используем для обеих платформ. А на практике…</p><p>Это не page object. Это два page objects, запиханных в один файл через if/else. И так в каждом методе.</p><p>А сверху ещё слой Steps. Обёртки над page objects «для читаемости». И в steps тоже if (platform), потому что логика взаимодействия разная. На Android ты скроллишь через UiScrollable семантически, «прокрути до элемента с текстом X». На iOS координатами, «двигай палец из точки A в точку B». Один метод в steps, а внутри два разных мира.</p><p>В какой-то момент ловишь себя на мысли: я же не тесты пишу. Я подгоняю pages и steps под две платформы, чтобы фреймворк не развалился. Это уже не автоматизация тестирования, это поддержка фреймворка ради поддержки фреймворка.</p><p><b>Каждый работает в своём темпе и все друг другу мешают</b></p><p>У одного задача покрыть тестами новый экран на Android. У второго пофиксить падающие тесты на iOS. У третьего добавить тестовые данные.</p><p>Все трое лезут в mobile-automation-framework. Все трое меняют pom.xml, BaseTest, page objects. Каждый в своей ветке.</p><p>А потом мёрдж.</p><p><b>Технические причины, которые добили окончательно</b></p><p>Ладно, человеческий фактор. Но были и чисто технические штуки, которые окончательно убедили меня, что кроссплатформа тут бессмысленна.</p><p><b>Локаторы: работай с тем, что дают</b></p><p>Сразу скажу то, о чём мало кто пишет в статьях: в мобильной автоматизации ты работаешь с тем, что дают, а не с тем, что хотелось бы.</p><p>В теории есть AccessibilityID единый локатор для обеих платформ. Звучит хорошо. А на практике? Попробуй попросить мобильных разработчиков расставить одинаковые accessibility-идентификаторы на сотнях экранов. На Kotlin и Swift. Одновременно. Они тебя вежливо пошлют, но скорее всего не вежливо. И будут правы, у них свои спринты, свои дедлайны, и твои автотесты в их приоритетах где-то между «поправить тень у кнопки» и «никогда».</p><p>Так что реальный выбор:</p><p><b>XPath -</b> работает, но на iOS может быть тормозным. На Android через UiSelector быстро, нативно, надёжно. На iOS через NSPredicate тоже ок. А «универсальные» XPath типа //*[@text='Войти' or @label='Войти']  это путь к боли, потому что Page Source на двух платформах два совершенно разных XML-дерева.</p><p><b>Координаты -</b> костыль? Да. Но иногда единственный вариант. Когда у тебя кастомный контрол без accessibility-свойств, а разработчик говорит «это декоративный элемент», ты либо тыкаешь по координатам, либо не тестируешь.</p><p><b>OpenCV</b> - есть ещё вариант с распознаванием элементов по картинке. Для некоторых кейсов реально выручает. Но это отдельная тема на целую статью, может напишу потом.</p><p>Суть в том, что «напиши один локатор и работай на двух платформах» это миф. Page Source на Android это android.widget.Button с resource-id. На iOS  XCUIElementTypeButton с name и label. Разные типы элементов, разные атрибуты, разная глубина вложенности. Разные миры.</p><p><b>StaleElementReferenceException — «подарок» от iOS</b></p><p>Android рендерит UI через Choreographer синхронно с VSYNC. Элемент появился → стабилен → кликаем.</p><p>iOS рендерит через CoreAnimation с неявными анимациями. Элемент есть в дереве, но ещё анимируется. Формально кликабелен, фактически хрен.</p><p>Стандартный WebDriverWait с elementToBeClickable это не ловит. Элемент «кликабелен» по мнению Appium wait завершается. А потом click() падает, потому что DOM изменился между вызовами.</p><p>На Android этой проблемы нет вообще. Тот же тест, тот же wait, тот же код зелёный на Android, красный на iOS. Один и тот же метод, два разных результата. И это не баг это фундаментальное различие платформ.</p><p>Кастомные wait-стратегии для iOS отличаются от Android принципиально. Пихать их в один фреймворк строить leaky abstraction, которая протекает на каждом шаге.</p><p><b>Жесты — два разных мира</b></p><p>Свайп вниз на Android:</p><p>Свайп вниз на iOS:</p><p>Чувствуете разницу? И даже длительность свайпа важна: на Android 200мс это нормальный скролл. На iOS 200мс это fling, и элемент улетает за экран.</p><p>«Кроссплатформенная» обёртка для скролла функция на 40 строк с двумя ветками if (platform), внутри каждой и ещё if для performSwipeDown() vs performSwipeUp(). На 50+ экранах таких обёрток, которых десятки.</p><p>И каждая место для бага.</p><p><b>Решение: разделяй и властвуй</b></p><p>Решение было болезненным. Я реально откладывал, потому что казалось, что это шаг назад. Дублирование кода, нарушение DRY, всё такое. Мозг сопротивлялся.</p><p>А потом я просто сел и разделил.</p><p>Никаких общих page objects. Никаких общих steps. Никакого общего DriverFactory с 11 параметрами. Каждый проект со своим pom.xml, свои зависимости, свой BaseTest, свои локаторы.</p><p>Что осталось общего: подход к структуре (Maven + TestNG + Allure), CI-шаблоны, принципы организации. Но не код. Код полностью раздельный.</p><p><b>Что поменялось на практике</b></p><p>В Android-проекте DriverManager типизирован под AndroidDriver. В iOS под IOSDriver. Не AppiumDriver&lt;MobileElement&gt; с кастами и проверками, а конкретный тип для конкретной платформы. IDE подсказывает только релевантные методы. Компилятор ловит ошибки на этапе сборки, а не в рантайме.</p><p>BaseTest принимает ровно те параметры, которые нужны. Android: deviceName, platformVersion, udid, appPackage, appActivity, systemPort, serverUrl, appPath — 8 штук, все релевантные. iOS: deviceName, platformVersion, udid, appPath, serverUrl, wdaLocalPort — 6. Никаких @Optional("systemPort") со строкой “systemPort” в качестве дефолта.</p><p><b>А мерж-конфликты?</b></p><p>Когда один человек работает в mb-android-tests, а второй в mb-ios-tests то они <b>вообще</b> не пересекаются. Разные репозитории. Конфликт невозможен физически.</p><p>Обновление java-client в Android-проекте не затрагивает iOS. Хочешь обновить, обновляй. iOS продолжает работать на старой версии.</p><p>Добавить новый параметр для iOS? Меняешь BaseTest и testng.xml в iOS-проекте. Android даже не узнает.</p><p>Это прям кайф.</p><p><b>А как же дублирование кода?!</b></p><p>Конечно, конечно. Первый вопрос, который задают: «Но ведь ты пишешь тесты дважды!»</p><p>Нет.</p><p>Я пишу каждый тест один раз и без костылей. Без if (platform) в каждом методе. Да, для одного и того же экрана есть два теста, один для Android, один для iOS. Но каждый из них чистый, понятный, заточенный под свою платформу.</p><p>В старом варианте я тоже «писал один раз», а потом тратил столько же времени на поддержку if/else, мерж-конфликты и каскадные обновления. «Экономия» на создании оборачивалась переплатой на поддержке. С процентами.</p><p><b>Когда кроссплатформа всё-таки ок</b></p><p>Я не топлю за то, что кроссплатформенный фреймворк абсолютное зло. Есть ситуации, где он работает:</p><p>Приложение простое, пара экранов, стандартные контролы, минимум кастомного UI.</p><p>UI реально идентичен на обеих платформах. Бывает, наверное.</p><p>Команда из одиного человека. Сам пишешь, сам мёрджишь, сам разруливаешь. Голова справляется.</p><p>Минимум жестов. Нет сложных свайпов, drag-and-drop, pinch-to-zoom.</p><p>Если у тебя финтех, банк, enterprise-приложение с сотнями экранов, кастомными контролами и тремя+ QA, то два проекта дешевле. Не в строках кода, а во времени. В нервах. В часах, потраченных на мерж-конфликты вместо написания тестов.</p><p><b>Итого</b></p><p>Два проекта это не шаг назад и не двойная работа. Со стороны может выглядеть именно так, но на практике ты пишешь каждый тест один раз, под конкретную платформу, без лишних компромиссов. Потом поддерживаешь его без постоянных мерж конфликтов, каскадных обновлений и if/else в каждом втором методе.</p><p>Кроссплатформенный фреймворк на Appium для сложного нативного приложения часто оказывается иллюзией экономии.</p><p>В следующей статье покажу, как у нас устроена инфраструктура для 9 параллельных устройств на одном Mac Mini: порты, bash скрипты, Appium серверы и workaround’ы, которых нет в документации. Спойлер: там тоже всё не совсем как в гайдах.</p>]]></content:encoded>
    </item>
    <item>
      <title>itertools в Python: ленивые итераторы без лишних циклов</title>
      <link>https://tproger.ru/articles/itertools-v-python-lenivye-iteratory-bez-liwnih-ciklov</link>
      <comments>https://tproger.ru/articles/itertools-v-python-lenivye-iteratory-bez-liwnih-ciklov?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/itertools-v-python-lenivye-iteratory-bez-liwnih-ciklov</guid>
      <description><![CDATA[<p>Разбираем модуль itertools из стандартной библиотеки Python: как ленивые итераторы экономят память, какие функции использовать чаще всего и где поджидают подводные камни.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/itertools-v-python-lenivye-iteratory-bez-liwnih-ciklov">itertools в Python: ленивые итераторы без лишних циклов</a>»</p>]]></description>
      <category><![CDATA[Алгоритмы и структуры данных]]></category>
      <category><![CDATA[Функциональное программирование]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Практика]]></category>
      <category><![CDATA[Для продолжающих]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 12 Jul 2026 17:20:36 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если ваш код регулярно превращается в пять вложенных for и огромный список, который держится в памяти только ради того, чтобы тут же быть выброшенным в мусор, — скорее всего, вам не хватает itertools. Этот модуль стандартной библиотеки Python собрал ленивые итераторы, которые превращают обработку данных в конвейер: элементы поступают, преобразуются и уходят дальше без лишних промежуточных коллекций.</p><p>itertools — это не просто набор функций, а способ мыслить о данных как о потоке. Вместо того чтобы сначала строить список, а потом его перебирать, вы описываете, что должно произойти с каждым элементом, и получаете результат по мере необходимости. В статье разберём три семейства инструментов, покажем рабочие примеры и укажем на типичные ловушки.</p><p>itertools — модуль стандартной библиотеки Python, который предоставляет ленивые итераторы для композиции цепочек обработки данных.</p><p>Ленивость означает, что элементы создаются по запросу, поэтому можно работать с большими файлами и бесконечными потоками, не загружая всё в память.</p><p>Функции разделены на три группы: бесконечные итераторы (count, cycle, repeat), конечные итераторы (chain, islice, groupby и др.) и комбинаторные (product, permutations, combinations).</p><p>Многие рутинные задачи — flatten, батчинг, скользящее окно, группировка — решаются в одну строку, если знать правильную комбинацию функций.</p><p>Подводные камни: groupby требует предварительной сортировки по тому же ключу; итераторы одноразовые; tee() может неэкономно расходовать память.</p><h2>Зачем вообще ленивые итераторы?</h2><p>Обычный подход в Python — сгенерировать список и пройтись по нему циклом. Это просто и читаемо, пока данных немного. Когда файл весит несколько гигабайт, а строки приходят из сети, список становится дорогим: он требует памяти и времени, хотя в каждый момент вам нужен лишь один текущий элемент.</p><p>Ленивый итератор не строит коллекцию целиком. Он помнит текущее состояние и умеет «добыть» следующий элемент. Поэтому itertools работает с любыми итерируемыми источниками — файлами, генераторами, сетевыми потоками — и не требует, чтобы весь объём данных поместился в оперативную память.</p><p><b>Память vs скорость:</b><br />Ленивость экономит память, но не всегда ускоряет код. Если данные всё равно нужны целиком — например, для сортировки — список может оказаться быстрее. Используйте итераторы там, где важна потоковая обработка.</p><h2>Три семейства инструментов</h2><p>Документация Python делит функции модуля на три группы. Такое разделение помогает быстро выбрать инструмент: нужна бесконечная последовательность, преобразование конечной или перебор комбинаций.</p><h3>Бесконечные итераторы: count, cycle, repeat</h3><p>count — это range без конца. Ему можно задать начальное значение и шаг, и он будет выдавать числа до тех пор, пока его не остановят снаружи. cycle бесконечно повторяет переданную последовательность, а repeat — бесконечно или заданное число раз возвращает один объект.</p><p>Классический трюк — сочетание map и count: map(f, count()) работает как математическое табулирование tabulate(f), знакомое из SML и Haskell.</p><h3>Конечные итераторы: chain, islice, groupby и другие</h3><p>Это самая многолюдная группа. Здесь есть функции для склейки последовательностей, фильтрации, нарезки, группировки и пакетной обработки. Их объединяет одно: на вход подаётся конечный или контролируемый итератор, на выходе — тоже итератор.</p><p>batched появился в Python 3.12 и сразу стал незаменимым инструментом: партии запросов к API, пакеты строк для вставки в базу, страницы данных. Последняя партия может быть короче — это поведение по умолчанию.</p><p>groupby часто путают с SQL-аналогом, но это не тот же инструмент. Python-версия группирует только подряд идущие одинаковые ключи, поэтому перед ней обычно нужна сортировка по тому же ключу. Если забыть про это, результат покажется случайным.</p><h3>Комбинаторные итераторы: product, permutations, combinations</h3><p>Эти функции генерируют декартово произведение, перестановки и сочетания. Они незаменимы в тестировании, алгоритмах на графах, задачах оптимизации и даже в простых играх. Все они ленивые, поэтому можно перебирать комбинации по одной, не строя гигантский список.</p><p>product с аргументом repeat удобен для перебора многомерных конфигураций: product([0, 1], repeat=3) даст все двоичные triples, как в таблице истинности.</p><h2>Подводные камни, за которые хватаются новички</h2><p>Несмотря на простоту отдельных функций, у модуля есть несколько особенностей, которые легко превратить в баг.</p><ul><li>groupby работает только с подряд идущими одинаковыми ключами. Перед вызовом сортируйте данные по тому же ключу, иначе группы разобьются.</li><li>Итераторы одноразовые. После list(iterator) исходный итератор опустошён, и второй проход по нему даст пустой результат.</li><li>tee копирует данные во внутренний буфер, пока все производные итераторы не прочитают их. Если один итератор сильно отстаёт, память может расти не хуже списка.</li><li>zip_longest с бесконечным итератором никогда не остановится. Ограничивайте такие комбинации islice или takewhile.</li><li>product полностью потребляет входные итераторы, чтобы построить пулы значений. С бесконечными последовательностями его использовать нельзя.</li></ul><h2>Рецепты: от простого к составному</h2><p>Документация Python включает раздел рецептов — готовые комбинации функций, которые решают частые задачи. Некоторые из них настолько удобны, что со временем превращаются в полноценные функции модуля: так появились accumulate, compress и pairwise.</p><p>Для sliding_window сейчас часто используют рецепт из документации или аналог из more-itertools, где функция уже реализована и хорошо протестирована.</p><h2>Выводы</h2><p>itertools — это не библиотека для красивых однострочников, а инструмент для правильного мышления о данных. Он помогает отказаться от лишних промежуточных списков, писать компактные конвейеры и работать с потоками, которые не помещаются в память. Главное — не гнаться за краткостью любой ценой: иногда явный цикл понятнее, чем цепочка из пяти функций.</p><blockquote>Together, they form an iterator algebra making it possible to construct specialized tools succinctly and efficiently in pure Python.</blockquote><p>Источник: <a href="https://docs.python.org/3/library/itertools.html">itertools — Functions creating iterators for efficient looping</a>. Если в вашем коде до сих пор царят вложенные циклы и огромные списки — попробуйте заменить их на поток. Скорее всего, получится короче, быстрее и понятнее.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как приручить legacy-код: безопасная модернизация без заморозки фич</title>
      <link>https://tproger.ru/articles/kak-priruchit-legacy-kod-bezopasnaya-modernizaciya-bez-zamorozki</link>
      <comments>https://tproger.ru/articles/kak-priruchit-legacy-kod-bezopasnaya-modernizaciya-bez-zamorozki?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[KODE]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-priruchit-legacy-kod-bezopasnaya-modernizaciya-bez-zamorozki</guid>
      <description><![CDATA[<p>Как модернизировать legacy-код без остановки продукта: Strangler Fig Pattern, feature flags, shadow testing и безопасная миграция данных. Практика и антипаттерны.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-priruchit-legacy-kod-bezopasnaya-modernizaciya-bez-zamorozki">Как приручить legacy-код: безопасная модернизация без заморозки фич</a>»</p>]]></description>
      <category><![CDATA[Интернет]]></category>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Опрос]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Ruby]]></category>
      <category><![CDATA[MySQL]]></category>
      <category><![CDATA[Практика]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Рефакторинг]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Tor]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[MIT]]></category>
      <category><![CDATA[Финтех]]></category>
      <category><![CDATA[ICO]]></category>
      <category><![CDATA[Redis]]></category>
      <category><![CDATA[QA]]></category>
      <category><![CDATA[Бэкенд]]></category>
      <category><![CDATA[Twitter]]></category>
      <category><![CDATA[Игра]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Kubernetes]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[аналитик]]></category>
      <category><![CDATA[OpenTelemetry]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[DeFi]]></category>
      <category><![CDATA[Grafana]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Legacy]]></category>
      <category><![CDATA[Техника]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 23 Jun 2026 06:16:57 GMT</pubDate>
      <content:encoded><![CDATA[<p>Legacy-код — одна из самых болезненных тем в инженерных командах. Обычно все понимают, что система устарела: архитектура мешает быстро выпускать изменения, новые фичи приходится встраивать через обходные пути, тесты либо неполные, либо отсутствуют, а любое изменение в одном модуле неожиданно ломает другой.</p><p>Но при этом к такому коду часто боятся прикасаться. И не без причины. В старых системах редко бывает понятная карта зависимостей. Документация устарела, часть знаний живет только в головах нескольких разработчиков, а бизнес при этом продолжает ждать новых релизов, интеграций и продуктовых экспериментов.</p><p>Так появляется классическая ловушка legacy: систему надо модернизировать, но остановить развитие нельзя. Переписать всё с нуля страшно, поддерживать как есть — всё дороже. В результате продукт обрастает временными решениями, скорость разработки падает, а стоимость каждого следующего изменения растет.</p><p>Хорошая новость в том, что модернизация legacy-кода не обязана быть большим взрывом. Старую систему можно менять постепенно, сохраняя рабочий продукт, не замораживая фичи и не устраивая один критический релиз, от которого зависит всё.</p><h2>Почему Big Bang-переписывание чаще всего заканчивается плохо</h2><p>Когда команда долго живет с устаревшей системой, идея переписать всё с нуля выглядит очень соблазнительно. Кажется, что можно наконец избавиться от технического долга, выбрать нормальную архитектуру, перепроектировать модули, покрыть всё тестами и начать «правильно».</p><p>На старте такой план часто звучит логично. Особенно если текущая система действительно мешает развитию. Например, мобильное приложение растет, у него уже миллионы пользователей, бэкенд написан несколько лет назад как монолит, а каждая новая фича требует изменений в десятке мест. Команда устала чинить регрессии, бизнес устал ждать, и всем хочется «один раз нормально переписать».</p><p>Проблема не в самой идее переписывания, а в условиях, при которых оно проваливается. Большой риск возникает, когда совпадают четыре фактора: переписывание занимает много месяцев, в это время бизнес продолжает развивать старую систему, новая версия покрывает сразу большую часть функциональности, а откат связан с миграцией данных. Если все четыре пункта присутствуют, Big Bang почти гарантированно превратится в долгий и дорогой проект.</p><p>Допустим, команда решила переписать модуль заказов в e-commerce-продукте. В старой версии есть корзина, промокоды, доставка и оплата. Команда планирует за полгода сделать новый сервис заказов. Но за эти полгода бизнес добавляет подписки, подарочные сертификаты, частичную оплату бонусами и новую логику возвратов. В итоге новая система, которую проектировали под старые требования, к моменту релиза уже нуждается в доработке.</p><p>Есть и другая проблема: большой релиз почти всегда несет максимальный риск. Если вы заменяете крупный кусок системы целиком, ошибка влияет сразу на большую часть пользователей. Откат тоже становится сложным, потому что новая логика уже связана с новыми данными, контрактами и интеграциями.</p><p>Big Bang всё-таки бывает оправдан — но в узких условиях. Если кодовая база молодая (год-два), пользователей мало, у системы нет критичного состояния в БД и продукт можно временно заморозить или вести в обоих контурах параллельно, полное переписывание может оказаться дешевле постепенной миграции. Это редкая ситуация, и она быстро исчезает по мере роста продукта. В зрелых системах безопаснее работает другой подход — постепенная архитектурная эволюция.</p><h2>Пример: как команда переписала сервис документов и потеряла полгода</h2><p>Команда сопровождала сервис — старый модуль на aiohttp с Pydantic v1, через который проходила вся обработка путевых листов и актов осмотра транспорта. Сервис существовал шесть лет, был покрыт тестами фрагментарно, а его API использовали мобильное приложение водителей, диспетчерская веб-панель и пакетный импорт.</p><p>Команда решила переписать сервис целиком: перейти на FastAPI, обновить Pydantic до v2, заодно почистить контракты и заменить внутреннее хранилище документов с MongoDB на PostgreSQL. План был рассчитан на четыре месяца.</p><p>Через восемь месяцев проект всё ещё не был готов к выкатке, а к десятому месяцу команда откатила миграцию полностью. Причин было несколько.</p><p>Во-первых, переписывание шло параллельно с продуктовой разработкой. За время миграции бизнес добавил два новых типа документов и изменил правила подписи актов. Новая система проектировалась под старые требования и к моменту готовности уже не соответствовала продукту.</p><p>Во-вторых, команда не написала характеристических тестов. Поведение «как есть» нигде не было зафиксировано, и расхождения находились только в продакшене после переключения.</p><p>В-третьих, у старого сервиса были скрытые побочные эффекты, о которых никто не помнил. При смене статуса документа публиковал событие в Kafka, которое читал биллинг и сервис аналитики. В новой реализации это поведение не было воспроизведено, потому что в коде оно выглядело как «лишний» вызов. После переключения биллинг перестал получать события, и расхождение обнаружили только через две недели — по жалобе финансового отдела.</p><p>В-четвёртых, переключение было сделано «в лоб»: маршрут в API Gateway просто перенаправили на новый сервис. Фича-флага не было, теневого запуска не было, плана отката не было. Когда выяснилось, что новый сервис строже валидирует исторические форматы документов и отклоняет часть старых записей, быстро вернуться на старую реализацию не получилось — её к тому моменту уже отключили на стенде, а в БД успели уйти записи в новом формате.</p><p>В итоге миграцию свернули, потратив около десяти человеко-месяцев и потеряв доверие бизнеса. Сервис до сих пор работает в исходной реализации, а команда переходит к плану, описанному ниже.</p><h2>Strangler Fig Pattern: как заменить систему по частям</h2><p>Один из самых практичных подходов к модернизации legacy-кода — Strangler Fig Pattern. В софтверном виде паттерн был сформулирован Мартином Фаулером в 2004 году под названием StranglerFigApplication. Идея проста: не переписывать систему целиком, а постепенно выносить отдельные части в новую реализацию.</p><p>Название пришло из биологии. Фикус-душитель растет вокруг дерева-хозяина и постепенно вытесняет его. В архитектуре принцип похожий: старая система продолжает работать, новая функциональность появляется рядом, а затем отдельные потоки постепенно переводятся на новую реализацию.</p><p>Представим старый монолит интернет-магазина. Внутри него есть каталог, корзина, заказы, платежи, скидки, личный кабинет и уведомления. Переписать всё сразу — рискованно. Но можно начать с относительно изолированного участка, например с уведомлений.</p><p>Сначала команда описывает текущий контракт: какие события приходят в модуль уведомлений, какие каналы используются, какие шаблоны отправляются, какие ошибки считаются допустимыми. Затем рядом создается новый сервис уведомлений, который реализует тот же контракт. На первом этапе он может даже не отправлять реальные сообщения, а только принимать события и логировать результат. После проверки часть трафика переводится на новую реализацию. Когда сервис стабилизируется, старый код уведомлений удаляется из монолита.</p><p>Strangler Fig хорошо работает там, где между старым и новым кодом есть сетевая граница: HTTP, message bus, RPC. Если такой границы нет — например, нужно постепенно заменить функцию или класс внутри одного процесса — используется родственный паттерн Branch by Abstraction: над старой реализацией создается абстракция, рядом пишется новая реализация, переключение происходит через конфигурацию или фича-флаг, после стабилизации старая ветка удаляется. Снаружи это выглядит как Strangler Fig, но без сетевого прокси.</p><p>Такой подход снижает риск. В системе нет одного большого релиза, где всё меняется сразу. Есть серия небольших контролируемых изменений. Каждое можно протестировать, измерить и откатить.</p><h2>Главное правило: сначала повторить поведение, потом улучшать</h2><p>Одна из частых ошибок при модернизации legacy-кода — попытка одновременно переписать систему и улучшить бизнес-логику. Команда смотрит на старый модуль и думает: «Раз уж мы его трогаем, давайте сразу сделаем нормальную архитектуру, изменим контракты, уберем странные кейсы и перепишем поведение».</p><p>Это опасный путь. В legacy-системах странное поведение часто существует не случайно. За ним может стоять неочевидное бизнес-правило, старый клиент, интеграция с внешней системой или исторический баг, на который уже кто-то завязался.</p><p>Например, в системе расчета налогов может быть правило: для контрактов, заключенных до 2018 года, НДС округляется в меньшую сторону до целого рубля, а для всех остальных — по математическим правилам. Новый разработчик может решить, что это ошибка, и «исправить» округление. Но потом выяснится, что часть крупных клиентов держит это поведение в своих сверках, а смена правила приведет к расхождениям в актах и претензиям.</p><p>Прежде чем менять поведение, его нужно зафиксировать. Для этого пишут характеристические тесты (characterization tests, иногда называемые golden master или approval tests). Идея простая: на реальных данных или их обезличенных копиях прогоняется старая реализация, её ответы сохраняются как эталон, и любые будущие изменения, отклоняющиеся от эталона, отлавливаются автоматически. Тесты пишутся не для красоты, а для того, чтобы зафиксировать существующее поведение — даже странное — перед тем, как его трогать. Подробно эта техника описана у Майкла Физерса в книге Working Effectively with Legacy Code; на практике её удобно реализовать через библиотеки семейства approval-tests (approvaltests-python, approvaltests-java и аналоги).</p><p>Поэтому первый этап модернизации — не улучшение, а воспроизведение текущего поведения. Новая реализация должна вести себя так же, как старая. Даже если старое поведение кажется странным. Только после стабилизации можно отдельно обсуждать, что именно стоит менять.</p><h2>Feature toggles: как включать новую логику без риска</h2><p>Feature toggles, или фича-флаги, — один из главных инструментов безопасной миграции. Они позволяют включать и выключать новую логику без деплоя.</p><p>В обычной разработке релиз часто выглядит бинарно: код либо выкатили, либо нет. При миграции legacy это неудобно. Гораздо безопаснее иметь возможность включить новую реализацию для 1% пользователей, затем для 10%, потом для половины аудитории и только после этого для всех.</p><p>Например, команда переносит расчет стоимости доставки из монолита в новый сервис. С помощью фича-флага это выглядит так:</p><p>user_id передается явно, чтобы решение «попал ли пользователь в новый сегмент» было стабильным от запроса к запросу. Иначе один и тот же клиент будет получать разные ответы при обновлении страницы, и поведение системы станет непредсказуемым.</p><p>На первом этапе флаг включают только для внутренней команды. Потом для тестового сегмента пользователей. Затем для небольшой доли реального трафика. Если метрики стабильны, долю увеличивают. Если появляются ошибки, флаг выключают, и пользователи снова идут в старую реализацию.</p><p>Важно различать два разных типа флагов. Флаг постепенной выкатки (rollout flag) меняется редко и контролирует, какой процент пользователей видит новую логику. Kill switch — отдельный флаг, единственная задача которого — мгновенно выключить новую реализацию при инциденте. Kill switch должен опрашиваться на каждом запросе, его кэширование должно жить секунды, а не минуты, и он принципиально не должен зависеть от той системы, которую он выключает. Иначе в момент аварии может оказаться, что выключатель сам недоступен.</p><p>В качестве инфраструктуры для флагов команды обычно берут одну из платформ: LaunchDarkly, Unleash, Flagsmith, GrowthBook, либо собирают собственную поверх Redis или конфигурационного сервиса. Для миграции важны три свойства: быстрое распространение изменений (секунды, а не минуты), поддержка таргетинга по пользователю/сегменту и аудит — кто и когда менял флаг.</p><p>Важно, что фича-флаг — это не просто if в коде. Для серьезной миграции нужны правила: кто может включать флаг, как быстро его можно отключить, какие метрики отслеживаются, когда флаг должен быть удален.</p><p>Последний пункт особенно важен. Если флаги не удалять, система быстро превращается в набор ветвлений, где никто уже не понимает, какая логика актуальна.</p><h2>Shadow testing: как проверить новую систему на реальном трафике</h2><p>Feature toggles помогают безопасно переключать пользователей. Но перед этим хорошо бы понять, совпадает ли новая логика со старой. Для этого используют shadow testing.</p><p>Shadow testing — это запуск новой реализации параллельно старой, но без влияния на пользователя. Пользовательский запрос по-прежнему обрабатывает старая система, а новая получает копию запроса и считает результат «в тени». Пользователю этот результат не показывается. Команда только сравнивает ответы.</p><p>Например, есть старый модуль расчета скидок. Он учитывает промокоды, сегмент пользователя, историю покупок, регион и партнерские условия. Команда пишет новый сервис скидок. Чтобы не переключать пользователей сразу, можно запустить теневой режим:</p><p>Два момента, на которые стоит обратить внимание в этом коде. Теневой вызов запускается через asyncio.create_task — корутина сразу планируется в event loop и начнёт выполняться, как только функция вернёт управление. И весь блок завернут в try/except: исключение в новой логике не должно ронять основной запрос. Без этих двух свойств shadow testing рискует ухудшить продакшен вместо того, чтобы безопасно его проверить.</p><p>Небольшая оговорка для продакшена: event loop держит на task только слабую ссылку, и без сохранённой ссылки задача может быть собрана сборщиком мусора прямо во время выполнения. В реальном коде Task имеет смысл класть в set фоновых задач и удалять оттуда через add_done_callback. В примере выше эта обвязка опущена для читаемости.</p><p>Для критичной доменной логики — платежей, биллинга, расчета тарифов — допустимый уровень расхождения должен быть около нуля: цель в shadow-режиме не «как можно меньше различий», а «понимаем каждое расхождение». Для менее чувствительных доменов (рекомендации, ранжирование результатов поиска) можно жить с расхождением в долях процента, но и там расхождения нужно классифицировать, а не игнорировать. Возможно, это баги новой реализации. А возможно, старая система содержит устаревшую логику, которую нужно отдельно обсудить с бизнесом.</p><p>Shadow testing особенно полезен для критичных доменных частей: платежей, биллинга, расчета тарифов, персональных предложений, транзакций. Там нельзя просто «попробовать на пользователях» и посмотреть, что будет.</p><p>При этом важно отличать теневую проверку чтения от теневой проверки записи. Чтение проверить относительно дёшево: запрос идёт в обе системы, ответы сравниваются, никаких внешних эффектов нет. С записью всё сложнее. Если новая реализация в shadow-режиме действительно создаст заказ, спишет деньги или отправит письмо, у пользователя возникнут двойные эффекты. Поэтому для writes либо вводят идемпотентные ключи и shadow-режим без реальных побочных действий (внешние вызовы заменены no-op-стабами, БД — отдельной shadow-копией), либо вообще отказываются от теневой проверки записи в пользу постепенной выкатки за фича-флагом.</p><p>Сравнение ответов в реальной системе тоже не сводится к одной функции compare. Нужно отдельно решать, как игнорировать «нормальный» шум (метки времени, идентификаторы, порядок коллекций), как сэмплировать трафик, чтобы не утопить хранилище расхождений, и как организовать триаж — кто и в каком ритме разбирает накопившиеся диффы. Готовые решения этого класса — GitHub Scientist (Ruby и его порты в другие языки), Twitter Diffy, либо собственный лёгкий регистратор поверх Kafka и таблицы расхождений.</p><h2>С чего начинать модернизацию</h2><p>Начинать лучше не с самого больного и не с самого центрального модуля. Это звучит контринтуитивно, потому что обычно хочется сразу взяться за главный источник проблем. Но если начать с ядра системы, команда быстро упрется в максимальное количество зависимостей и рисков.</p><p>Удобный способ выбрать первый кусок — оценить кандидатов по двум осям: насколько модуль критичен для бизнеса (low / high) и насколько сильно он связан с остальной системой (low / high). Начинать стоит с квадранта low-criticality + low-coupling: ошибки в нем не уронят бизнес-показатели, а малое количество зависимостей позволит провести миграцию полностью, не утянув за собой смежные модули. Высоко-критичные и сильно связанные части (платежи, ядро авторизации) трогают в последнюю очередь — на этот момент команда уже наберёт опыт безопасной миграции.</p><p>Хорошие точки входа обычно: уведомления, генерация отчетов, поиск, история операций, профиль пользователя, отдельная часть каталога. Важно, чтобы у команды была возможность описать контракт: какие данные входят, какие выходят, какие ошибки возможны, какие внешние системы участвуют.</p><p>Допустим, в банковском приложении есть старый модуль истории операций. Он медленный, сложно расширяется, но при этом не выполняет сами транзакции. Это хороший кандидат для первой миграции. Ошибка в истории операций неприятна, но обычно менее критична, чем ошибка в списании денег.</p><p>Команда может вынести чтение истории в отдельный сервис, сначала запустить его в shadow-режиме, потом включить для части пользователей, затем полностью перевести чтение на новую реализацию. При этом критичная транзакционная логика останется в старой системе до тех пор, пока команда не наберет опыт безопасной миграции.</p><h2>Миграция данных: самая сложная часть</h2><p>Большая часть статьи говорит о маршрутизации запросов и переключении трафика. Но в реальных проектах основная сложность лежит ниже — в данных. Старая и новая реализации почти всегда работают с общим состоянием: одной БД, одним хранилищем документов, одним набором очередей. Переехать туда «одним коммитом» нельзя.</p><p>Базовый рабочий приём — Expand-Contract (он же Parallel Change). Изменение схемы делается в три такта. На этапе expand в БД добавляются новые поля, таблицы или индексы, при этом старое поведение полностью сохраняется. Затем — migrate: обе реализации начинают писать и в старое, и в новое место (dual writes), а отдельный фоновый процесс делает backfill — заполняет новые поля историческими данными. После этого читатели по одному переключаются на новую схему. Только когда никто из читателей не использует старую структуру, наступает contract — удаление лишних колонок и таблиц.</p><p>Несколько практических деталей, которые часто упускают:</p><p>·         Dual writes — это не бесплатная операция. Две записи означают две точки отказа. Если одна из них упала, нужно решать, что делать: продолжать ли работу, ставить ли событие в очередь на повтор, помечать ли запись как несогласованную. Простое «сначала пишем туда, потом сюда» в продакшене на нагрузке приводит к расхождениям.</p><p>·         Backfill часто длиннее, чем кажется. На большой таблице миграция в одном UPDATE блокирует продакшен. Поэтому backfill делают батчами по N тысяч строк с паузами, отслеживают прогресс и предусматривают возможность остановить и продолжить.</p><p>·         Онлайн-изменения схемы на крупных таблицах делаются не штатным ALTER TABLE, а специализированными инструментами: gh-ost или pt-online-schema-change для MySQL, встроенные онлайн-механизмы PostgreSQL для индексов и колонок, Liquibase/Flyway — для управления версионированием изменений в репозитории.</p><p>·         Shadow testing данные не покрывает. Можно сравнить, что новая реализация возвращает то же, что и старая, но если за этим стоит другая схема в БД, проверка корректности самой миграции данных — это отдельная работа: сверки, контрольные суммы, выборочный аудит исторических записей.</p><p>Без этих шагов любая красивая фасадная архитектура наталкивается на разъезжающиеся данные — и тогда даже идеальный Strangler Fig снаружи не спасает.</p><h2>Прокси-слой как точка контроля</h2><p>Чтобы постепенно заменять legacy-код, нужно управлять маршрутизацией запросов. Для этого часто создают прокси-слой, API Gateway или фасад, через который проходит обращение к старой и новой логике. В терминах Domain-Driven Design такой слой часто называют Anti-Corruption Layer: он защищает новую реализацию от старых контрактов и наоборот, позволяя двум моделям сосуществовать без взаимного «загрязнения».</p><p>Без такой точки контроля миграция становится хаотичной. Часть клиентов ходит напрямую в старый модуль, часть — в новый, часть использует обходные пути, а команда теряет возможность централизованно переключать трафик.</p><p>Прокси-слой решает несколько задач. Он скрывает детали реализации от клиентов, позволяет направлять часть запросов в новую систему, поддерживает фича-флаги, собирает метрики и упрощает откат.</p><p>В качестве технической основы команды обычно берут один из трех вариантов: классический API gateway (Kong, AWS API Gateway), service mesh (Envoy, Istio) или более простой reverse proxy (NGINX, HAProxy). Service mesh особенно удобен, когда трафик уже идёт внутри Kubernetes-кластера: маршрутизацию можно менять конфигурацией, без правок кода клиентов и сервисов.</p><p>Например, мобильное приложение обращается к endpoint /orders/history. Раньше этот endpoint напрямую обслуживал монолит. После введения API Gateway приложение продолжает ходить по тому же контракту, но внутри gateway может решать, куда направить запрос: в legacy-модуль или новый сервис истории заказов.</p><p>Управление маршрутизацией обычно делается не «всё или ничего», а на основании атрибутов запроса: значения заголовка (X-Migration-Cohort: new), куки, хэша от user-id (стабильное разбиение пользователей на сегменты) или географического региона. Это позволяет выкатывать новую реализацию сначала на одну страну, на сотрудников самой компании или на тестовый сегмент — и только потом расширять охват.</p><p>Для клиента ничего не меняется. Для команды появляется управляемость.</p><h2>Наблюдаемость: без метрик миграция превращается в гадание</h2><p>Постепенная модернизация невозможна без нормальной наблюдаемости. Если команда не видит, что происходит внутри системы, она не сможет безопасно переключать трафик.</p><p>Минимальный набор — это логи, метрики и распределенная трассировка (distributed tracing). Нужно понимать, сколько запросов идет в старую и новую реализацию, сколько ошибок возникает, как меняется latency, где появляются таймауты, какие статусы возвращаются, какие бизнес-метрики проседают.</p><p>Технические метрики стоит формулировать не как «средний ответ» и «процент ошибок», а в терминах SLI и SLO: целевые показатели вида «99.9% запросов на /orders/history отвечают быстрее 300 ms за 30 дней» с явным error budget. Latency измеряется по перцентилям (p50, p95, p99) — среднее значение почти всегда обманчиво, а хвосты распределения говорят о реальном опыте пользователя. На время миграции имеет смысл выставить отдельные SLO для нового и старого пути и сравнивать их.</p><p>В качестве инструментов де-факто стандартом стал OpenTelemetry для трассировок, метрик и логов — единый протокол, который пишет в практически любое хранилище. Дальше — Prometheus и Grafana для метрик, Jaeger или Tempo для traces, Sentry или аналог для ошибок. Для миграции важна возможность фильтровать метрики по «варианту» — отдельно по старому и новому пути — иначе все цифры смешаются и реальную динамику будет не видно.</p><p>Технических метрик недостаточно. Если команда переносит оформление заказа, важно смотреть не только на 500 ошибки и время ответа, но и на конверсию в оплату, количество брошенных корзин, повторы запросов, обращения в поддержку.</p><p>Пример: новая система формально отвечает быстрее старой и не дает ошибок. Но после включения на 10% пользователей падает конверсия в оплату. Причина может быть не в серверной ошибке, а в изменении порядка полей, другом тексте сообщения или потере какого-то edge-case. Без бизнес-метрик команда может решить, что миграция успешна, хотя для продукта она уже создает проблему.</p><h2>Практическая последовательность миграции</h2><p>Рабочая последовательность обычно выглядит так.</p><p>Сначала команда выбирает ограниченный участок системы. На этом этапе важно не просто назвать модуль, а описать его границы. Какие сценарии он закрывает? Кто его вызывает? Какие данные он читает и пишет? Какие внешние интеграции использует? Какие неочевидные бизнес-правила в нем есть?</p><p>Затем поверх legacy-логики создается стабильный контракт. Это может быть API, фасад, gateway или отдельный слой внутри приложения. Главная задача — сделать так, чтобы клиенты зависели не от внутренней реализации, а от понятного интерфейса. На этом этапе полезно вспомнить про contract testing (Pact, Spring Cloud Contract): автотесты со стороны потребителей фиксируют, что именно они ожидают от API, и предупреждают о ломающих изменениях до того, как они доедут до продакшена.</p><p>После этого рядом пишется новая реализация. Она должна повторять текущее поведение, а не сразу становиться «идеальной версией будущего». На этом этапе полезно фиксировать все расхождения: где старая система работает странно, где требования не описаны, где бизнес-правила требуют уточнения.</p><p>Следующий этап — shadow testing. Новая система получает копии реальных запросов, считает результат, но пользователю по-прежнему возвращается ответ legacy. Команда сравнивает результаты и устраняет расхождения.</p><p>Когда новая реализация достаточно стабильна, начинается постепенное переключение через feature toggles. Сначала внутренние пользователи, потом 1% реального трафика, затем 5–10%, затем 50% и только после этого 100%.</p><p>На каждом этапе команда смотрит на метрики. Если всё стабильно, движение продолжается. Если появляются проблемы, флаг выключается, трафик возвращается в legacy, а команда разбирает причины.</p><p>Последний этап — удаление старого кода. Это не формальность, а обязательная часть миграции. И «удалить старый код» — это не один коммит, а явный Definition of Done: вырезана старая ветка кода, удалён фича-флаг, обновлена документация и схемы архитектуры, переименованы или удалены устаревшие дашборды и алерты, обновлены runbook’и для on-call и проведено короткое внутреннее обучение. Если этого не сделать, через полгода никто уже не вспомнит, какой путь актуален, и легаси-ветвление останется в коде навсегда.</p><h2>Откат миграций: дешёвый только пока не пошли записи</h2><p>Откатить миграцию, в которой ещё не было записи в БД, легко: достаточно переключить фича-флаг, и трафик снова идёт через старую реализацию. Откатить миграцию, в которой новая система уже неделю писала данные в новые таблицы, — отдельный, гораздо более тяжёлый разговор.</p><p>Поэтому ещё на этапе проектирования каждое изменение должно сопровождаться явным планом отката. Удобно различать три типа шагов.</p><p>Полностью обратимые шаги. Чтение через новый сервис, расчёт «в тени», новые метрики. Откат — выключить флаг. Это самый комфортный режим, и в нём стоит держать миграцию как можно дольше.</p><p>Обратимые с компенсацией. Новая реализация пишет дополнительные данные (например, дублирует операции в новую таблицу), но старый источник тоже обновляется. Откат возможен, но требует решить, что делать с уже записанными данными: оставить, очистить, синхронизировать. План этих действий должен быть написан до выкатки, не во время инцидента.</p><p>Forward-only. После некоторой точки откат становится невозможен — например, после того, как старая схема удалена или внешние интеграции перенастроены на новый сервис. Такие шаги допустимы, но к ним нужно приходить отдельно, осознанно, с особенно строгими SLO в предыдущем этапе. До forward-only-перехода имеет смысл подержать систему в режиме параллельной работы дольше, чем по графику.</p><p>Базовое правило: ни один шаг миграции не должен уходить в продакшен, если у команды нет письменного ответа на вопрос «как мы откатываемся в случае проблемы». Иначе при инциденте откатываться будут на ходу — и не факт, что успешно.</p><h2>Пример: как тот же сервис мигрировали со второй попытки</h2><p>После неудачного опыта команда взялась за тот же сервис заново, но изменила подход.</p><p>На первом шаге они зафиксировали поведение существующего сервиса. На самые часто используемые сценарии (создание путевого листа, подпись акта осмотра, выгрузка пакета документов за период) написали характеристические тесты на реальных продакшен-данных, обезличенных и сохранённых как фикстуры. Любое будущее изменение поведения теперь падало в CI как явное расхождение.</p><p>Параллельно команда провела инвентаризацию побочных эффектов. Из исходного кода и логов выяснилось, что сервис не только хранит документы, но и: публикует событие в Kafka при смене статуса, инкрементирует счётчик в Redis для рейтинга водителей, отправляет webhook во внешнюю систему партнёра, пишет в таблицу аудита. Каждый из этих эффектов попал в отдельный пункт чек-листа «что должно остаться» в новой реализации.</p><p>Затем команда выбрала первый кусок для выноса — не весь сервис, а только чтение документов (GET /documents/{id} и GET /documents/by-driver/{driver_id}). Это была наименее рискованная часть: ошибки в чтении неприятны, но не ломают финансовые потоки.</p><p>Новый сервис написали на FastAPI рядом со старым. На уровне API Gateway появилось правило маршрутизации: запросы на чтение шли в старый сервис, но в фоне дублировались в новый. Ответ пользователю всегда возвращал legacy, а ответ нового сервиса сравнивался с эталоном и записывался в отдельную таблицу для разбора. Использовали обёртку поверх asyncio.create_task — на ответ пользователя теневой вызов не влиял.</p><p>За три недели shadow-режима команда нашла четыре расхождения. Два оказались багами новой реализации (округление времени, неправильная сортировка вложений). Два — давно забытыми особенностями старого сервиса (одно поле возвращалось в UTC, другое — в локальной зоне; так было исторически, бизнес не возражал, но в новой реализации захотели единый формат). Все четыре зафиксировали явно: баги — починили, особенности — согласовали с продуктовой командой как осознанное изменение.</p><p>Когда расхождений не осталось, включили фича-флаг на сотрудников самой компании. Через неделю — на 1% реальных водителей. Дальше шаг по 5%, 25%, 50%, 100% с паузой в несколько дней между этапами. На каждом шаге следили не только за HTTP-ошибками и latency, но и за продуктовыми метриками: количество подписанных актов, время от открытия документа до подписи, доля повторных запросов. Один раз пришлось откатиться с 25% на 5% — в одном из регионов выросло время отклика из-за неэффективного запроса. Исправили, выкатили снова.</p><p>Через два месяца чтение полностью перешло в новый сервис. Старый код чтения и фича-флаг удалили в том же релизе. После этого по той же схеме мигрировали запись документов, потом публикацию событий, потом импорт из внешних систем. Полная миграция заняла девять месяцев — почти столько же, сколько провалившийся Big Bang, — но продукт всё это время продолжал развиваться, инцидентов не было, и в конце команда осталась с системой, которую понимает.</p><h2>Типичные ошибки при работе с legacy</h2><p>Первая ошибка — пытаться улучшить всё сразу. Команда одновременно меняет архитектуру, бизнес-логику, контракты и инфраструктуру. В результате становится невозможно понять, какая именно часть вызвала проблему. Правильнее сначала воспроизвести поведение, стабилизировать новую реализацию и только потом улучшать.</p><p>Вторая ошибка — недооценивать скрытые зависимости и побочные эффекты. Legacy-код часто делает больше, чем кажется. На один и тот же вызов могут быть навешаны: запись в таблицу аудита, инкремент счётчика в кэше, публикация события в очередь, обновление статуса связанной сущности, инвалидация кэша, дёрганье webhook’а во внешнюю систему. Если в новой реализации воспроизвести только явный путь, скрытые потребители молча перестанут получать данные — и узнают об этом через жалобу бизнеса, а не через ошибку в логах. Поэтому перед выносом любого модуля имеет смысл составить инвентаризацию побочных эффектов: пройтись по коду и логам и выписать каждое нелогичное действие отдельным пунктом чек-листа.</p><p>Третья ошибка — отсутствие наблюдаемости. Без логов, метрик и трассировки команда не управляет миграцией, а угадывает. Особенно опасно смотреть только на технические ошибки и игнорировать бизнес-показатели.</p><p>Четвертая ошибка — не договариваться с бизнесом. Модернизация не должна быть невидимой «инженерной активностью в стол». Её нужно встраивать в roadmap, объяснять эффект и договариваться о приоритетах. Если бизнес не понимает, зачем команда тратит время на миграцию, работа будет постоянно проигрывать новым фичам.</p><p>Пятая ошибка — не удалять старый код. Временное сосуществование старой и новой логики нормально. Вечное сосуществование — нет. Если legacy не удаляется, технический долг не уменьшается, а просто меняет форму.</p><p>Шестая ошибка — не удалять фича-флаги после миграции. Флаг, который сыграл свою роль и больше никогда не выключается, превращается в постоянное ветвление в коде. Через год команда не помнит, можно ли удалить такую ветку или там сидит важный edge-case. Через два — кода с такими «мёртвыми» флагами становится больше, чем основной логики. Поэтому каждый флаг должен заводиться с условием удаления («после полной выкатки и двух недель стабильной работы») и иметь ответственного, кто этим удалением займётся.</p><p>Отдельно стоит упомянуть организационную сторону. Закон Конвея работает и в обратную сторону: если новый и старый код владеются разными командами с разными приоритетами, миграция будет тормозиться независимо от выбранного паттерна. На время миграции имеет смысл явно проговорить, кто отвечает за переход, и не разделять старую и новую реализации между несовместимыми roadmap’ами.</p><h2>Компромиссы, к которым нужно быть готовыми</h2><p>Постепенная модернизация безопаснее Big Bang-переписывания, но она не бесплатна. Некоторое время система будет сложнее, чем раньше. В ней появятся старый и новый код, прокси-слой, фича-флаги, дублирование логики, дополнительные метрики.</p><p>Shadow testing увеличит нагрузку на инфраструктуру, потому что часть запросов будет обрабатываться дважды. Команде придется поддерживать дисциплину: документировать контракты, отслеживать флаги, удалять старую реализацию после миграции, поддерживать contract-тесты в актуальном состоянии.</p><p>Но это контролируемая сложность. Она распределена во времени и управляется инженерными практиками. В отличие от Big Bang-риска, где команда долго работает с минимальной обратной связью, а потом выкатывает один большой релиз с максимальной неопределенностью.</p><h2>Когда Strangler Fig особенно оправдан</h2><p>Постепенная миграция особенно хорошо подходит для систем, где downtime невозможен или слишком дорог. Это финтех, e-commerce, биллинг, мобильные бэкенды с большой аудиторией, высоконагруженные продукты, старые монолиты и системы с большим количеством интеграций.</p><p>Если продуктом ежедневно пользуются сотни тысяч или миллионы людей, нельзя позволить себе «переписать и посмотреть, что будет». Нужно менять архитектуру так, чтобы пользователь не замечал процесса миграции.</p><p>Этот подход также полезен там, где бизнес продолжает активно развивать продукт. Если фичи нельзя заморозить на полгода, модернизация должна идти параллельно с продуктовой разработкой.</p><h2>Когда модернизацию лучше не делать</h2><p>Постепенная миграция — мощный инструмент, но у неё тоже есть стоимость, и иногда правильный ответ — оставить систему как есть. Несколько сценариев, в которых модернизация плохо окупается.</p><p>Продукт, который уходит из эксплуатации. Если через год сервис будет выключен или заменён на покупное решение, тратить квартал на его рефакторинг бессмысленно. Достаточно стабилизировать то, что есть.</p><p>Модуль, который никто не трогает. Если код десятилетней давности продолжает работать, не падает, не требует изменений и не вызывает инцидентов, его «уродливость» — не повод его переписывать. Цель модернизации — упростить будущие изменения; если будущих изменений нет, цели тоже нет.</p><p>Регулируемые системы с тяжёлой ресертификацией. В банковских, медицинских и государственных контурах любое изменение в критичной системе может потребовать повторной сертификации, перепрохождения аудитов, обновления договорной обвязки. В таких условиях стоимость модернизации может на порядок превышать стоимость поддержки текущей реализации, и решение нужно принимать вместе с владельцем продукта и юристами, а не только инженерным составом.</p><p>Простой тест: если на вопрос «какой бизнес-сценарий мы откроем после миграции» нет внятного ответа — модернизацию имеет смысл отложить и заняться чем-то другим.</p><h2>Что получает команда</h2><p>Главный результат постепенной модернизации — управляемость. Команда начинает лучше понимать систему, контролировать изменения и снижать риск инцидентов.</p><p>Появляются понятные контракты, наблюдаемость, практика безопасных релизов, культура удаления старого кода. Разработчики перестают бояться legacy, потому что у них появляется метод, а не только желание «когда-нибудь всё переписать».</p><p>Для бизнеса это тоже выгодно. Продукт продолжает развиваться, сроки становятся более прогнозируемыми, риски крупных сбоев снижаются, а технический долг постепенно уменьшается.</p><h2>Модернизация — это процесс, а не проект</h2><p>Legacy нельзя «починить за квартал». Если система развивалась годами, она не станет простой после одного рефакторинга. Но её можно системно улучшать.</p><p>Strangler Fig Pattern, Branch by Abstraction, feature toggles, shadow testing и аккуратная миграция данных дают рабочую модель: выбрать ограниченный участок, описать контракт, реализовать новую версию, проверить её на реальном трафике, постепенно переключить пользователей и удалить старый код.</p><p>Это не самый быстрый путь. Зато он управляемый. А в зрелых продуктах управляемость важнее скорости.</p><p>Потому что цель модернизации — не написать красивую новую систему. Цель — сделать так, чтобы продукт продолжал развиваться, команда могла безопасно вносить изменения, а пользователи не становились участниками инженерного эксперимента.</p>]]></content:encoded>
    </item>
    <item>
      <title>Valve впервые за 4 года обновил GameNetworkingSockets — что нового в 1.5</title>
      <link>https://tproger.ru/news/valve-vpervye-za-4-goda-obnovil-gamenetworkingsockets-chto-novo</link>
      <comments>https://tproger.ru/news/valve-vpervye-za-4-goda-obnovil-gamenetworkingsockets-chto-novo?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/valve-vpervye-za-4-goda-obnovil-gamenetworkingsockets-chto-novo</guid>
      <description><![CDATA[<p>Valve выпустил GameNetworkingSockets 1.5 — первый релиз за 4 года. Поменялась семантика SendMessages, добавили ECN, jitter stats, Rust bindings. Что обновить.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/valve-vpervye-za-4-goda-obnovil-gamenetworkingsockets-chto-novo">Valve впервые за 4 года обновил GameNetworkingSockets — что нового в 1.5</a>»</p>]]></description>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 30 Apr 2026 14:37:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Valve <a href="https://github.com/ValveSoftware/GameNetworkingSockets/releases/tag/v1.5.0">впервые с лета 2022 года выложила тег</a> GameNetworkingSockets — релиз 1.5. Накопленный за почти четыре года хвост — около 350 коммитов с прошлого тега: поменялась семантика SendMessages (нужно ревизовать места, которые ничего не делают с её результатом), появились ECN и jitter-метрики, ETW-диагностика на Windows, фиксы race-багов в P2P через WebRTC ICE и community-биндинги для Rust. Если про эту библиотеку слышите впервые — на ней работают Counter-Strike, Dota 2 и десятки сторонних проектов, использующих Steam Datagram Relay.</p><p>GameNetworkingSockets (GNS) — это open-source транспортный слой для игр от Valve. UDP-сокеты с надёжной доставкой, шифрованием end-to-end, congestion control, NAT traversal через ICE, retry-логикой поверх ненадёжной сети. По устройству ближе всего к QUIC — UDP в основе, поверх свой надёжный канал, шифрование, фрагментация. Но это не QUIC: формат пакетов и хэндшейк свои, совместимости с RFC 9000 нет. Когда Valve открыла исходники в 2018 году, у инди-разработчиков и небольших студий появился рабочий движок сетевой части без необходимости заказывать его за миллионы долларов или писать самим с нуля.</p><p>С тех пор библиотеку взяли в самые разные продукты — от шутеров до симуляторов и до RPG. Major-тег 1.4.0 вышел в январе 2022 года, патч-релиз 1.4.1 — в июне 2022. С тех пор в репозитории шла обычная разработка — около 350 коммитов в master с фиксами и улучшениями, — но нового тега не было. 28 апреля 2026 года Valve собрала весь этот хвост в релиз 1.5 и подытожила, что именно изменилось.</p><p><b>v1.5.0 — первый тег за почти 4 года.</b> Major-тег 1.4.0 вышел в январе 2022, патч 1.4.1 — в июне 2022. Накопленный хвост — около 350 коммитов в master с прошлого тега.</p><p><b>Поменялась семантика SendMessages.</b> Раньше функция возвращала единый код, по которому невозможно было понять, какие из сообщений ушли. Теперь каждое сообщение получает свой результат, и интерфейс облегчает retry. Старый код, который игнорировал результат и работал как «отправь и забудь», нужно пересмотреть.</p><p><b>Новые конфиги</b>: Explicit Congestion Notification (ECN), статистика jitter, IPLocalHost_AllowWithoutAuth и ещё несколько. Помогают тюнинговать поведение в стрессовых сетях и тестовых окружениях.</p><p><b>Native ICE-клиент по-прежнему в beta.</b> Race-баги, ведущие к hang, починили; для production-P2P пока всё равно WebRTC ICE.</p><p><b>Появились первые Rust bindings</b> — community-вклад, не официально поддерживаемый Valve, но рабочая отправная точка для Rust-проектов.</p><h2>Что такое GameNetworkingSockets и кто на нём работает</h2><p>GameNetworkingSockets — это библиотека сетевого транспорта, открытая Valve в 2018 году. По смыслу она ближе всего к QUIC: UDP в основе, поверх — собственный надёжный канал, шифрование, контроль перегрузки, фрагментация. Главное отличие — ориентация на игровой трафик: маленькие частые сообщения, тонкая конфигурация ретраев, поддержка ненадёжной доставки рядом с надёжной (можно выбрать на каждое сообщение).</p><p>Использует библиотеку прежде всего сама Valve: на ней работают Counter-Strike, Dota 2 и любой другой мультиплеер из Steam, который ходит через Steam Datagram Relay (SDR) — собственную сеть Valve, агрегирующую трафик через быстрые узлы поближе к игроку. Кроме Valve, библиотеку взяли разные инди- и middleware-проекты, плюс она встроена как дополнительный backend в несколько игровых движков.</p><p>У GNS есть два режима. Первый — клиент-сервер по обычному IP, без участия Steam-сети. Второй — P2P, через ICE для NAT traversal. P2P-режим требует внешнего signaling-сервера для обмена ICE-кандидатами между пирами; пример Valve поставляет в репозитории.</p><h2>Что нового в 1.5</h2><h3>API: новая семантика SendMessages, плоский C API для Messages</h3><p>Главное изменение в API — поведение ISteamNetworkingSockets::SendMessages при ошибках. Раньше функция возвращала единый код, который не давал понять, какие из сообщений ушли, а какие нет. Теперь каждое сообщение получает свой результат, а интерфейс облегчает retry — можно прозрачно переотправить только упавшие, не дублируя успешные. Если у вас в коде есть обёртка «отправил пачку — получил ОК или нет», её надо переписать под новый паттерн, иначе при сбоях часть сообщений просто потеряется.</p><p>Добавлен flat C API для ISteamNetworkingMessages — это режим, где сокеты привязываются не к connection-у, а к идентичности игрока, и отправка идёт по принципу «отправь пользователю X». Раньше этот режим был доступен только из C++. Теперь можно дёргать его и из C, и из любого языка с C FFI без C++-обёртки — что особенно актуально для Rust-, Go- и Python-биндингов.</p><p>Появилась хук-функция SteamNetworkingSockets_SetServiceThreadInitCallback — для тех, кто хочет подкрутить поведение сервисного потока (приоритет, имя, привязка к ядру) до того, как библиотека начнёт обрабатывать пакеты.</p><h3>Надёжность и наблюдаемость</h3><p>На уровне пакетов и очереди сообщений библиотека теперь автоматически корректирует часть out-of-order ситуаций — раньше эти случаи выливались в reorder-events для прикладного кода, и каждый разработчик разбирался с ними сам. Не идеальное решение для всех сценариев, но для игрового трафика — обычно то, что нужно по умолчанию.</p><p>Из новых конфигов и метрик:</p><ul><li>ECN (Explicit Congestion Notification) — поддержка пометок в IP-заголовке, чтобы роутеры могли сигнализировать о перегрузке без потери пакетов.</li><li>Jitter stats — статистика разброса времени доставки, видимая через стандартные accessor-ы. Полезно для тонкой настройки буферов и плавности геймплея.</li><li>IPLocalHost_AllowWithoutAuth — режим без аутентификации для localhost-соединений, удобен в тестовых сборках, dedicated-серверах локальной отладки и CI.</li><li>ETW (Event Tracing for Windows) — диагностические события, видимые в Windows Performance Analyzer и аналогах.</li></ul><h3>P2P: ICE-клиенты, race-баги</h3><p>P2P-стек получил серию точечных фиксов. В WebRTC ICE-клиенте, который Valve использует как основной для P2P, починили race-баги, которые приводили к hang при определённых таймингах рукопожатия. В нативном ICE-клиенте — собственной имплементации ICE-стека Valve, которая развивается параллельно ICE из WebRTC, исправили несколько багов, но он по-прежнему помечен как beta — для production пока рекомендуют WebRTC ICE.</p><p>Пример сигнального сервера в репозитории переписан с нуля на Python — раньше он жил на C++ и имел набор багов, которые мешали запустить локальный P2P-тест из коробки. Сейчас пример работает «как описано» и заодно проверяется в CI: P2P-сценарии добавили в авто-тесты, что для самоподдерживающейся кодовой базы серьёзный шаг.</p><h3>Rust bindings, CMake/vcpkg, протобафы</h3><p>В релиз попали первые официальные Rust bindings — но с дисклеймером community contribution: их пишет и поддерживает не Valve, а сторонние мейнтейнеры. Если планируете сетевой стек на Rust поверх GNS — подключите биндинг как зависимость, но будьте готовы к тому, что приоритет фиксов и обновлений отличается от основной библиотеки.</p><p>Интеграция с CMake и vcpkg существенно упрощена — собрать GNS без сторонних рецептов теперь реально на обычной машине. Параллельно починили совместимость с новыми версиями protobuf и abseil — последняя регулярная боль для тех, кто строил на vcpkg или conan.</p><h2>Почему 4 года тишины</h2><p>Valve в release notes причину не комментирует. Видимая динамика — около 600 коммитов в master за этот период, регулярные мерж-реквесты от внешних контрибьюторов, активное реагирование на issue. Пакетный релиз делается, по всей видимости, по другому критерию — когда внутреннее использование в продуктах требует фиксированной версии для интеграции.</p><p>Для пользователей библиотеки это означало одно из двух: либо собирать сборку из master и брать на себя риск сломанных интерфейсов, либо сидеть на 1.4, не получая четырёх лет улучшений. Релиз 1.5 закрывает обе дороги: можно зафиксироваться на стабильном теге и получить весь хвост.</p><h2>Стоит ли переходить на 1.5</h2><p>Если у вас 1.4 в продакшене:</p><ul><li>Тщательно проверьте код вокруг SendMessages — теперь по каждому сообщению есть свой результат, и старый «отправь и забудь» нужно дополнить логикой ретраев.</li><li>Прогоните регрессионный тест P2P, если используете — race-баги в WebRTC ICE и нативном ICE затрагивали реальные сценарии и могли проявляться раз в N подключений.</li><li>Подключите ECN и jitter stats к телеметрии — за 4 года накопилось чем мерить качество соединения, грех не воспользоваться.</li><li>Если в ваших сборках болела совместимость с протобафом или abseil — берите 1.5: эти места починили.</li></ul><p>Если выбираете между GNS и альтернативами для нового проекта — релиз 1.5 не меняет принципиально позиционирование. GNS остаётся хорошим выбором, когда нужен стабильный, проверенный в Counter-Strike транспорт с готовым P2P для NAT traversal. Для проектов, где важно глубже интегрироваться с QUIC, WebTransport или WebRTC напрямую, существуют более специализированные стеки. Между GNS и более минималистичными ENet, kcp, RakNet выбор зависит от потребностей: GNS даёт из коробки больше фич (ICE, шифрование, контроль перегрузки), ценой большего C++-кода и зависимостей; ENet и kcp компактнее и быстрее интегрируются.</p><h2>Выводы</h2><p>GameNetworkingSockets 1.5 — это спокойный пакетный релиз: четыре года накопленных улучшений, без масштабных переписываний интерфейсов. Главное API-изменение — семантика SendMessages, и это та правка, которую разработчики на 1.4 пропустить не смогут. Всё остальное — про observability, P2P-стабильность и удобство сборки.</p><p>Сам факт, что Valve собрала тег после такой паузы, — хороший сигнал: библиотеку используют достаточно, чтобы стабильный артефакт имел смысл. Для маленьких студий, у которых нет сил тащить master из репозитория каждый раз, это означает возможность снова жить на стабильной версии без четырёхлетнего отставания.</p><p>Источники: <a href="https://github.com/ValveSoftware/GameNetworkingSockets/releases/tag/v1.5.0">релиз v1.5.0 на GitHub</a>, <a href="https://github.com/ValveSoftware/GameNetworkingSockets">репозиторий и документация</a>, обзор у <a href="https://www.phoronix.com/news/Valve-GameNetworkingSockets-1.5">Phoronix</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Вышел OpenSSL 4.0 — выпилены engines, SSLv3 и ASN1_STRING</title>
      <link>https://tproger.ru/news/vywel-openssl-4-0-vypileny-engines-sslv3-i-asn1-string</link>
      <comments>https://tproger.ru/news/vywel-openssl-4-0-vypileny-engines-sslv3-i-asn1-string?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/vywel-openssl-4-0-vypileny-engines-sslv3-i-asn1-string</guid>
      <description><![CDATA[<p>OpenSSL 4.0 — первый мажор с 2021 года. Удалили engine-интерфейс (ломает gost-engine), SSLv3, сделали ASN1_STRING непрозрачным. Узнайте, как мигрировать с 3.x.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/vywel-openssl-4-0-vypileny-engines-sslv3-i-asn1-string">Вышел OpenSSL 4.0 — выпилены engines, SSLv3 и ASN1_STRING</a>»</p>]]></description>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 15 Apr 2026 09:00:04 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если в вашей сборке крутится что-то линкованное с OpenSSL — посмотрите, не сломает ли вас переход на 4.0: релиз выкидывает engine-интерфейс (на нём держится gost-engine для ГОСТ-криптографии), поддержку SSLv3, скрипт c_rehash и делает непрозрачной структуру ASN1_STRING. Следом едут новые фичи — Encrypted Client Hello, гибридный постквант-обмен и FFDHE в TLS 1.2.</p><p>14 апреля 2026 года OpenSSL Project <a href="https://openssl-library.org/post/2026-04-14-openssl-4.0/">выпустил OpenSSL 4.0</a> — первый мажорный релиз со времён 3.0 (сентябрь 2021). За четыре с половиной года накопилось много удалений и чуть поменьше новых возможностей. Разбираем, что именно сломается при апгрейде и ради чего всё это затевалось.</p><ul><li>OpenSSL 4.0 — первый мажор с 2021 года. Релиз 14 апреля 2026.</li><li>Engine-интерфейс удалён полностью. Ломает gost-engine, старые PKCS#11- и TPM-адаптеры — мигрируйте на providers.</li><li>Поддержка SSLv3 вырезана из кода (выключена по умолчанию была с 2016 года).</li><li>ASN1_STRING стал непрозрачным — прямой доступ к полям через -&gt; больше не компилируется.</li><li>Появилась поддержка ECH (RFC 9849) — TLS прячет SNI от провайдера.</li><li>Добавлен гибридный постквантовый обмен SM2+ML-KEM-768 и подпись ML-DSA-MU.</li></ul><h2>Что выпилили: список для миграции</h2><p>OpenSSL 3.0 в 2021 году ввёл архитектуру providers и одновременно объявил engine-интерфейс устаревшим. Четыре года переходного периода закончились: engines больше нет в коде, опция сборки no-engine всегда включена, макрос OPENSSL_NO_ENGINE — всегда определён. Это самое болезненное для тех, кто держал кастомный крипто-плагин: GOST, аппаратные HSM, PKCS#11-токены со старым драйвером.</p><p>Из публичных API в 4.0 пропали или стали непрозрачными:</p><ul><li>Engine-интерфейс целиком — <a href="https://www.openssl.org/docs/man3.0/man7/provider.html">providers</a> теперь единственный способ подключить внешнюю криптографию.</li><li>Поддержка SSLv2 Client Hello и SSLv3. SSLv3 деприкейтнули ещё в 2015 году (<a href="https://datatracker.ietf.org/doc/html/rfc7568">RFC 7568</a>), в 1.1.0 выключили по умолчанию в 2016-м, теперь удалили из кода.</li><li>Структура ASN1_STRING стала непрозрачной. Прямой доступ к полям — через функции-аксессоры.</li><li>ERR_get_state(), ERR_remove_state(), ERR_remove_thread_state() — объект ERR_STATE теперь непрозрачный.</li><li>Кастомные методы EVP_CIPHER, EVP_MD, EVP_PKEY, EVP_PKEY_ASN1 — устаревшие API удалены.</li><li>X509_cmp_time() и семейство деприкейтнуты в пользу X509_check_certificate_times().</li><li>Скрипт c_rehash — использовать openssl rehash.</li><li>BIO_f_reliable() — был сломан с 3.0 и без жалоб прожил все эти годы.</li><li>Опция msie-hack в команде openssl ca.</li><li>Таргеты сборки darwin-i386 и darwin-ppc.</li><li>Устаревшие эллиптические кривые в TLS (<a href="https://datatracker.ietf.org/doc/html/rfc8422">RFC 8422</a>) выключены в сборке по умолчанию — включаются флагом enable-tls-deprecated-ec.</li><li>Explicit EC curves — аналогично, флаг enable-ec_explicit_curves.</li></ul><p>Отдельно изменилось поведение глобальной очистки. libcrypto больше не ставит обработчик на atexit(); OPENSSL_cleanup() теперь вызывается как глобальный деструктор при выходе процесса — значит, освобождение памяти по умолчанию происходит позже и в непредсказуемом порядке относительно других деструкторов. Если вам нужна детерминированная очистка до завершения процесса (например, чтобы выявлять утечки под valgrind), вызывайте OPENSSL_cleanup() явно.</p><h2>Что это значит для ГОСТ-криптографии</h2><p><a href="https://github.com/gost-engine/engine">gost-engine</a> — основной проект, который даёт OpenSSL понимание российских алгоритмов (ГОСТ Р 34.10-2012, ГОСТ Р 34.11-2012, «Кузнечик» и «Магма» по ГОСТ Р 34.12-2015). Как понятно из названия, он реализован именно как engine и без engine-слоя собраться и загрузиться в OpenSSL 4.0 не сможет.</p><p>Альтернатива — <a href="https://github.com/provider-corner/gostprov">gostprov</a>, провайдер от того же сообщества на новом API. На 15 апреля 2026 года gostprov покрывает базовые примитивы — ГОСТ Р 34.10-2012 (подпись), ГОСТ Р 34.11-2012 (хеш «Стрибог») и блочный шифр «Магма»/«Кузнечик» (ГОСТ Р 34.12-2015). Что ещё не закрыто по сравнению с gost-engine: часть схем шифрования CMS (ГОСТ-обёртки ключей), VKO KEK-2012 и ряд нишевых TLS-свитов. Если ваш продукт сертифицирован по требованиям ФСБ или продаётся в госсектор — апгрейд на 4.0 нужно планировать заранее, с пересертификацией.</p><p>Ветки 3.x продолжают поддерживаться: 3.5 — LTS до апреля 2030 года, 3.4/3.3 — обычные релизы с обновлениями безопасности. Если с 4.0 спешить некуда — остановитесь на 3.5 и дождитесь, пока gostprov покроет нужные вам примитивы.</p><h2>Что добавили</h2><h3>Encrypted Client Hello (ECH)</h3><p>ECH — это <a href="https://datatracker.ietf.org/doc/rfc9849/">RFC 9849</a>, принятый в марте 2026 года. В обычном <a href="https://tproger.ru/articles/tls-handshake-explained">TLS-рукопожатии</a> первый Client Hello содержит SNI — имя сайта, к которому вы подключаетесь — в открытом виде. Провайдер видит его и по нему можно фильтровать трафик или собирать метаданные. ECH делит Client Hello на две части: ClientHelloOuter с именем фронтового домена идёт в открытую, а ClientHelloInner с настоящим SNI шифруется публичным ключом, опубликованным через DNS (HTTPS-запись).</p><p>OpenSSL 4.0 — первая мажорная версия с ECH в основной ветке. Серверная и клиентская стороны поддерживают draft-final в полном объёме. Документация проекта — <a href="https://github.com/openssl/openssl/blob/master/doc/designs/ech-api.md">doc/designs/ech-api.md</a>.</p><h3>Гибридный постквант: SM2+ML-KEM-768</h3><p>OpenSSL поддерживает ML-KEM (Module-Lattice Key Encapsulation Mechanism, FIPS 203 — постквантовый обмен ключами) и гибриды с ним с версии 3.5. В 4.0 добавили ещё один гибридный обмен — curveSM2MLKEM768: китайский SM2 (<a href="https://datatracker.ietf.org/doc/rfc8998/">RFC 8998</a>) плюс ML-KEM-768 в качестве постквантовой части. Комбинация адресная — она нужна прежде всего для рынка КНР, где SM2 обязателен по национальному стандарту. Плюс новый алгоритм цифровой подписи ML-DSA-MU — вариант <a href="https://tproger.ru/news/openssh-10-3-zakryvaet-shell-injection-i-nachinaet-postkvantovuyu">ML-DSA</a> с внешним префиксом (prehash) для больших сообщений.</p><p>Для остального мира в релизе также появился <a href="https://csrc.nist.gov/pubs/sp/800/185/final">cSHAKE</a> (SP 800-185 — customizable SHAKE, версия SHAKE с доменным разделением). cSHAKE используется как строительный блок в новых стандартах NIST — именно на нём построен KMAC, а также часть постквантовых подписей. Плюс KDF для SNMP и SRTP — узкие штуки, но их в OpenSSL долго не было.</p><h3>FFDHE в TLS 1.2 и прочие мелочи</h3><p>FFDHE (finite-field Diffie-Hellman) по <a href="https://datatracker.ietf.org/doc/html/rfc7919">RFC 7919</a> — способ согласовывать группы для классического DH из фиксированного списка, а не из того, что сервер пришлёт. В TLS 1.3 это сделали сразу, в TLS 1.2 OpenSSL годами поддерживал только «пришли мне параметры». 4.0 закрыл этот пробел.</p><ul><li>FIPS self tests теперь можно откладывать до реального использования — флаг -defer_tests в openssl fipsinstall.</li><li>На Windows можно выбирать статическую или динамическую линковку VC Runtime.</li><li>Нижние границы параметров PKCS5_PBKDF2_HMAC теперь проверяются при работе в FIPS-провайдере.</li><li>Проверка AKID добавлена при установленном X509_V_FLAG_X509_STRICT.</li><li>CRL-верификация получила несколько дополнительных проверок корректности.</li></ul><h2>Как мигрировать на OpenSSL 4.0</h2><ol><li>Не обновляйтесь в лоб. Сначала прогоните вашу сборку с 3.5 и флагами -Wdeprecated-declarations и OPENSSL_NO_DEPRECATED_3_0, чтобы увидеть, где висит engine-API или структурный доступ к ASN1_STRING.</li><li>Составьте карту зависимостей: какие ваши библиотеки линкуются с OpenSSL и какие из них делают что-то нестандартное. Особое внимание — ко всему, где в коде встречается ENGINE_*.</li><li>Если используете ГОСТ — ставьте параллельно gostprov на 3.x, проверьте, что покрываются все ваши примитивы, и только после этого двигайтесь к 4.0.</li><li>Проверьте, как ваше приложение освобождает ресурсы OpenSSL. Если вы полагались на atexit()-финализацию или ранний OPENSSL_cleanup() в середине работы — добавьте явный вызов в точку, где очистка действительно нужна.</li><li>Пересоберите статические пакеты. OpenSSL 4.0 несовместим по ABI с 3.x — пакетные менеджеры дистрибутивов ближайшие месяцы будут подтягивать зависимости.</li></ol><h2>Выводы</h2><p>OpenSSL 4.0 — релиз не столько про новые фичи, сколько про дочистку хвостов. За четыре с половиной года команда вывела из эксплуатации несколько слоёв устаревшего API и зафиксировала архитектуру providers как единственный способ подключать внешнюю криптографию. Цена — несовместимость по исходникам и ABI. На 15 апреля 2026 года крупные пакеты Debian, Ubuntu, RHEL и Fedora ещё линкуются с 3.x; пересборка экосистемы займёт месяцы, а для продуктов на engines (HSM-адаптеры, gost-engine, старые PKCS#11-драйверы) — ещё дольше.</p><p>Практический совет: если у вас нет конкретной нужды в ECH или SM2+ML-KEM-768, ближайший год можно спокойно сидеть на 3.5 LTS и следить за тем, как пересобираются ваши зависимости. Когда пакетные менеджеры дистрибутивов начнут подтягивать 4.0 автоматически — это и будет момент серьёзной миграции.</p><p>Полный changelog, downloadable tarballs и ключи для проверки подписи — на странице <a href="https://github.com/openssl/openssl/releases/tag/openssl-4.0.0">релиза на GitHub</a>. Сам <a href="https://github.com/openssl/openssl/blob/openssl-4.0.0/CHANGES.md">файл CHANGES.md</a> — хорошее чтение на вечер для всех, кто хоть раз линковал с OpenSSL.</p>]]></content:encoded>
    </item>
    <item>
      <title>Anna’s Archive начала выкладывать терабайты музыки со Spotify на торренты после иска на $13 трлн</title>
      <link>https://tproger.ru/news/anna-s-archive-nachala-vykladyvat-terabajty-muzyki-so-spotify-na</link>
      <comments>https://tproger.ru/news/anna-s-archive-nachala-vykladyvat-terabajty-muzyki-so-spotify-na?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/anna-s-archive-nachala-vykladyvat-terabajty-muzyki-so-spotify-na</guid>
      <description><![CDATA[<p>Anna’s Archive начала выкладывать на торренты миллионы треков со Spotify на фоне иска на $13 трлн от правообладателей</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/anna-s-archive-nachala-vykladyvat-terabajty-muzyki-so-spotify-na">Anna’s Archive начала выкладывать терабайты музыки со Spotify на торренты после иска на $13 трлн</a>»</p>]]></description>
      <category><![CDATA[Spotify]]></category>
      <category><![CDATA[Утечка данных]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 13 Feb 2026 06:38:13 GMT</pubDate>
      <content:encoded><![CDATA[<p>Теневая библиотека Anna’s Archive <a href="https://cybernews.com/security/shadow-library-releases-music-scraped-from-spotify/">начала</a> публиковать на торрентах аудиофайлы, бэкап которых был сделан со Spotify.</p><p>Интересный факт: все это происходит на фоне иска на астрономические $13 трлн, поданного платформой и крупными лейблами к библиотеке.</p><h2>Что именно выложили</h2><p>Пользователи Reddit заметили десятки новых раздач — всего 47 торрент-файлов объемом около 6,4 ТБ.</p><p>В них содержится примерно 2,8 млн треков. По сообщениям тех, кто успел скачать часть архива, файлы сопровождаются метаданными: названием композиции, альбомом, артистом, издателем и обложками.</p><p>Сейчас раздачи идут медленно: у части торрентов всего по одному сидеру.</p><p>Важно: опубликованная часть — лишь фрагмент более масштабного архива. Ранее Anna’s Archive заявляла о «скрейпе» порядка 300 ТБ музыки — около 86 млн треков, что якобы покрывает 99,6 % всех композиций на Spotify.</p><p>Пока на торренты выложены только наименее популярные композиции с меткой pop_0 — это внутренняя шкала популярности Spotify от 0 до 100.</p><p>Отдельно библиотека уже публиковала 200-гигабайтный архив с метаданными — 256 млн треков и 186 млн уникальных ISRC-кодов.</p><h2>Реакция Spotify и иск на триллионы</h2><p>Spotify заявила, что выявила и заблокировала аккаунты, использовавшиеся для «незаконного скрейпинга». После этого компания вместе с крупными правообладателями подала иск против неизвестных операторов Anna’s Archive.</p><p>Сумма требований — $13 трлн — выглядит как какая-то нереалистичная цифра. Она получена исходя из максимальных компенсаций в США: до $150 000 за каждое предполагаемое нарушение авторских прав. Если умножить эту ставку на миллионы треков, итог и правда уходит в космос.</p><p>По решению суда регистраторы уже отключили часть доменов библиотеки, включая основной в домене .org.</p><h2>Это конец или только начало</h2><p>После подачи иска Anna’s Archive временно скрыла раздел, посвященный загрузке музыки со Spotify. Публичных комментариев от проекта с тех пор не было. Однако появление торрентов показывает: процесс публикации, по крайней мере частично, продолжается.</p><p>Отдельная проблема для тех, кто теоретически захочет хранить весь архив — банальная физика. 300 ТБ — это десятки жестких дисков. Пользователи уже шутят, что стоимость хранилищ на фоне ИИ-бума делает «пиратство на таком масштабе» дорогим удовольствием.</p>]]></content:encoded>
    </item>
    <item>
      <title>Вышел Go 1.26: до 40% быстрее GC, дешевле cgo и экспериментальный SIMD</title>
      <link>https://tproger.ru/news/vywel-go-1-26--do-40--bystree-gc--dewevle-cgo-i-eksperimentalny</link>
      <comments>https://tproger.ru/news/vywel-go-1-26--do-40--bystree-gc--dewevle-cgo-i-eksperimentalny?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/vywel-go-1-26--do-40--bystree-gc--dewevle-cgo-i-eksperimentalny</guid>
      <description><![CDATA[<p>Вышел Go 1.26: новый GC до 40% быстрее, cgo дешевле, экспериментальный SIMD и усиленная безопасность рантайма</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/vywel-go-1-26--do-40--bystree-gc--dewevle-cgo-i-eksperimentalny">Вышел Go 1.26: до 40% быстрее GC, дешевле cgo и экспериментальный SIMD</a>»</p>]]></description>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Криптография]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[AMD]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 12 Feb 2026 01:45:27 GMT</pubDate>
      <content:encoded><![CDATA[<p>Go 1.26 вышел спустя полгода разработки. Релиз традиционно без фанфар, но с ощутимыми изменениями под капотом: ускорили сборку мусора, удешевили вызовы C-кода, усилили защиту рантайма и добавили несколько экспериментальных пакетов.</p><h2>Новый GC по умолчанию: минус до 40% накладных расходов</h2><p>Так, в релизе включён сборщик мусора <b>greenteagc</b>. Он оптимизирован для частого создания и сканирования мелких объектов.</p><p>В приложениях с активной аллокацией это даёт снижение накладных расходов GC <b>на 10–40%</b>. Если у вас сервис с короткоживущими структурами, это обновление может стать бесплатным ускорением, без изменения кода.</p><h2>cgo стал дешевле</h2><p>Вызовы функций на C через cgo также подешевели примерно на <b>30%</b>. Это важно для проектов, которые тянут нативные библиотеки (криптография, обработка изображений, старый C-код).</p><p>Дополнительно в runtime для 64-битных платформ включили рандомизацию адресного пространства (heap base). Это усложняет эксплуатацию уязвимостей в C-коде, подключённом через cgo. При необходимости можно отключить через:</p><h2>new() теперь умеет принимать выражения</h2><p>Встроенная функция new() получила маленькое, но приятное расширение: теперь можно передать выражение для начального значения.</p><p>Было:</p><p>Теперь можно:</p><p>Мелочь, но код становится компактнее и чище.</p><h2>Обобщённые типы: разрешили «ссылаться на себя»</h2><p>Generics стали чуть гибче. Теперь тип может передавать сам себя в список параметров типа:</p><p>Раньше такая самоссылка вызывала ошибку. Теперь — нет. Для сложных generic-алгоритмов это снимает лишние ограничения.</p><h2>Больше аллокаций в стеке, меньше в куче</h2><p>Компилятор расширил список случаев, когда слайсы размещаются в стеке, а не в куче. А так как меньше давления на GC, то и выше производительность.</p><h2>go fix переписали полностью</h2><p>Команду go fix переписали на базе пакета analysis. Теперь она использует анализаторы из пакета modernize, которые предлагают правки с учётом новых возможностей языка и стандартной библиотеки.</p><p>Также появился анализатор inline — он разворачивает вызовы функций, помеченных директивой:</p><h2>Новые пакеты</h2><p>В стандартную библиотеку добавили:</p><ul><li>crypto/hpke — реализация Hybrid Public Key Encryption</li><li>crypto/mlkem/mlkemtest</li><li>testing/cryptotest</li></ul><p>Появился экспериментальный simd/archsimd — низкоуровневый доступ к SIMD-инструкциям на AMD64. Это первый осторожный шаг Go в сторону управляемых векторных вычислений без ассемблера.</p><p>Также добавили экспериментальный runtime/secret для безопасного обнуления временной памяти и новый профиль goroutineleak в runtime/pprof — для поиска утечек горутин.</p><p>Скачать Go 1.26 можно по <a href="https://go.dev/dl/">ссылке</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>*WhatsApp переписал медиадвижок на Rust и выкинул 160 тысяч строк C++</title>
      <link>https://tproger.ru/news/-whatsapp-perepisal-mediadvizhok-na-rust-i-vykinul-160-tysyach-stro</link>
      <comments>https://tproger.ru/news/-whatsapp-perepisal-mediadvizhok-na-rust-i-vykinul-160-tysyach-stro?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/-whatsapp-perepisal-mediadvizhok-na-rust-i-vykinul-160-tysyach-stro</guid>
      <description><![CDATA[<p>*WhatsApp переписал медиадвижок на Rust, убрав 160 тыс строк C++, чтобы снизить уязвимости и повысить безопасность медиа</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/-whatsapp-perepisal-mediadvizhok-na-rust-i-vykinul-160-tysyach-stro">*WhatsApp переписал медиадвижок на Rust и выкинул 160 тысяч строк C++</a>»</p>]]></description>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[Android]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[iOS]]></category>
      <category><![CDATA[Rust]]></category>
      <category><![CDATA[Мессенджер]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 29 Jan 2026 02:14:21 GMT</pubDate>
      <content:encoded><![CDATA[<p>*Meta тихо <a href="https://engineering.fb.com/2026/01/27/security/rust-at-scale-security-whatsapp/">провернула</a> одну из самых крупных миграций на Rust в пользовательском софте.</p><p>*WhatsApp заменил более 160 000 строк C++-кода на Rust в критически важной части приложения — обработке медиафайлов. Новый код уже развернут на миллиардах устройств: от Android и iOS до веба, десктопа и носимых гаджетов.</p><p>Цель проста и прагматична: снизить класс уязвимостей, которые годами преследуют мессенджеры — ошибки управления памятью.</p><h2>Откуда вообще взялась проблема</h2><p>История тянется с 2015 года и уязвимости Stagefright в Android. Тогда выяснилось неприятное: достаточно отправить специально собранный видеофайл и он выполнит код на устройстве жертвы еще до того, как пользователь что-то нажмет.</p><p>Проблема была в системных медиабиблиотеках операционной системы. Именно поэтому приложения вроде *WhatsApp не могли решить ее самостоятельно.</p><p>После этого в *WhatsApp появился собственный C++-модуль wamedia, который проверял медиафайлы на соответствие стандартам, чтобы не скормить ОС заведомо опасный контент.</p><p>Все это работало, но с оговоркой: код автоматически обрабатывал недоверенные данные, а значит сам становился идеальной мишенью для эксплойтов.</p><h2>Почему именно Rust</h2><p>В *WhatsApp довольно рано сделали неприятный, но честный вывод: значительная часть критических багов связаны с банальными ошибками работы с памятью в C и C++. Rust эту категорию проблем убирает на уровне языка.</p><p>Вместо аккуратного «подкручивания гаек», разработчики пошли чуть более радикальным путем: переписали медиабиблиотеку целиком, параллельно поддерживая две реализации — на C++ и на Rust.</p><p>Их прогоняли через дифференциальный фаззинг, тесты и сравнение поведения, пока результаты не совпали.</p><figure><img src="https://media.tproger.ru/user-uploads/111041/2026-01-29/fdbeec47-e345-4933-b0d8-8ba73ae9944a.webp" alt="" /></figure><h2>Что получилось на выходе</h2><p>Итог оказался даже лучше ожидаемого. 160 000 строк на C++ превратились примерно в 90 000 строк на Rust. И это уже с тестами.</p><p>Производительность не просела, а потребление памяти в ряде сценариев даже снизилось. Основные сложности были не в коде, а вокруг него: размер бинарников из-за стандартной библиотеки Rust и сборка под десятки платформ.</p><p>Тем не менее, библиотеку полностью выкатили в прод. Сейчас этот Rust-код ежемесячно доставляется на миллиарды устройств, включая *WhatsApp, *Messenger и *Instagram.</p><p>В *Meta прямо называют это крупнейшим клиентским деплоем Rust, о котором им известно.</p><h2>Зачем это пользователю, который «просто шлет мемы»</h2><p>Новая система, внутри компании получившая имя Kaleidoscope, проверяет файлы еще до того, как ими займутся системные библиотеки.</p><p>Она отсекает битые и нестандартные структуры, ловит подмену типов (когда «картинка» на деле исполняемый файл), отдельно помечает рискованные форматы вроде PDF со скриптами и вложениями.</p><p>По сути, это еще один слой защиты. Пользователь его не видит, но это и не нужно.</p>]]></content:encoded>
    </item>
    <item>
      <title>context-async-sqlalchemy — лучший способ использовать sqlalchemy в async python приложении</title>
      <link>https://tproger.ru/articles/context-async-sqlalchemy---luchwij-sposob-ispolzovat-sqlalchemy-v-async-python-prilozhenii</link>
      <comments>https://tproger.ru/articles/context-async-sqlalchemy---luchwij-sposob-ispolzovat-sqlalchemy-v-async-python-prilozhenii?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Крылосов Андрей]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/context-async-sqlalchemy---luchwij-sposob-ispolzovat-sqlalchemy-v-async-python-prilozhenii</guid>
      <description><![CDATA[<p>context-async-sqlalchemy помогает очень просто работать с sqlalchemy в async python приложениях через контекст. Автоматическое управление engine, session, transaction.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/context-async-sqlalchemy---luchwij-sposob-ispolzovat-sqlalchemy-v-async-python-prilozhenii">context-async-sqlalchemy — лучший способ использовать sqlalchemy в async python приложении</a>»</p>]]></description>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 07 Jan 2026 10:50:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>Сначала кратко пройдемся по теории из чего состоит sqlalchemy и как ее происходит интеграция в python приложение. Посмотрим какие есть нюансы и как <a href="https://github.com/krylosov-aa/context-async-sqlalchemy">context-async-sqlalchemy</a> помогает вам удобно работать.</p><p>Важно что речь идет только об async python.</p><h2>Краткая сводка по sqlalchemy</h2><p>sqlalchemy предоставляет Engine, который отвечает за пул подключений к базе данных. Так же sqlalchemy предоставляет Session через которую мы и делаем sql запросы. Сессия обладает одним единственным коннектом, который она получает от engine.</p><figure><img src="https://media.tproger.ru/user-uploads/134966/2025-12-09/91d524dc-03e6-4d69-a998-99045995b2f4.png" alt="" /></figure><p>Engine должен жить долго, чтобы долго жил пул коннектов к бд. А вот сессии должны жить как можно короче, чтобы как можно быстрее отдавать коннект конкурирующим операциям.</p><p>(На схеме 2 engine подключено к одной бд, что конечно странно. Тут хотелось просто подсветить что каждый engine имеет свой пул. В приложении вы будете иметь один engine для одной бд. Например 1 для мастера и 1 для реплики)</p><h2>Внедрение и использование в приложении</h2><h3>Прямое использование</h3><p>Для начала посмотрим на самое простое внедрение и ручное использование в котором используется только sqlalchemy и это можно внедрить куда угодно.</p><p>Создаем engine и создаем session_maker чтобы создавать сессии:</p><p>И вот представим у нас есть функция создания юзера, которая является ручкой:</p><p>На 2 строке мы открыли сессию, на 3 строке открыли транзакцию и наконец на 4 строке мы выполнили какой-то sql запрос относящийся к созданию юзера.</p><p>А теперь представим, что мы делаем два sql запроса в рамках создания юзера</p><p>Тут появляется 2 проблемы:</p><ol><li>Используется 2 транзакции, хотя вероятно мы бы хотели получить одну транзакцию</li><li>Дублирование кода</li></ol><p>Можно попытаться решить эту проблему, если вынести контекстные менеджеры повыше:</p><p>Но если мы теперь взглянем на несколько ручек, то увидим что дублирование кода не исчезло:</p><h3>Dependency</h3><p>Можно использовать dependency и вынести управление сессией и транзакцией туда. Например в FastAPI это можно сделать так:</p><p>Эту проблему можно было бы решить, если в dependency возвращать не сессию напрямую, а например какой-то DI контейнер и из него уже извлекать сессии и иметь возможность их закрывать. Но это увеличивает количество кода практически как в предыдущем варианте и готовых решений в интернете я не нашел.</p><p>Так же теперь session нужно прокидывать по всему стеку вниз, до момента где эта сессия реально потребуется:</p><p>Как видите do_first сам не использует сессию, но вынужден принимать аргумент чтобы прокинуть его ниже. Лично мне это очень не нравится. Мне нравится инкапсулировать такое внутрь insert_to_database, тут скорее вкусовщина и борьба философий.</p><h3>Обертки над sqlalchemy</h3><p>Есть разные обертки над sqlalchemy которые могут предоставлять разные удобства, но я из даже рассматривать тут не буду потому что у них есть важный нюанс: новый синтаксис. То есть разработчики знающие sqlalchemy не сразу смогут работать через библиотеку обертку.</p><h2>Новая библиотека</h2><p>Все выше указанное мне не очень понравилось. Мне не понравилось что в своем новом FastAPI сервисе мне нужно написать кучу кода, чтобы было удобно работать с sql и готовых решений которые позволили бы писать мало кода, но и не ограничивали бы ручное управление сессиями и транзакциями я не нашел. И сначала я написал удобно для себя и теперь делюсь этим с миром.</p><p>Что хотелось получить от библиотеки при работе с ней:</p><ul><li>Мало кода без дублирования</li><li>Автоматический commit или rollback, когда нет нужды вручную этим управлять</li><li>Есть возможность ручного управления сессией и транзакцией</li><li>Удобно для CRUD и удобно для сложных сценариев</li><li>Не привносит новый синтаксис как обертки</li><li>Не зависит от веб фреймворка</li></ul><p>И вот что получилось:</p><h3>Простейший сценарий</h3><p>Вот пример простейшего сценария, когда просто в ручке хочется сделать один sql запрос и чтобы сессия как-то сама создалась, сама открылась транзакция и само все закрылось. Мне тут не нужно обо всем этом париться. Я просто знаю, что в конце обработки запроса все это точно будет закрыто.</p><p>Функция db_session создает новую сессию с которой можно работать. Сессия будет закрыта в конце обработки запроса. Все. Вот так просто. 1 строка для получения сессии и выполняем нужные sql запросы.</p><p>А вот так выглядит несколько запросов в рамках одной сессии и транзакции:</p><p>Функция db_session не будет создавать новую сессию если она уже есть. Таким образом insert_user_profile использует ту же самую сессию и ту же транзакцию.</p><h3>Досрочное закрытие транзакции</h3><p>А что если хочется закоммитить заранее? Можно!</p><p>Или вот например такой кейс: у вас есть функция insert_something, которая используется в одной ручке, где автокоммит в конце запроса - хорошо. И вы хотите переиспользовать insert_something внутри другой ручки, в которой нужен досрочный коммит. Не нужно никак модифицировать insert_something, можно сделать так:</p><p>А еще лучше сделать вот так, как бы обернуть функцию в отдельную транзакцию:</p><p>Можно так же досрочно сделать rollback через rollback_db_session .</p><h3>Досрочное закрытие сессии</h3><p>Бывают ситуации, что нам нужно закрыть сессию, чтобы отпустить коннект, пока мы например делаем другую долгую работу. Можно сделать так:</p><p>close_db_session закрывает сессию. Когда update_something вызовет db_session он уже получит новую сессию и другой коннект.</p><h4>Конкурентное исполнение запросов</h4><p>В sqlalchemy нельзя делать 2 конкурентных запроса в одной сессии. Для этого нужно создавать отдельную сессию.</p><p>Библиотека предоставляет 2 способа чтобы можно было легко делать конкурентные запросы.</p><p>run_in_new_ctx запускает функцию в новом контексте, таким образом функция получит новую сессию. Так можно например использовать функции в gather или asyncio.create_task</p><p>Либо можно вообще использовать сессию не используя контекст вообще. Как в ручном режиме про который я рассказывал в начале</p><p>Эти способы можно комбинировать:</p><h3>Другие сценарии</h3><p>В репозитории есть примеры интеграциий в приложения. Там же можно увидеть <a href="https://github.com/krylosov-aa/context-async-sqlalchemy/tree/main/examples/fastapi_example/routes">различные сценарии, как можно пользоваться библиотекой</a>. Через эти же сценарии сама библиотека и тестируется, в контексте приложения, а не в абстракции.</p><h2>Интеграция библиотеки с приложением</h2><p>Теперь посмотрим как интегрировать эту библиотеку в свое приложение. Я хотел сделать так, чтобы это было очень просто.</p><p>Начнем как раз с создания engine и session_maker, а так же ответим на вопрос что такое connect который все время передается в функции библиотеки. За параметры соединения с базой данных отвечает DBConnect</p><p>Предполагаемое использование - глобальный инстанс, который отвечает за жизненный цикл engine и session_maker.</p><p>Он принимает на вход 2 фабрики:</p><ul><li>engine_creator - фабрика по созданию engine</li><li>session_maker_creator - фабрика по созданию session_maker</li></ul><p>Вот примеры:</p><p>host - опциональный параметр хоста базы данных к которой нужно подключиться.</p><p>Почему хост опционален и почему фабрики? Потому что либа позволяет переподключаться к бд в рантайме. Это важно, например, при работе с мастером и репликой.</p><p>У DBConnect есть еще один опциональный параметр - обработчик, который будет вызван перед созданием новой сессии. Там вы можете поместить какую угодно логику:</p><p>В конце жизни вашего приложения нужно корректно закрыть соединение. Для этого у DBConnect есть метод close</p><p>А вот всю самую важную магию по управлению сессиями и транзакциями берет на себя middleware. Ее очень просто подключить.</p><p>Вот пример для FastAPI:</p><p>Так же есть чистая ASGI middleware</p><h2>Тестирование</h2><p>Тестирование - очень важная часть разработки. Я предпочитаю тестировать с реальным живым postgresql. И в таком случае есть важная проблема, которую нужно решить - изоляция данных между тестами. И базово есть 2 подхода:</p><ul><li>удалять данные из бд между тестами. Тогда у приложения своя транзакция, у теста своя</li><li>делать общую транзакцию между тестом и приложением, чтобы делать rollback</li></ul><p>Первый подход очень удобен в отладке и иногда только с помощью такого подхода можно протестировать сложные сценарии где много транзакций открывается и закрывается. Или конкурентные запросы. Так же это "честный" способ тестирования. Мы проверяем как наше приложение работает с сессиями.</p><p>Но есть минус: долго выполняются. А все из-за очистки данных между тестами. Например это можно делать через truncate, но все равно по всем таблицам долго пробежаться.</p><p>Второй подход как раз наоборот очень быстрый за счет rollback, но не такой честный, потому что мы должны подготовить сессию и транзакцию для приложения заранее.</p><p>В своих сервисах я использую оба подхода сразу. Общая транзакция в большинстве тестов с простой логикой и меньшинство сложных тестов в отдельных транзакциях.</p><p>Библиотека предоставляет пару удобств для тестирования:</p><p>Первая из них это rollback_session - сессия, которая всегда будет откатываться в конце. Ее на самом деле в обоих видах тестов стоит использовать</p><p>А вот специально для тестов с общими транзакциями есть set_test_context и put_savepoint_session_in_ctx</p><p>Эта фикстура создаст контекст заранее. Таким образом приложение будет работать в этом контексте, а не будет создавать свое. А так же там будет лежать подготовленная сессия, которая вместо commit будет делать release save point.</p><h2>Как все работает</h2><p>Вот схема как все работает:</p><figure><img src="https://media.tproger.ru/user-uploads/134966/2025-12-09/eb183a90-8c1f-4a4f-b36a-a12e12370714.png" alt="" /><figcaption>Как все работает</figcaption></figure><p>middleware инициализирует контекст. Ваше приложение приложение обращается к этому контексту через функции библиотеки. В конце middleware закрывает все незакрытое и закрывает контекст.</p><p>Как работает middleware:</p><figure><img src="https://media.tproger.ru/user-uploads/134966/2025-12-09/919041f6-6cb3-4e81-8fec-3c87a7f1247e.png" alt="" /><figcaption>как работает middleware</figcaption></figure><p>Тот самый контекст про который шла речь это ContextVar. В нем хранится мутабельный контейнер. Как раз когда ваше приложение обращается к библиотеки для получения сессии, библиотека работает с этим контейнером. И именно потому что контейнер мутабельный можно досрочно закрывать сессии и транзакции. Middleware будет работать только с тем, что осталось незакрытым в контейнере.</p><h2>Итог</h2><p>Подведем итог. Получилась классная либа, которая помогает работать с sqlalchemy:</p><ul><li>Мало кода без дублирования</li><li>Автоматический commit или rollback, когда нет нужды вручную этим управлять</li><li>Есть возможность ручного управления сессией и транзакцией</li><li>Удобно для CRUD и удобно для сложных сценариев</li><li>Не привносит новый синтаксис как обертки</li><li>Не зависит от веб фреймворка</li><li>удобно тестировать</li></ul><p>Используйте!</p><ul><li>Библиотека доступна под MIT лицензией</li><li><a href="https://github.com/krylosov-aa/context-async-sqlalchemy">Открытый исходный код на github</a></li><li><a href="https://krylosov-aa.github.io/context-async-sqlalchemy/">Есть документация</a></li><li><a href="https://pypi.org/project/context-async-sqlalchemy/">Доступен в pypi</a></li></ul><p>Я использую эту библиотеку в реальном production приложении. Так что смело используйте в любых своих проектах и приносите фидбэк! Я открыт к улучшениям, доработкам, замечаниям!</p><p>Не забудьте поставить звезду на github, если понравился проект! Спасибо!</p>]]></content:encoded>
    </item>
    <item>
      <title>Как мигрировать на Node.js 22 без рисков: инструкция</title>
      <link>https://tproger.ru/articles/kak-migrirovat-na-node-js-22-bez-riskov--instrukciya</link>
      <comments>https://tproger.ru/articles/kak-migrirovat-na-node-js-22-bez-riskov--instrukciya?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Светлана Гринь]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-migrirovat-na-node-js-22-bez-riskov--instrukciya</guid>
      <description><![CDATA[<p>Node.js 22 стал надёжным стандартом для компаний, которым важно сохранить стабильность после завершения поддержки прежних версий. Разберём практические шаги по безопасной миграции. </p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-migrirovat-na-node-js-22-bez-riskov--instrukciya">Как мигрировать на Node.js 22 без рисков: инструкция</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Оптимизация]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Рефакторинг]]></category>
      <category><![CDATA[Node.js]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[Бэкенд]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[CI/CD]]></category>
      <category><![CDATA[Инфраструктура]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 14 Dec 2025 12:40:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Node.js 22 сегодня становится дефолтным выбором для компаний, которые откладывали обновление годами. Вокруг этой версии сформировалась зрелая экосистема, а крупные команды уже успели протестировать релиз в продакшене. Разберём, что думают разработчики о платформе и какие подводные камни вас ждут при миграции.</p><h2>Почему релиз Node.js 22 важен</h2><p>30 апреля 2025 года завершился жизненный цикл версии Node.js 18. Сообщество заранее предупреждало об этом через официальный аккаунт в X. Там напомнили разработчикам о необходимости перейти на более свежие версии — Node.js 20 или 22. Восемнадцатая версия перестала получать патчи безопасности, поэтому обновление стало критичным для поддержания стабильной работы приложений.</p><p>Наиболее надёжным вариантом стала миграция на Node.js 22, которая сейчас находится в статусе долгосрочной поддержки (LTS) и гарантирует обновления безопасности и стабильность на ближайшие годы.</p><p>Хотя релиз этой версии не выглядел революционным, он существенно изменил основу платформы. Многие возможности, которые раньше требовали внешних библиотек, теперь встроены прямо в платформу: WebSocket-клиент, стабильный fetch(), работа с файлами, Blob и URL, улучшенная совместимость ESM и CommonJS. Это уменьшает количество зависимостей, снижает вероятность уязвимостей и значительно упрощает поддержку проектов.</p><p>Помимо удобства разработки, в новой версии усилились производительность и безопасность. Обновлённый движок V8 ускоряет выполнение кода, а оптимизация старта и снижение потребления памяти делают Node.js более стабильным в высоконагруженных и serverless-сценариях. Улучшенная модель разрешений, строгие настройки TLS и расширенная поддержка AbortController повышают защиту на уровне рантайма, ограничивая последствия уязвимостей в сторонних пакетах. Это даёт компаниям возможность строить более надёжные сервисы с меньшими затратами на контроль рисков и эксплуатацию.</p><p>Node.js 22 также стал удобнее для работы гибридных команд. Стабильная интеграция ESM и CommonJS облегчает миграцию старых проектов, а унификация Web-API делает код универсальным и понятным даже для сотрудников без глубокого опыта в бэкенде. Улучшенные инструменты тестирования и диагностики повышают прозрачность разработки и снижают время на нахождение ошибок.</p><blockquote>Node.js 22 — эволюционный релиз. Он развивает ранее введённые возможности (fetch, ESM, WebSocket и др.), но не переворачивает парадигму разработки. Это укрепление уже заданного курса.</blockquote><h2>Возможности Node.js 22</h2><p><b>Расширение JavaScript и обновление V8.</b> Получив движок V8 12.x, Node.js подтянул все улучшения ECMAScript 2024. Код стал исполняться быстрее как за счёт оптимизаций в компиляторе, так и благодаря улучшенной работе с асинхронностью. Например, async/await теперь обрабатываются эффективнее, а создание структур данных, активно используемых в серверах, стало менее затратным.</p><p>С точки зрения разработчика изменения могут быть неочевидны, но приложения на реальной нагрузке выполняются быстрее, стабильнее и предсказуемее.</p><p><b>Corepack включён по умолчанию.</b> До выхода Node.js 22 разработчики сами решали, подключать ли Corepack. Теперь он активен без дополнительной настройки, и это серьёзное изменение в экосистеме. Все менеджеры пакетов контролируются единой прослойкой, что устраняет зависимость от версии, установленной глобально у разработчика или в CI.</p><p>На практике это означает, что версия менеджера пакетов становится частью проекта и перестаёт зависеть от среды. Ошибки вида «у меня работает, а у коллеги нет» заметно сокращаются. Благодаря этому процессы разработки и сборки становятся стабильнее.</p><blockquote>Corepack, как мне кажется, сильно упростит жизнь большим командам. Исчезает вечная история “а у меня Yarn другой версии” или “Pnpm не подтянулся”. Corepack берёт на себя управление версионированием менеджеров пакетов, а значит, сборки становятся более воспроизводимыми. Для корпоративных проектов это плюс, особенно если речь идёт о распределённых командах или CI/CD-конвейерах.</blockquote><p><b>WebSocket API и улучшенные Web Streams.</b> Node.js 22 внедрил нативную поддержку WebSocket API. Теперь можно создавать WebSocket-клиенты и серверы без сторонних библиотек вроде ws. Это делает код чище и ближе к браузерному API.</p><p>Параллельно были улучшены Web Streams. Работа с потоками стала предсказуемой, а инструменты вроде CompressionStream и DecompressionStream функционируют так же, как и в современных браузерах. Поддержка универсального кода — сервер + клиент — стала проще, а объём внешних зависимостей уменьшился.</p><p><b>Улучшения в работе CommonJS и ESM.</b> Node.js постепенно движется в сторону ESM, но у огромного количества проектов всё ещё используется CommonJS. В новой версии улучшена производительность смешанных проектов и сокращены ошибки при импорте модулей между двумя системами. Между ними появилось меньше «подводных камней», а значит миграция на ESM может идти постепенно, без ломки архитектуры.</p><p><b>Стабильный встроенный fetch().</b> Его реализация теперь полностью совпадает с браузерной, так что в простых кейсах можно отказаться от axios или node-fetch. Меньше зависимостей — быстрее запуск и меньше технического долга.</p><p><b>Развитие модели разрешений</b>, которая позволяет ограничивать доступ приложения к файловой системе, сети или переменным окружения прямо на уровне рантайма. Даже если зависимость уязвима, код не сможет выйти за пределы разрешённых прав. Это огромный шаг в сторону реальной безопасности.</p><blockquote>Я бы отметил более зрелую работу с Permission Model. Она уже не экспериментальная и реально помогает ограничивать доступ к файловой системе и сети. Параллельно улучшилась производительность V8, а вместе с ней и общая отзывчивость серверных приложений. Подтянули и Web-стек: стабильнее стали Web Streams, Request/Response и другие API, которые сближают Node с браузерами. Всё это не революция, но тренд на унификацию растёт.</blockquote><p><b>Расширенные возможности тестирования.</b> Node.js продолжает развивать встроенный тестовый фреймворк node:test. Теперь доступны кастомные репортеры, покрытие кода без внешних инструментов и mock timers (замена реальной работы таймеров). Это позволяет использовать встроенный тест-раннер для большинства задач, отказавшись от Jest или Vitest в простых проектах.</p><p><b>Обновления в безопасности.</b> Обновление OpenSSL — одно из самых чувствительных изменений в релизе. Поддержка старых криптоалгоритмов исключена, проверка сертификатов стала строже, а взаимодействие по TLS 1.3  стабильнее.</p><blockquote>С точки зрения безопасности рывка не произошло, но заметное движение есть: Permission Model, улучшенная работа с OpenSSL, более аккуратная валидация входящих данных. Всё это снижает риски, но полностью опасность не снимает, потому что реальная безопасность всё равно лежит в архитектуре, процессов CI/CD и культуре разработки.</blockquote><p><b>Повышенная производительность.</b> Заметные улучшения коснулись старта приложения, работы с памятью и производительности под нагрузкой. Приложения запускаются быстрее, а распределение нагрузки между worker threads стало более эффективным. Это позволит обслуживать больше запросов при тех же ресурсах и уменьшить расходы на инфраструктуру.</p><p><b>Международные стандарты и локализация.</b> Были обновлены Intl API на базе новой версии ICU. Преимущества: точные часовые пояса, поддержка новых календарей и систем чисел. Это критично для глобальных SaaS-платформ, аналитических сервисов и финтех-продуктов.</p><p>По словам Даниила Гоника, для разработчиков наиболее значимы такие изменения, как WebSocket-клиент, модульная система., обновление V8, улучшение JIT-компиляторов, добавление новых возможностей JS и улучшение встроенного test-раннера.</p><h2>Как безопасно мигрировать на Node.js 22</h2><p>Переход лучше начинать с <b>аудита и подготовки окружения</b>. Сначала стоит убедиться, что все зависимости поддерживают Node.js 22. Особенно это касается библиотек, которые используют нативные модули, криптографию и WebSockets. Проверка совместимости позволит избежать неожиданностей вроде ошибок компиляции или падений при запуске.</p><p>После этого нужно прогнать <b>тесты</b>. Даже минимальный набор позволит выявить проблемы, связанные с изменениями в ESM/CJS, WebSocket API или OpenSSL.</p><p>Само <b>обновление среды</b> зависит от выбранного инструмента. Через nvm или n процесс занимает секунды, а для Docker достаточно указать новый базовый образ. Если проект использует CI/CD, стоит уделить внимание Corepack: теперь он активен всегда, что может изменить поведение сборки.</p><p>После обновления полезно <b>проверить логи</b> и внимательно <b>изучить предупреждения</b>. Большинство проблем решается установкой последних версий библиотек, иногда — правкой конфигурации TLS или обновлением менеджера пакетов.</p><p>Обновление стоит внедрять поэтапно, начиная со staging или частичного продакшена, и держать готовность к откату.</p><blockquote>Я обычно советую подход двухконтурного обновления. Сначала поднять проект на 22-ю версию в отдельной среде, включить максимальный объём логов, запустить тесты и прогнать реальные сценарии. Потом обновить линтеры, сборщики и самые старые пакеты, чтобы убрать накопленные за годы предупреждения. И только когда всё стабильно, имеет смысл переключать продакшен. По сути, обновление Node нужно делать так же аккуратно, как обновление облачных сервисов: через изоляцию, наблюдаемость и бэкап-стратегию.</blockquote><blockquote>В Node.js 22 удалены некоторые устаревшие, малоиспользуемые функции, поэтому при переходе может потребоваться рефакторинг мест, где они использовались. Следует проверить депрекейты: Node.js 22 помечает ряд старых возможностей как устаревшие и предлагает альтернативы. Необходимо убедиться, что все библиотеки и пакеты, используемые проектом, поддерживают новую версию Node.js.<br />При скачке сразу с 18/20 на 22 некоторые зависимости могут оказаться несовместимыми с обновлённым движком V8 или новыми APIs — может понадобиться их обновление до последних версий.</blockquote><h2>Кому стоит подождать с переходом</h2><p>Переход на Node.js 22 подходит не всем проектам. В некоторых ситуациях разумнее подождать, чтобы избежать регрессий и поломок в продакшене. Вот кому стоит повременить с переходом:</p><ul><li>Тем, кто использует инструменты сборки или менеджеры пакетов, которые ещё не совместимы с Node.js 22 и могут выдавать ошибки или не работать вовсе.​</li><li>Командам, которые работают на старых версиях ОС. Известны проблемы совместимости с macOS 10.14 и ниже, а также возможны ошибки на Windows при миграции старых приложений.​</li><li>Тем, чьи CI/CD, контейнеры или Docker-образцы завязаны на конкретные версии Node.js и npm. Переход на 22-ю версию требует много регрессионного тестирования.​</li><li>Проектам с критически важными C++-добавками. Смена major-версии влечёт за собой обновление бинарных интерфейсов, что может вызывать ошибки при компиляции нативных модулей.</li><li>Пользователям определённых интеграций. Для некоторых версий MongoDB‑драйверов зафиксированы фатальные баги после перехода на конкретные промежуточные версии Node.js 22.x.​</li><li>Если вы используете проекты, которые сами рекомендуют Node.js 18 или 20, а обновление их зависимостей под 22 только планируется.</li></ul><blockquote>В продакшене чаще всего проблемы возникают не из-за самих изменений в платформе, а из-за того, как эти изменения проявляются в реальных проектах. Где-то обновился V8 и стал вести себя строже, где-то повылезали deprecated-модули, а где-то просто сломались сборщики или старые зависимости. Многие команды до сих пор живут на Webpack 4, Express 4 или TypeORM старых версий: вот они первыми столкнутся со сложностями.</blockquote><h2>Что дальше</h2><p>Среди будущих трендов в экосистеме <a href="http://node.js/">Node.js</a> Максим Захаренко выделяет следующие: <i>«Первое — постепенное сближение Node с Web-стеком, чтобы код становился максимально универсальным. Второе — рост влияния Bun и Deno, которые будут подталкивать Node к более агрессивной оптимизации. И третье — всё более активная интеграция с AI-инструментами, особенно в DevTools и в цепочках генерации кода»</i>.</p><blockquote>Всё больше веб-API внедряются в Node.js (fetch, WebSocket, EventTarget). Этот тренд будет продолжаться. ESM становится стандартом, поддержка будет расширяться, CommonJS постепенно уйдёт в прошлое. Расширяется WASI и поддержка WASM-модулей. Node.js движется в сторону мульти-языковой среды. Модель прав доступа и другие sandbox-механизмы также продолжат развиваться. Кроме того, в версии Node.js 22.5.0 экспериментально добавлен встроенный модуль SQLite (через –experimental-sqlite). Это важное уточнение: в релизе 22.0.0 SQLite отсутствовал.</blockquote><p>Даниил Гоник хотел бы увидеть в будущих релизах стабильную и удобную модель разрешений, возможность require() для ESM без флагов, улучшения в DevX: поддержка TS «из коробки», больше инструментов в ядре, расширение SEA (Single Executable Apps) и встроенные механизмы верификации зависимостей (подписи, integrity).</p><h2>Выводы</h2><p>Node.js 22 делает приложения быстрее, безопаснее и совместимее с Web API, улучшает работу с памятью и снижает зависимость от глобальных инструментов. Хотя переход требует подготовки, он не представляет серьёзных рисков, если следовать базовой процедуре: проверить зависимости, прогнать тесты и обновить среду постепенно. Если инфраструктура современная, а стек устойчивый, переход на Node.js 22 принесёт ощутимые преимущества как в скорости работы, так и в удобстве разработки.</p>]]></content:encoded>
    </item>
    <item>
      <title>Go против Rust против Zig: какой язык для чего нужен</title>
      <link>https://tproger.ru/articles/go-protiv-rust-protiv-zig--kakoj-yazyk-dlya-chego-nuzhen</link>
      <comments>https://tproger.ru/articles/go-protiv-rust-protiv-zig--kakoj-yazyk-dlya-chego-nuzhen?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Валерия Турчак]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/go-protiv-rust-protiv-zig--kakoj-yazyk-dlya-chego-nuzhen</guid>
      <description><![CDATA[<p>Это попытка понять философию языков и определить, какой язык ближе лично вам.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/go-protiv-rust-protiv-zig--kakoj-yazyk-dlya-chego-nuzhen">Go против Rust против Zig: какой язык для чего нужен</a>»</p>]]></description>
      <category><![CDATA[Языки программирования]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Rust]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 12 Dec 2025 10:05:36 GMT</pubDate>
      <content:encoded><![CDATA[<p><i>Это перевод статьи для Tproger. Автор оригинала делится опытом изучения трёх системных языков программирования и размышляет, почему каждый из них сделал именно такие компромиссы в дизайне. Это попытка понять философию языков и определить, какой подход ближе лично вам.</i></p><p>Недавно я понял, что вместо того, чтобы использовать “правильный инструмент для задач” я просто использую инструменты, которые сказали на работе — и это определило языки программирования, которые я знаю. Последние пару месяцев я потратил много времени на эксперименты с языками, которые не использую в рабочих проектах. Цель не была в том, чтобы стать экспертом — я хотел сформировать мнение о том, для чего каждый язык действительно хорош.</p><p>Языки программирования отличаются по многим параметрам, и сравнивать их сложно, не скатываясь к совершенно скучному или бесполезному выводу “везде есть компромиссы”. Конечно, компромиссы есть всегда. Интересный вопрос — почему этот конкретный язык выбрал именно такой набор компромиссов?</p><p>Этот вопрос важен для меня, потому что я не хочу выбирать язык по чек-листу, будто покупаю увлажнитель воздуха. Меня волнует создание софта и мои инструменты. Делая свои компромиссы, языки выражают набор ценностей. Я хочу понять, какие ценности резонируют со мной.</p><p>Этот вопрос также помогает прояснить разницу между языками, которые на первый взгляд сильно пересекаются по возможностям. Судя по количеству вопросов статей вроде “Go или Rust” и “Rust или Zig”, люди тоже не понимают, что происходит. Сложно запомнить, что язык X лучше для веб-сервисов, потому что у него есть фичи a, b и c, а у языка Y только a и b. Гораздо проще запомнить, что язык X лучше для веб-сервисов, потому что язык Y создан человеком, который ненавидит интернет (условно) и считает, что нужно вырубить всю сеть.</p><p>Я собрал здесь мнение о трёх языках, с которыми недавно экспериментировал: Go, Rust и Zig. Я попытался превратить свой опыт с каждым языком в общий вывод о том, что этот язык представляет из себя и насколько хорошо реализует свои ценности. Да, это упрощение, но кристаллизация упрощённых предубеждений — именно то, что я здесь и делаю.</p><h2>Go: минимализм для корпораций</h2><p>Go выделяется своим минимализмом. Его называют “современным C”. Go не похож на C, потому что у него есть сборщик мусора и полноценная среда выполнения, но он похож на C тем, что весь язык помещается в голове.</p><p>Весь язык помещается в голове, потому что в Go очень мало возможностей. Долгое время Go был известен отсутствием дженериков. Их наконец добавили в Go 1.18, но только после 12 лет, в течение которых люди умоляли это сделать. Другие возможности, обычные для современных языков — например, размеченные объединения (tagged unions) или синтаксический сахар для обработки ошибок — в Go так и не появились.</p><p>Похоже, команда разработки Go ставит высокую планку для добавления новых возможностей. В результате получился язык, который заставляет писать много шаблонного кода для реализации логики, которую на другом языке можно выразить короче. Но в результате также получился язык, стабильный во времени и лёгкий для чтения.</p><p>Ещё один пример минимализма Go — тип slice. И в Rust, и в Zig есть slice, но это толстые указатели (fat pointers) и только они. В Go slice — это толстый указатель на непрерывную последовательность в памяти, но slice также может расти. То есть он объединяет функциональность типа Vec&lt;T&gt; из Rust и ArrayList из Zig. Кроме того, поскольку Go управляет памятью за вас, он сам решает, где будет жить память вашего slice — в стеке или куче. В Rust или Zig вам придётся сильно задуматься, где живёт ваша память.</p><p>История происхождения Go, насколько я понимаю, примерно такая: Роб Пайк устал ждать компиляции проектов на C++ и устал от ошибок, которые другие программисты Google делали в тех же проектах на C++. Поэтому Go прост там, где C++ перегружен. Это язык для рядовых программистов, спроектированный быть достаточным для 90% задач и при этом простым для понимания, даже (или особенно) при написании конкурентного кода.</p><p>Я не использую Go на работе, но думаю, что должен бы. Go минималистичен ради корпоративного сотрудничества. Я не считаю это недостатком — создание софта в корпоративной среде имеет свои вызовы, которые Go решает.</p><h2>Rust: максимализм ради безопасности</h2><p>Если Go минималистичен, то Rust максималистичен. Популярный слоган Rust — “абстракции с нулевой стоимостью” (zero-cost abstractions). Я бы дополнил: “абстракции с нулевой стоимостью, и их очень много!”</p><p>У Rust репутация сложного для изучения языка. Я согласен с Джейми Брэндоном, который пишет, что Rust делает сложным не система времён жизни (lifetimes), а количество концепций, запиханных в язык. Я не первый, кто приводит в пример этот конкретный комментарий на GitHub, но он идеально показывает концептуальную плотность Rust:</p><p>Тип Pin&lt;&amp;LocalType&gt; реализует Deref, но не реализует DerefMut. Типы Pin и &amp; помечены #[fundamental], так что возможна реализация DerefMut для Pin&lt;&amp;LocalType&gt;&gt;. Вы можете использовать LocalType == SomeLocalStruct или LocalType == dyn LocalTrait, и можете привести Pin&gt; к Pin&gt;. (Действительно, два слоя Pin!!) Это позволяет создать пару “умных указателей, реализующих CoerceUnsized, но имеющих странное поведение” на стабильной версии (Pin&lt;&amp;SomeLocalStruct&gt; и Pin&lt;&amp;dyn LocalTrait&gt; становятся умными указателями со «странным поведением», и они уже реализуют CoerceUnsized).</p><p>Конечно, Rust не пытается быть максималистичным просто так, как Go пытается быть минималистичным. Rust сложный, потому что пытается достичь двух целей — безопасности и производительности — которые частично противоречат друг другу.</p><p>Цель производительности понятна сама по себе. Что означает “безопасность” — менее очевидно, по крайней мере для меня (хотя, может быть, я просто слишком долго писал на Python). “Безопасность” означает “безопасность памяти” — идею, что вы не должны иметь возможность разыменовать невалидный указатель или сделать двойное освобождение памяти. Но это также означает больше. “Безопасная” программа избегает всего неопределённого поведения (undefined behavior, или UB).</p><p>Что такое ужасное UB? Лучший способ понять это — вспомнить, что для любой работающей программы ЕСТЬ СУДЬБЫ ХУЖЕ СМЕРТИ. Если в программе что-то идёт не так, немедленное завершение — это прекрасно! Потому что альтернатива, если ошибка не поймана — ваша программа переходит в сумеречную зону непредсказуемости, где её поведение может определяться тем, какой поток выиграет следующую гонку данных, или тем, какой мусор оказался по конкретному адресу памяти. Теперь у вас хайзенбаги и дыры в безопасности. Очень плохо.</p><p>Rust пытается предотвратить UB без потери производительности во время выполнения, проверяя всё во время компиляции. Компилятор Rust умный, но не всеведущий. Чтобы проверить ваш код, ему нужно понимать, что код будет делать во время выполнения. Поэтому в Rust есть выразительная система типов и множество трейтов, которые позволяют объяснить компилятору то, что в другом языке было бы просто видимым поведением кода во время работы.</p><p>Это делает Rust сложным, потому что вы не можете просто взять и сделать что-то! Вы должны узнать, как Rust это называет — найти нужный трейт или что-то ещё — и реализовать это так, как Rust ожидает. Но если вы это делаете, Rust может дать гарантии о поведении вашего кода, которые другие языки не дают, а это в зависимости от приложения может быть критично. Он также может давать гарантии о чужом коде, что делает использование библиотек в Rust простым и объясняет, почему проекты на Rust имеют почти столько же зависимостей, сколько проекты в экосистеме JavaScript.</p><h2>Zig: свобода и контроль</h2><p>Из трёх языков Zig самый новый и наименее зрелый. На момент написания статьи Zig на версии 0.14. У его стандартной библиотеки почти нет документации, и лучший способ научиться её использовать — читать исходный код напрямую.</p><p>Не знаю, правда ли это, но мне нравится думать о Zig как о реакции одновременно на Go и Rust. Go прост, потому что скрывает детали того, как работает компьютер. Rust безопасен, потому что заставляет прыгать через свои обручи. Zig освободит вас! В Zig вы контролируете вселенную, и никто не может указывать, что делать.</p><p>И в Go, и в Rust выделить объект в куче просто — достаточно вернуть указатель на структуру из функции. Выделение памяти неявное. В Zig вы выделяете каждый байт сами, явно. (В Zig ручное управление памятью.) У вас больше контроля, чем даже в C: чтобы выделить байты, нужно вызвать alloc() на конкретном виде аллокатора, то есть вы должны выбрать лучшую реализацию аллокатора для вашего случая.</p><p>В Rust создать изменяемую глобальную переменную настолько сложно, что на форумах идут длинные обсуждения, как это сделать. В Zig вы просто создаёте её, без проблем.</p><h3>Неопределённое поведение всё ещё важно в Zig</h3><p>Zig называет его “нелегальным поведением” (illegal behavior). Он пытается обнаружить его во время выполнения и обрушить программу, когда это происходит. Для тех, кого беспокоит стоимость таких проверок по производительности, Zig предлагает четыре разных “режима релиза” на выбор при сборке программы. В некоторых проверки отключены. Идея в том, что вы можете запустить программу достаточно раз в проверяемых режимах, чтобы иметь разумную уверенность: в непроверяемой сборке нелегального поведения не будет. Это кажется мне очень прагматичным дизайном.</p><p>Ещё одно различие между Zig и двумя другими языками — отношение Zig к объектно-ориентированному программированию. ООП давно не в моде, и Go, и Rust избегают наследования классов. Но в Go и Rust достаточно поддержки других идиом ООП, чтобы вы могли построить программу как граф взаимодействующих объектов, если захотите. В Zig есть методы, но нет приватных полей структур и нет языковой возможности для полиморфизма во время выполнения (динамической диспетчеризации), хотя std.mem.Allocator просто умирает стать интерфейсом. Насколько я могу судить, эти исключения намеренны; Zig — язык для дата-ориентированного дизайна (data-oriented design).</p><p>Ещё одна вещь, которую я хочу сказать, потому что она открыла мне глаза: может показаться безумием создавать язык программирования с ручным управлением памятью в 2025 году, особенно когда Rust показал, что сборка мусора не нужна и компилятор может всё сделать за вас. Но это дизайнерский выбор, тесно связанный с выбором исключить возможности ООП. В Go, Rust и множестве других языков вы обычно выделяете маленькие кусочки памяти за раз для каждого объекта в графе объектов. У вашей программы тысячи маленьких скрытых malloc() и free(), и, следовательно, тысячи разных времён жизни. Это RAII. В Zig может показаться, что ручное управление памятью потребует много утомительной, подверженной ошибкам работы, но это так только если вы настаиваете на привязке выделений памяти к каждому маленькому объекту. Вместо этого вы можете просто выделять и освобождать большие куски памяти в определённых разумных точках программы (например, в начале каждой итерации цикла событий) и использовать эту память для данных, с которыми работаете. Именно этот подход и поощряет Zig.</p><p>Многие люди не понимают, зачем нужен Zig, если уже есть Rust. Дело не только в том, что Zig пытается быть проще. Думаю, разница более важная. Zig хочет, чтобы вы вырезали ещё больше объектно-ориентированного мышления из своего кода.</p><p>У Zig весёлая, подрывная атмосфера. Это язык для разрушения корпоративной классовой иерархии (объектов). Это язык для мегаломанов и анархистов. Мне он нравится. Надеюсь, он скоро выйдет в стабильный релиз, хотя текущий приоритет команды Zig — переписать все свои зависимости. Не исключено, что они попытаются переписать ядро Linux, прежде чем мы увидим Zig 1.0.</p><p>Go — для командной работы и быстрой разработки, Rust — для критически важных систем, где нужны максимальные гарантии, Zig — для тех, кто хочет полного контроля и готов от ООП отказаться в пользу дата-ориентированного подхода. Выбор зависит не от списка фич, а от того, какая философия вам ближе.</p>]]></content:encoded>
    </item>
    <item>
      <title>Обновление urllib3 доказало — DeprecationWarning мертв. Python-экосистема его просто не видит</title>
      <link>https://tproger.ru/news/obnovlenie-urllib3-dokazalo---deprecationwarning-mertv--python-ekosistema-ego-prosto-ne-vidit</link>
      <comments>https://tproger.ru/news/obnovlenie-urllib3-dokazalo---deprecationwarning-mertv--python-ekosistema-ego-prosto-ne-vidit?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/obnovlenie-urllib3-dokazalo---deprecationwarning-mertv--python-ekosistema-ego-prosto-ne-vidit</guid>
      <description><![CDATA[<p>urllib3 показал, что DeprecationWarning не работает: Python игнорирует устаревшие API, из-за чего ломаются даже крупные проекты</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/obnovlenie-urllib3-dokazalo---deprecationwarning-mertv--python-ekosistema-ego-prosto-ne-vidit">Обновление urllib3 доказало — DeprecationWarning мертв. Python-экосистема его просто не видит</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Фреймворки и библиотеки]]></category>
      <category><![CDATA[Kubernetes]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 12 Dec 2025 06:44:11 GMT</pubDate>
      <content:encoded><![CDATA[<p>Разработчик <i>Сэт Ларсон</i> <a href="https://sethmlarson.dev/deprecations-via-warnings-dont-work-for-python-libraries">рассказал</a> о неожиданном эффекте, с которым столкнулась команда <b>urllib3</b> — одной из самых популярных библиотек в Python-экосистеме.</p><p>В версии <b>urllib3 2.6.0</b> разработчики удалили несколько API, которые считались проблемными еще с 2019 года и были официально помечены как устаревшие с 2022-го.</p><p>Все было сделано «по правилам»: предупреждения в документации, changelog, отдельные сообщения через DeprecationWarning при каждом использовании устаревших методов.</p><p>Казалось, что сигнал более чем <b>очевидный</b>. Но на практике это не сработало.</p><p>После релиза выяснилось, что удаление API стало сюрпризом даже для активно поддерживаемых проектов — зависимых библиотек и крупных клиентов.</p><h2>Почему предупреждения никто не заметил</h2><p>Ключевая проблема в том, что <b>DeprecationWarning в Python по умолчанию отключен</b>. Он находится в списке предупреждений, которые интерпретатор просто игнорирует, если разработчик явно не включил их показ.</p><p>В итоге ситуация выглядела так: API годами «кричал» о своей устарелости, но его никто не слышал.</p><p>Когда методы удалили, пользователи и сопровождающие популярных библиотек — Kubernetes-клиента, Fastly, Airflow — столкнулись с поломками и неожиданными ошибками.</p><p>По словам Ларсона, обратная связь была однозначной: разработчики не видели предупреждений и не понимали, что API вот-вот исчезнет. В результате команде urllib3 пришлось <b>срочно вернуть удаленные методы обратно</b> и выпустить исправляющий релиз.</p><h2>Предупреждение есть, эффекта нет</h2><p>Вывод автора жесткий: <b>DeprecationWarning в текущем виде не работает для Python-библиотек</b>. Он формально существует, но экосистема его просто не воспринимает как сигнал к действию.</p><p>Парадокс в том, что сам механизм warnings в Python удобный и встроенный прямо в язык. Но именно DeprecationWarning оказался слишком «вежливым» — он не мешает, не ломает код и потому остается незамеченным.</p><h2>Какие есть варианты выхода</h2><p>Ларсон рассматривает несколько возможных путей:</p><ul><li>создавать собственные предупреждения на базе UserWarning, которые не игнорируются по умолчанию;</li><li>отказаться от длительных периодов устаревания и делать более частые мажорные релизы по SemVer, как это принято в криптографических библиотеках;</li><li>менять культуру работы с предупреждениями в Python — но это долгий и малореалистичный путь.</li></ul><h2>Что это значит для экосистемы</h2><p>История с urllib3 показала: даже в зрелой и массовой экосистеме стандартные механизмы могут перестать выполнять свою функцию. DeprecationWarning задумывался как мягкий способ предупредить пользователей, но на практике он стал «мертвым письмом».</p><p>Для разработчиков библиотек это тревожный сигнал: если вы полагаетесь только на стандартные предупреждения, велика вероятность, что их просто никто не увидит — до тех пор, пока API не исчезнет и все не сломается.</p>]]></content:encoded>
    </item>
    <item>
      <title>5 опенсорс-инструментов для повседневной работы разработчика</title>
      <link>https://tproger.ru/articles/5-opensors-instrumentov-dlya-povsednevnoj-raboty-razrabotchika</link>
      <comments>https://tproger.ru/articles/5-opensors-instrumentov-dlya-povsednevnoj-raboty-razrabotchika?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Валерия Турчак]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/5-opensors-instrumentov-dlya-povsednevnoj-raboty-razrabotchika</guid>
      <description><![CDATA[<p>Для работы с видео, паролями, серверами, торрентами и защиты экрана от любопытных глаз.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/5-opensors-instrumentov-dlya-povsednevnoj-raboty-razrabotchika">5 опенсорс-инструментов для повседневной работы разработчика</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Парсинг]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Windows]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[macOS]]></category>
      <category><![CDATA[Бэкенд]]></category>
      <category><![CDATA[YouTube]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Видеоконтент]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 11 Dec 2025 12:50:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>Рабочий день программиста состоит не только из написания кода. Нужно управлять серверами, скачивать видео для обучения, хранить секреты проектов, работать с торрент-архивами документации и защищать конфиденциальные данные на экране. Для каждой из этих задач есть готовые решения, но часто они либо платные, либо требуют облачной подписки, либо закрыты.</p><p>Мы собрали пять свободных инструментов, которые решают типичные задачи разработчика: от скачивания видео с любых сайтов до защиты от подглядывающих коллег. Все они работают локально или self-hosted, не отправляют данные в облако и распространяются с открытым исходным кодом.</p><p>Больше подобных находок — в тг-канале <a href="https://t.me/+P6xe2tVbQWU2NDhi">Инструменты программиста</a>. Там каждый день появляются свежие CLI-утилиты, GUI-приложения, библиотеки и сервисы для разработки. Всё протестировано, с примерами использования и ссылками на репозитории.</p><h2>GUI для скачивания видео: yt-channel-downloader</h2><p><a href="https://github.com/hyperfield/yt-channel-downloader/">yt-channel-downloader</a> — графическое приложение для скачивания видео с YouTube и любых других сайтов, где есть видеоконтент. Это не только видеохостинги: если на странице есть видео, приложение попытается его скачать.</p><p>Под капотом работает связка из трёх Python-библиотек: yt-dlp для универсального парсинга, scrapetube для работы с каналами и плейлистами, pytube как вспомогательный инструмент. Поверх этого — кроссплатформенный графический интерфейс для Windows, macOS и Linux.</p><p>Как это работает: вводите ссылку на видео, плейлист или целый канал. Приложение подтягивает список доступных роликов и даёт выбрать, что именно качать — целиком или выборочно. Можно скачать только аудиодорожку или выбрать конкретное качество видео.</p><figure><img src="https://media.tproger.ru/user-uploads/99854/2025-12-11/638e1ddb-0815-4e1a-8919-178e91ef38d5.jpeg" alt="" /></figure><p>Полезные особенности:</p><ul><li>Вход в аккаунт YouTube прямо из приложения. Это позволяет скачивать приватные ролики, доступные только по ссылке или для авторизованных пользователей. Куки хранятся в локальном конфиге и автоматически очищаются при выходе из аккаунта.</li><li>Пометка уже скачанных файлов. Не нужно вручную проверять, что уже есть на диске.</li><li>Ограничение параллельных потоков. Если качаете большой плейлист, можно задать лимит одновременных загрузок, чтобы очередь не подвисала и не перегружала канал.</li></ul><p>Для работы нужен установленный ffmpeg — он используется для конвертации и склейки потоков. Для пользователей Windows доступен <a href="https://github.com/hyperfield/yt-channel-downloader/releases">готовый инсталлятор в разделе Releases</a> (размещён на SourceForge).</p><p>Код и инструкции по установке — <a href="https://github.com/hyperfield/yt-channel-downloader/">на GitHub</a>. В планах у автора: поддержка скачивания YouTube Shorts, поиск по полученному списку видео, более наглядный прогресс-бар, история загрузок и расширенная поддержка других видеоплощадок.</p><h2>gopass — менеджер паролей для разработчиков</h2><p><a href="https://github.com/gopasspw/gopass">gopass</a> — консольный менеджер паролей, заточенный под командную работу и версионирование. Все секреты хранятся в виде файлов, шифруются через GPG и версионируются в Git. Вы можете держать их локально, синхронизировать через любой git-ремоут (GitHub, GitLab, собственный сервер) и при этом всегда иметь историю изменений.</p><p>Рабочий цикл выглядит консольно и привычно для разработчиков. Из терминала вы листаете хранилище командой gopass ls, смотрите конкретный пароль через gopass show, генерируете новый — gopass generate. Копирование в буфер обмена тоже работает из командной строки, что удобно для скриптов и автоматизации.</p><figure><img src="https://media.tproger.ru/user-uploads/99854/2025-12-11/a7518a77-b4b1-47a5-8b0f-1e4bcb19061c.jpeg" alt="" /></figure><p>Поверх базовой функциональности есть плагины:</p><ul><li>gopass-bridge — интеграция с браузером. Позволяет автоматически заполнять формы входа без копирования паролей вручную.</li><li>Помощь с Git-кредами. gopass может выступать credential helper для Git, так что пароли от репозиториев тоже хранятся зашифрованными и версионируются.</li><li>Проверка через Have I Been Pwned. Можно проверить, не утекли ли ваши пароли в публичные базы.</li></ul><p>GPG обеспечивает асимметричное шифрование: секреты зашифрованы вашим публичным ключом, приватная часть не покидает машину. Если работаете в команде, достаточно добавить GPG-ключи коллег в хранилище — каждый сможет расшифровать общие секреты своим приватным ключом. При этом никто не видит приватных ключей других участников.</p><p>gopass написан на Go, поэтому работает на macOS, Linux и Windows без дополнительных зависимостей. Настройка сводится к созданию git-репозитория с зашифрованными файлами и клонированию его на рабочие машины. Один репозиторий — доступ с любого устройства.</p><p><a href="https://github.com/gopasspw/gopass">Код в репозитории</a>, документация подробная, есть примеры для всех основных сценариев использования.</p><h2>Self-hosted SSH-клиент: Termix</h2><p><a href="https://github.com/Termix-SSH/Termix">Termix</a> — полностью опенсорсная и self-hosted альтернатива Termius для управления серверами по SSH через единый веб-интерфейс. Разворачивается в Docker как бэкенд, синхронизируется с клиентами под веб, Windows, Linux, macOS, iOS и Android.</p><p>Ключевые возможности:</p><ul><li>SSH-терминал с вкладками и сплитами. Можно открыть до 4 панелей одновременно, переключаться между сессиями, кастомизировать тему оформления и шрифты. Всё работает через браузер или нативное приложение.</li><li>SSH-туннели с автопереподключением. Настраиваете туннель один раз, система сама восстанавливает соединение при обрывах и отслеживает состояние туннелей в реальном времени.</li><li>Файловый менеджер поверх SSH. Можно просматривать и редактировать код прямо в интерфейсе, смотреть картинки, слушать аудио, проигрывать видео, загружать и выгружать файлы, выполнять операции копирования, перемещения, удаления — всё без отдельного SFTP-клиента.</li><li>Менеджер хостов. Организация серверов по тегам и папкам, автоматическая заливка SSH-ключей на хосты, безопасное хранение логинов и паролей в зашифрованной базе.</li><li>Мониторинг. Для любого подключённого сервера можно посмотреть загрузку CPU, память, диск, сеть, аптайм и системную информацию. Есть дашборд с общим обзором по всем хостам.</li></ul><p>Под капотом: веб-клиент собран на React + Tailwind + Shadcn, бэкенд работает с зашифрованной базой SQLite, автоматическая настройка SSL-сертификатов, вход через OIDC и двухфакторная аутентификация (TOTP). Интерфейс поддерживает несколько языков.</p><p>Проект распространяется под Apache 2.0. Основной способ установки — docker-compose с томом для данных, всё настраивается за пару минут. Для десктопа и мобильных устройств доступны нативные сборки и приложения в официальных сторах под все основные платформы.</p><p><a href="https://github.com/Termix-SSH/Termix">Код в репозитории</a>, на скриншотах видно, как выглядит интерфейс — аккуратно, функционально, без лишних элементов.</p><figure><img src="https://media.tproger.ru/user-uploads/99854/2025-12-11/ae32f5b2-ef82-4e08-9018-270c5eaccfa6.jpg" alt="" /></figure><h2>TUI-клиент для торрентов: Torrra v2</h2><p><a href="https://github.com/stabldev/torrra">Torrra</a> — TUI-клиент для поиска и скачивания торрентов прямо из консоли, без браузера и без отдельного GUI-приложения. Написан на Python, интерфейс собран на библиотеке Textual, так что всё выглядит аккуратно и отзывчиво даже в терминале.</p><p>Можно подключаться к своим индексаторам Jackett или Prowlarr, смотреть результаты поиска и выбирать, чем качать. Есть два режима: через встроенный движок на базе libtorrent или передать magnet-ссылку во внешний торрент-клиент (Transmission, qBittorrent и так далее).</p><p>Автор утверждает, что во второй версии серьёзно ускорил UI, улучшил навигацию по спискам, прокачал поиск и добавил возможность работы с несколькими торрентами одновременно. Плюс почистил интеграцию с индексаторами и отполировал раскладку интерфейса — теперь всё помещается в стандартное окно терминала без скроллинга.</p><p>Установить можно несколькими способами:</p><ul><li>Через pipx: pipx install torrra</li><li>Из AUR для пользователей Arch Linux</li><li>Через Homebrew на macOS</li><li>Docker-образ для изолированного запуска</li><li>Готовые бинарники под Linux, macOS и Windows</li></ul><p>После установки минимальный сценарий работы такой: поднимаете Jackett или Prowlarr (это отдельные сервисы для агрегации торрент-индексаторов), запускаете</p><p>Дальше стрелками ходите по списку результатов, Enter — начать скачивание, p — пауза, r — продолжить, q — выйти из программы.</p><p>Поведение можно подкрутить через файл config.toml: задать дефолтные индексаторы, пути для сохранения файлов, какие клиенты использовать для загрузки, чтобы каждый раз не вбивать одно и то же в аргументах командной строки.</p><p>Проект кроссплатформенный (Linux/macOS/Windows) и активно развивается: есть подробная документация, регулярные релизы, автор отвечает на issues. <a href="https://github.com/stabldev/torrra">Код в репозитории</a>, на видео можно посмотреть демонстрацию работы.</p><h2>Защита от подглядывания: EyesOff для macOS</h2><p><a href="https://github.com/YM2132/EyesOff">EyesOff</a> — приложение для macOS, которое следит через веб-камеру и предупреждает, когда кто-то подглядывает в ваш экран. Актуально для работы в опенспейсах, коворкингах или просто дома, когда не хочется, чтобы кто-то читал ваш код или переписку через плечо.</p><p>Написано на Python + PyQt, модель распознавания лиц крутится локально на вашем Mac — ничего не уходит в облако, никакие кадры не сохраняются. Есть три режима оповещения на выбор:</p><ul><li>Попап на экране — появляется окно с предупреждением, что кто-то смотрит.</li><li>Системная нотификация — более деликатный вариант, уведомление в углу экрана.</li><li>Автозапуск приложения — можно настроить, чтобы автоматически запускалась блокировка экрана или любое другое приложение.</li></ul><p>Автор написал <a href="https://ym2132.github.io/building_EyesOff_part2_model_training">подробный разбор</a> того, как тренировал модель детекции. Интересный момент: он оптимизировал accuracy не в среднем по всем дистанциям, а конкретно для mid-range (~1-2 метра) — именно там обычно стоят любопытные коллеги. На близких дистанциях (менее метра) и дальних (более трёх метров) точность может быть ниже, но это компромисс ради производительности и практичности.</p><p>Есть одно ограничение: приложение пока детектит просто наличие лиц в кадре, а не направление взгляда. То есть если человек в кадре, но смотрит в сторону или на свой телефон, EyesOff всё равно сработает. Автор обещает доработать определение направления взгляда в следующих версиях, но для большинства сценариев текущей логики достаточно.</p><p>Для параноиков и тех, кто работает с конфиденциальными данными в публичных местах, это полезный инструмент. Код открыт, можно посмотреть, как именно работает детекция, и убедиться, что никакие данные не утекают.</p><p>Все пять инструментов объединяет один принцип: контроль над своими данными. Вы не зависите от подписок, облачных сервисов или закрытых платформ. Каждый из них решает конкретную задачу, делает это хорошо и не требует доверять кому-то свои пароли, SSH-ключи или видео с камеры. Код открыт, можно проверить, как всё устроено, и при желании — доработать под свои нужды.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как использовать асинхронные вьюхи в Django 5.1 с примерами кода</title>
      <link>https://tproger.ru/articles/django-5-1--asinhronnye-vyuhi--migracii-i-drugie-osobennosti-reliza</link>
      <comments>https://tproger.ru/articles/django-5-1--asinhronnye-vyuhi--migracii-i-drugie-osobennosti-reliza?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Денис Кудерин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/django-5-1--asinhronnye-vyuhi--migracii-i-drugie-osobennosti-reliza</guid>
      <description><![CDATA[<p>Разберитесь с асинхронным программированием в Django 5.1: работа с async-вьюхами, ORM-запросами и системой миграций. Готовые примеры кода, решение типичных ошибок и лучшие практики для веб-разработчиков.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/django-5-1--asinhronnye-vyuhi--migracii-i-drugie-osobennosti-reliza">Как использовать асинхронные вьюхи в Django 5.1 с примерами кода</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Django]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 07 Dec 2025 12:10:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>В августе 2024 состоялся релиз Django 5.1. Хотя на уже доступны более новые версии, например, Django 5.2 LTS, версия 5.1 остается актуальной и полностью поддерживаемой. Это делает её стабильным выбором для многих проектов в активной разработке.</p><p>Именно этот релиз завершил важный этап стабилизации асинхронных возможностей фреймворка. Он поддерживает Python версий с 3.10 по 3.13, что покрывает потребности большинства разработчиков.</p><p>Асинхронность в Django прошла долгий путь: начало было положено в версии 3.0 с базовой поддержкой ASGI, в Django 4.0 появились асинхронные ORM-запросы. В версии 5.1 этот инструмент окончательно сформировался для высокопроизводительных приложений, и его успели проверить «в боевых условиях» много разработчиков.</p><h2>Зачем вообще нужна асинхронность?</h2><figure><img src="https://media.tproger.ru/user-uploads/133848/2025-11-14/6f0770e3-862f-4c36-9820-0b672bb07d6b.png" alt="" /></figure><p>Представьте большой ресторан с одним официантом. Он принимает заказ, бежит на кухню, ждет приготовления, несет блюдо. Пока он ждет на кухне, другие посетители сидят без внимания. Так работают синхронные  приложения.</p><p>Асинхронность — это штат из нескольких официантов. Пока один ждет на кухне, другие обслуживают клиентов. Сервер не блокируется на одной операции, а переключается между задачами.</p><p>Главное изменение в Django 5.1 — стабилизация асинхронного API. Ранние реализации, начиная с Django 3.1 содержали скрытые проблемы, которые теперь устранены. Асинхронные вьюхи перестали быть экспериментальной функцией.</p><p>Основное преимущество асинхронности — эффективная работа с операциями ввода-вывода. Это запросы к внешним API, взаимодействие с файлами и базами данных. В таких сценариях асинхронный код может обрабатывать больше запросов на том же оборудовании — в некоторых случаях до 3-5 раз, в зависимости от нагрузки и конфигурации..</p><p>Рассмотрим практический пример. Допустим, мы разрабатываем агрегатор новостей. Приложение должно получать данные из трех источников одновременно.</p><p>Импортируем необходимые библиотеки:</p><p>Этот код выполняет все три запроса параллельно. В синхронной версии общее время выполнения равнялось бы сумме времени всех запросов. В асинхронной — времени самого медленного запроса.</p><figure><img src="https://media.tproger.ru/user-uploads/133848/2025-11-14/dd8d3017-4f27-4e00-aa09-e115edc00a20.png" alt="" /></figure><h2>Асинхронный ORM: текущее состояние</h2><p>Django 5.1 продолжает улучшать асинхронную поддержку ORM (Object-Relational Mapping — система, которая позволяет работать с базой данных как с набором Python-объектов). Большинство операций с БД теперь имеют асинхронные версии. Но важно понимать ограничения.</p><p>Полностью асинхронные запросы работают только с драйверами, поддерживающими асинхронность. Для PostgreSQL это psycopg3, для MySQL — aiomysql. SQLite имеет ограниченную асинхронную поддержку.</p><p>Пример асинхронного ORM-запроса:</p><p>Методы, начинающиеся с «a» (aget, alist, afirst), предоставляют асинхронный интерфейс к стандартным ORM-операциям.</p><h2>Производительность: реальные показатели</h2><p>Асинхронный подход в Django 5.1 показывает наибольшую эффективность в сценариях с интенсивным вводом-выводом, где приложение активно взаимодействует с внешними API, файловыми системами или сетевыми ресурсами. В таких условиях асинхронная обработка запросов позволяет эффективно использовать ресурсы сервера за счет параллельного выполнения операций ожидания.</p><p>Архитектурные преимущества асинхронности реализуются, если соблюден ряд условий:</p><ul><li>используется ASGI-сервера вместо WSGI;</li><li>правильно настроены асинхронные драйверов базы данных;</li><li>нет блокирующих операций в основном потоке выполнения.</li></ul><p>При грамотной реализации это позволяет обрабатывать тысячи одновременных соединений без пропорционального увеличения потребления памяти.</p><p>На практике производительность сильно зависит от конкретной конфигурации и характера нагрузки. Для CPU-bound операций или простых CRUD-приложений с минимальной внешней интеграцией выигрыш может быть незначительным. Однако в задачах, требующих множественных параллельных обращений к внешним сервисам или обработки потоковых данных, асинхронная архитектура демонстрирует существенное преимущество перед традиционным синхронным подходом.</p><h2>Типичные ошибки и как их избежать</h2><p>Переход на асинхронность требует изменения концепции разработки. Самые частые ошибки связаны с неправильным смешением синхронного и асинхронного кода. Рассмотрим основные подводные камни и способы их обхода.</p><p>Ошибка: вызов синхронной функции из асинхронного контекста без обертки.</p><p>Неправильный подход:</p><p>Правильное решение:</p><p>Другая распространенная проблема — блокирующие вызовы в асинхронном коде. Даже в асинхронной функции такие операции как сложные вычисления или синхронные HTTP-запросы будут блокировать цикл событий.</p><p>Решение — выносить ресурсоемкие задачи в отдельные потоки через asyncio.to_thread или использовать специализированные воркеры.</p><p>Типичная ошибка: неправильная работа с транзакциями в асинхронном контексте. Синхронные транзакции Django не работают с асинхронным кодом.</p><p>Неправильно:</p><p>Правильное решение — использовать sync_to_async для обертки всей транзакции:</p><p>Ошибка — постановка избыточного количества одновременных задач без ограничений. Это может привести к исчерпанию ресурсов сервера.</p><p>Проблемный код:</p><p>Решение — использовать семафоры для ограничения параллелизма:</p><p>Ошибка неправильной обработки исключений в асинхронном коде. В синхронном Python исключения распространяются по стеку вызовов, но в асинхронном это работает иначе.</p><p>Неправильно:</p><p>Правильный подход — учитывать специфику асинхронных исключений:</p><p>Ошибка блокировки цикла событий долгими CPU-bound операциями. Асинхронность не ускоряет вычисления, а только улучшает работу с вводом-выводом.</p><p>Проблемный код:</p><p>Решение — вынос вычислений в отдельный поток:</p><p>Ошибка неправильного использования глобальных переменных в асинхронном коде. Состояние может изменяться неожиданно из-за параллельного выполнения.</p><p>Опасный код:</p><p>Решение — использование контекстных переменных или передача состояния явно:</p><p>Ошибка создания взаимной блокировки при неправильном использовании примитивов синхронизации. Асинхронные блокировки имеют свои особенности.</p><p>Проблемный код:</p><p>Решение — проектировать код так, чтобы избегать вложенных блокировок и использовать timeout:</p><p>Исключив эти ошибки, сможете создавать более надежный и производительный асинхронный код в Django 5.1.</p><h2>Когда асинхронность не нужна</h2><p>Асинхронность — мощный инструмент, но не универсальное решение. Есть сценарии, где ее применение не дает преимуществ, а только усложняет код.</p><p>Ситуации, когда асинхронность избыточна:</p><ul><li>Простые CRUD-приложения без внешних вызовов — если приложение в основном выполняет базовые операции с базой данных и не взаимодействует с внешними API, синхронный код проще для понимания и отладки.</li><li>Проекты с небольшой нагрузкой — когда количество одновременных пользователей измеряется десятками, а не тысячами, дополнительные затраты на управление асинхронными задачами перевешивают преимущества.</li><li>Команды без опыта работы с асинхронным кодом — асинхронное программирование требует понимания цикла событий и корутин (легковесных программ, которые позволяют писать асинхронный код так, как будто он синхронный). Ошибки сложнее обнаружить и исправить.</li><li>Приложения с интенсивными вычислениями — Python GIL ограничивает параллельное выполнение CPU-bound задач, поэтому для вычислений лучше подходит многопроцессорность.</li><li>Интеграция со сторонними библиотеками — многие популярные Python-библиотеки не поддерживают асинхронность, приходится использовать обертки sync_to_async.</li><li>Быстрая разработка и тестирование — написание и отладка асинхронных тестов занимает больше времени, что критично для стартапов.</li><li>Высокие требования к надежности — синхронная архитектура предсказуемее и надежнее для проектов, где стабильность важнее производительности.</li><li>Ограниченные ресурсы разработки — стоимость разработки и поддержки асинхронных приложений обычно выше из-за требований к квалификации команды.</li><li>Миграция legacy-проектов — переписывание существующих синхронных систем на асинхронность рискованно и часто неоправданно.</li><li>Микросервисная архитектура — выделение отдельных сервисов для асинхронных задач часто практичнее, чем преобразование всего приложения.</li></ul><p>Выбор между синхронным и асинхронным подходом должен основываться на конкретных требованиях проекта, а не на модных тенденциях. Измеряйте производительность, оценивайте сложность и принимайте взвешенные решения. Для многих проектов проверенная синхронная архитектура остается оптимальным решением.</p><h2>Миграции в Django 5.1: эволюция продолжается</h2><p>Система миграций — один из самых мощных инструментов Django. В версии 5.1 она получила значительные улучшения в производительности и надежности.</p><p>Новый алгоритм обнаружения изменений стал умнее. Раньше простые изменения типа переименования поля могли генерировать каскад ненужных миграций. Теперь система лучше понимает намерения разработчика.</p><p>Рассмотрим пример улучшенного обнаружения изменений. Было в models.py (основном файле для описания структуры базы данных):</p><p>В Django 4.2 это могло создать две отдельные миграции. В 5.1 система понимает, что created и created_at — одно поле, и генерирует одну миграцию с операцией RenameField и изменением max_length.</p><figure><img src="https://media.tproger.ru/user-uploads/133848/2025-11-14/ba142314-f343-4547-931d-80ed37f1a0ca.png" alt="" /></figure><h2>Безопасные миграции больших таблиц</h2><p>Работа с таблицами в миллионы записей всегда была болезненной точкой. Блокировки таблиц при применении миграций могли приводить к простоям приложения.</p><p>В Django 5.1 представлен атрибут Operation.category. Он позволяет классифицировать операции миграций. Команда showmigrations теперь отображает специальные символы для каждой операции. Это упрощает чтение плана миграций. Разработчики быстрее понимают структуру изменений в базе данных.</p><p>Новая система категорий помогает автоматизировать проверку миграций. Инструменты анализа кода могут использовать категории для поиска потенциальных проблем, что особенно полезно в больших проектах со сложной историей миграций. Визуальные метки делают процесс разработки более наглядным. Легко отслеживать прогресс применения миграций в разных средах.</p><p>Новые опции в миграциях:</p><h2>Миграции с данными: лучшие практики</h2><p>Миграции данных остаются мощным, но опасным инструментом. Ошибки в этом процессе может привести к катастрофическим последствиям.</p><p>Как делать правильно:</p><ul><li>всегда тестировать миграции на полной копии production-данных;</li><li>использовать пакетную обработку для больших объемов данных;</li><li>предусматривать откат для каждой операции с данными;</li><li>добавлять индикатор прогресса для долгих миграций</li></ul><p>Пример безопасной миграции данных:</p><h2>Интеграция с облачными базами данных</h2><p>В 2025 году большинство проектов развернуты в облачных средах. Django 5.1 улучшил поддержку облачных баз данных типа Amazon RDS, Google Cloud SQL и Azure Database.</p><p>Основные улучшения:</p><ul><li>лучшая обработка временных разрывов соединения;</li><li>поддержка реплик для чтения для распределения нагрузки;</li><li>улучшенная работа с пулами соединений;</li><li>автоматическое переподключение при обрывах.</li></ul><p>Конфигурация для облачной PostgreSQL:</p><p>Django 5.1 сделал встроенную поддержку пулов соединений PostgreSQL через psycopg3, чтобы сократить расходы на установку соединений.</p><h2>Мониторинг и отладка асинхронного кода</h2><p>Отладка асинхронного кода требует специальных подходов. Трассировка стека в асинхронных приложениях сложнее из-за работы цикла событий (event loop).</p><p>Новые инструменты для мониторинга:</p><ul><li>ASGI middleware (промежуточный слой) для мониторинга производительности;</li><li>интеграция с системами мониторинга производительности приложений;</li><li>специализированные логи для асинхронных операций;</li><li>метрики для event loop.</li></ul><p>Пример middleware для мониторинга:</p><h2>Тестирование асинхронных приложений</h2><p>Тестирование асинхронного кода в Django требует использования специальных тестовых классов и подходов.</p><p>Пример тестирования асинхронной вьюхи:</p><h2>Безопасность асинхронного кода</h2><p>Асинхронность приносит новые векторы атак. Состояния гонки, взаимные блокировки и проблемы с разделением состояния становятся более вероятными.</p><p>Как минимизировать риски:</p><ul><li>использовать потокобезопасные структуры данных;</li><li>избегать разделяемого изменяемого состояния;</li><li>тщательно тестировать на состояния гонки;</li><li>использовать асинхронные версии блокировок при необходимости.</li></ul><p>Пример безопасной работы с разделяемыми ресурсами:</p><h2>Миграционная стратегия для legacy-проектов</h2><p>Перевод существующего проекта на асинхронность требует продуманного подхода.</p><p>Рекомендуется постепенная миграция:</p><ol><li>Начать с новых эндпоинтов, реализуя их асинхронно.</li><li>Выделить наиболее нагруженные части API для перевода на async.</li><li>Использовать гибридный подход, где это необходимо.</li><li>Тщательно тестировать производительность на каждом этапе.</li></ol><p>Пример гибридного подхода. Старые синхронные вьюхи остаются:</p><p>Новые эндпоинты делаем асинхронными:</p><p>Гибридный эндпоинт:</p><h2>Производительность в продакшене: метрики и мониторинг</h2><p>При развертывании асинхронных приложений важно отслеживать правильные метрики.</p><p>Традиционные метрики веб-приложений дополняются специфическими для async:</p><ul><li>Event loop latency — задержки в обработке событий;</li><li>Active tasks — количество активных асинхронных задач;</li><li>Queue size — размер очереди задач;</li><li>Database connection pool usage — использование пула соединений.</li></ul><p>Настройка мониторинга:</p><h2>Итоги: асинхронность как стандарт</h2><p>Django 5.1 знаменует переход асинхронности из категории экспериментальных возможностей в стандартный инструмент разработки. Стабильность и производительность async-компонентов достигли уровня, позволяющего использовать их в production-проектах.</p><p>Система миграций продолжает развиваться, предлагая улучшенную производительность и надежность. Новые функции особенно ценны для больших проектов с миллионами записей.</p><p>Ключевые выводы для разработчиков в 2025 году:</p><ul><li>асинхронные вьюхи готовы к использованию в продакшене;</li><li>наибольший выигрыш от асинхронности — в сценариях с интенсивным вводом-выводом;</li><li>миграции стали надежнее и безопаснее для больших баз данных;</li><li>постепенная миграция legacy-кода — оптимальная стратегия;</li><li>мониторинг и тестирование требуют адаптации под асинхронную парадигму.</li></ul><p>Django продолжает эволюционировать, поддерживая равновесие между современными требованиями и обратной совместимостью. Асинхронность в Django 5.1 — это закономерный этап развития фреймворка, который уже более 15 лет входит в топ наиболее популярных инструментов для веб-разработки на Python.</p>]]></content:encoded>
    </item>
    <item>
      <title>Инженер реализовал завирусившийся XKCD-комикс про зависимости ПО</title>
      <link>https://tproger.ru/news/inzhener-realizoval-zavirusivwijsya-xkcd-komiks-pro-zavisimosti-po</link>
      <comments>https://tproger.ru/news/inzhener-realizoval-zavirusivwijsya-xkcd-komiks-pro-zavisimosti-po?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/inzhener-realizoval-zavirusivwijsya-xkcd-komiks-pro-zavisimosti-po</guid>
      <description><![CDATA[<p>Инженер создал Stacktower — интерактивную версию культового XKCD-комикса, показывающую, как одна зависимость может «обрушить» все приложение</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/inzhener-realizoval-zavirusivwijsya-xkcd-komiks-pro-zavisimosti-po">Инженер реализовал завирусившийся XKCD-комикс про зависимости ПО</a>»</p>]]></description>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Node.js]]></category>
      <category><![CDATA[Rust]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 05 Dec 2025 09:04:53 GMT</pubDate>
      <content:encoded><![CDATA[<p>Веб-инженер <i>Маттиас Хюэль</i> <a href="https://stacktower.io/">создал</a> <b>интерактивную версию культового комикса XKCD №2347</b>, в котором автор высмеивает хрупкость современного ПО.</p><p>Это тот самый рисунок, который в последние месяцы превратился в популярный мем: огромные цифровые системы стоят на одном крошечном модуле, поддерживаемом энтузиастом из Небраски.</p><p>Но теперь эта «шутка» стала наглядной — <b>проект Stacktower превращает рисунок в настоящую визуализацию зависимостей</b>.</p><p>На заглавной схеме, полностью повторяющей комикс, можно нажать на любой блок — и увидеть реальные пакеты, библиотеки и цепочки зависимостей.</p><p>Проект динамически строит дерево зависимостей, позволяя проследить, как небольшие модули опираются на еще меньшее количество фундаментальных компонентов.</p><figure><img src="https://media.tproger.ru/user-uploads/111041/2025-12-05/1b29d25e-fccc-45ef-ade8-a7c35ad092ba.jpeg" alt="" /></figure><h2>Как работает Stacktower</h2><p>Сайт предлагает две модели: <i>«стабильную башню»</i> и <i>«неустойчивую башню»</i>, где уровни подстраиваются под выбранные библиотеки.</p><p>Пользователь может загрузить зависимости своих приложений — например, на <b>Python</b> или <b>JavaScript</b> — и увидеть, что будет, если убрать даже один элемент.</p><p>На странице приводится пример для <b>Node.js</b>:</p><p>приложение зависит от Express → Express зависит от body-parser → body-parser зависит от qs → и так далее</p><p>Stacktower иллюстрирует, что даже простое приложение тянет десятки модулей, часто неподконтрольных разработчику.</p><p>Есть и <b>Python-вариант</b>:</p><p>импорт Flask тянет Werkzeug, Jinja2, MarkupSafe, Click и еще несколько пакетов. А те, в свою очередь, имеют собственные зависимости.</p><h2>Зачем это нужно</h2><p>Автор подчеркивает: <b>цель проекта — не критиковать экосистемы, а показать их реальное устройство</b>.</p><p>Стек современных приложений неизбежно сложен и даже крошечный модуль может стать критически важным. Именно так в 2022 году случайное удаление библиотеки left-pad временно «сломало» огромный кусок JavaScript-мира.</p><p>Stacktower превращает эту абстрактную проблему в понятный визуальный эффект: убираешь одну зависимость — рушится вся конструкция.</p><h2>Комьюнити уже подхватило идею</h2><p>Проект быстро разошелся по Reddit, Hacker News и X: разработчики делятся скриншотами своих «башен», спорят о хрупкости экосистем и обсуждают, стоит ли пересматривать подход к зависимости.</p><p>Кто-то предлагает добавить поддержку Rust и Go, другие мечтают о корпоративной версии инструмента для визуального аудита безопасности.</p><p>Изучить проект подробнее можно на его <a href="https://github.com/matzehuels/stacktower">странице</a> на GitHub.</p>]]></content:encoded>
    </item>
    <item>
      <title>Разработке обещают смерть последние 30 лет, теперь из-за ИИ. Почему она все еще живее всех живых</title>
      <link>https://tproger.ru/news/razrabotke-obeshhayut-smert-poslednie-30-let--teper-iz-za-ii--pochemu-ona-vse-eshhe-zhivee-vseh-zhivyh</link>
      <comments>https://tproger.ru/news/razrabotke-obeshhayut-smert-poslednie-30-let--teper-iz-za-ii--pochemu-ona-vse-eshhe-zhivee-vseh-zhivyh?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/razrabotke-obeshhayut-smert-poslednie-30-let--teper-iz-za-ii--pochemu-ona-vse-eshhe-zhivee-vseh-zhivyh</guid>
      <description><![CDATA[<p>30 лет предсказывают смерть разработки, теперь из-за ИИ. Но каждая «революция» лишь меняет инструменты, а не отменяет потребность в инженерах</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/razrabotke-obeshhayut-smert-poslednie-30-let--teper-iz-za-ii--pochemu-ona-vse-eshhe-zhivee-vseh-zhivyh">Разработке обещают смерть последние 30 лет, теперь из-за ИИ. Почему она все еще живее всех живых</a>»</p>]]></description>
      <category><![CDATA[Интернет]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Машинное обучение]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[Рефакторинг]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[HTML]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 02 Dec 2025 12:36:14 GMT</pubDate>
      <content:encoded><![CDATA[<p>История разработки — это череда повторяющихся <b>прогнозов о ее скорой гибели</b>.</p><p>В сети появился <a href="https://www.jasonscheirer.com/weblog/vignettes/">материал</a>, автор которого — программист с 20+ летним стажем — вспоминает, как еще в 90-е взрослые уверяли его, что <b>программирование обречено</b>.</p><p>Тогда активно утверждалось, что <b>ООП решит все проблемы раз и навсегда</b>: появятся библиотеки-«кирпичики», а бизнес просто будет собирать приложения как LEGO, вообще без инженеров.</p><p>Прошли десятилетия, а профессия не только не исчезла — <b>она стала одной из самых востребованных</b>. Каждый уровень абстракции, который должен был «убить» разработчиков, просто поднимал планку и открывал новые задачи.</p><h2>Мультимедиа, IDE и другие «концы света», которые не случились</h2><p>В начале 90-х индустрия переживала <b>«мультимедийную революцию»</b>: казалось, что любая программа должна уметь работать со звуком и видео, иначе останется в прошлом.</p><p>Но через несколько лет <b>это стало обыденностью</b> — просто очередным &lt;video /&gt; в HTML. Никто массово не разорился из-за отсутствия мультимедиа в продуктах.</p><p>В 2000-х на горизонте появился <b>новый «убийца профессии»</b> — умные IDE вроде IntelliJ. Автодополнение, рефакторинг, перенос классов, исправление ошибок до сборки — все это казалось магией, которая вот-вот заменит людей.</p><p>Но <b>инструменты лишь ускорили работу</b>, а <b>не забрали ее</b>. IDE прекрасно переставляет код, но не пишет новую логику.</p><h2>Автоматизация в реальности: она освобождает время, а не людей</h2><p>Автор приводит два примера: он автоматизировал работу контрактника, мигрировавшего базу MUMPS, и автоматизировал собственные задачи по обновлению сайтов, боясь потерять работу. В обоих случаях люди остались на своих местах — просто стали заниматься чем-то другим.</p><p>Вывод простой: <b>работы становится не меньше, а больше</b>. Автоматизация убирает рутину, но не отменяет необходимости решать новые проблемы.</p><h2>Новые ввения приходят и уходят, но разработка остается</h2><p>Интернет, Web 2.0, машинное обучение — каждая волна начиналась как революция и заканчивалась чем-то будничным. Мы привыкли к тому, что технологии, которые вчера казались чудом, сегодня воспринимаются как мелочь.</p><p><b>Текущая волна ИИ — не исключение</b>. Да, большие языковые модели меняют рабочие процессы. Да, они автоматизируют часть задач.</p><p>Но автор призвал быть честными с самими собой: такие сдвиги редко уничтожают профессию. Они скорее превращают ее в новую версию самой себя.</p><h2>Вместо финала: ИИ не убьет разработчиков, но сделает их работу другой</h2><p>Пугающие прогнозы звучат громко, но реальность — она сложнее. Пока одни обещают «конец эпохи программистов», другие продолжают писать код, решать задачи и адаптироваться к новым инструментам.</p><p>Как и последние 30 лет, разработка остается живой потому, что мир постоянно усложняется. А значит — всегда будет кому этот мир программировать.</p>]]></content:encoded>
    </item>
    <item>
      <title>T-строки в Python: новый способ форматирования строк</title>
      <link>https://tproger.ru/articles/t-stroki-v-python--novyj-sposob-formatirovaniya-strok</link>
      <comments>https://tproger.ru/articles/t-stroki-v-python--novyj-sposob-formatirovaniya-strok?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Валерия Турчак]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/t-stroki-v-python--novyj-sposob-formatirovaniya-strok</guid>
      <description><![CDATA[<p>Разбираемся, зачем они нужны и когда их использовать</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/t-stroki-v-python--novyj-sposob-formatirovaniya-strok">T-строки в Python: новый способ форматирования строк</a>»</p>]]></description>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 02 Dec 2025 10:14:19 GMT</pubDate>
      <content:encoded><![CDATA[<p>Python постоянно развивает инструменты для работы со строками. В версии 3.14 появился новый синтаксис — t-строки. Разбираемся, зачем они нужны и когда их использовать.</p><p>Эта статья написана с помощью сервис . Исходник — <a href="https://www.pythonmorsels.com/t-strings-in-python/">видео и гайд про новые t-строки в Python 3.14.</a></p><h2>Эволюция форматирования строк в Python</h2><h3>Процентный стиль (%) — с самого начала</h3><p>Python умел форматировать строки через процент с первых версий:</p><h3>Класс Template — Python 2.4</h3><p>В модуле string появился альтернативный способ:</p><h3>Метод format() — Python 2.6</h3><p>Форматирование стало компактнее:</p><h3>F-строки — Python 3.6</h3><p>Этот синтаксис быстро стал стандартом де-факто:</p><h3>T-строки — Python 3.14</h3><p>Новый инструмент для отложенной интерполяции:</p><h2>Когда использовать t-строки</h2><h3>Для разработчиков приложений</h3><p>Если вы пишете прикладной код, t-строки вам скорее всего не понадобятся прямо сейчас. Применяйте их только когда библиотека, которую вы используете, явно требует передать t-строку.</p><h3>Для авторов библиотек</h3><p>T-строки полезны при разработке библиотек, где пользователям нужна отложенная интерполяция. Типичные сценарии:</p><ul><li>Экранирование SQL-запросов перед выполнением</li><li>Обработка HTML перед рендерингом</li><li>Работа с регулярными выражениями</li><li>Предварительная обработка данных перед объединением в строку</li><li>Отложенная интерполяция (как в модуле logging)</li></ul><h3>Отличия f-строк от t-строк</h3><p>Ключевое различие: f-строки выполняют интерполяцию немедленно и возвращают готовую строку, t-строки возвращают объект Template с отложенной интерполяцией.</p><h4>Проблема, которую не решают f-строки</h4><p>Рассмотрим функцию dedent из модуля textwrap, которая удаляет общие отступы из текста:</p><p>Результат:</p><p>Функция корректно убирает общие отступы, но сохраняет относительные:</p><p>Результат:</p><h3>Где f-строки создают проблему</h3><p>Возьмём многострочный код:</p><p>Попробуем вставить его в f-строку и передать в dedent:</p><p>Получаем некорректный результат:</p><p>Первая строка кода имеет отступ, остальные — нет. Вся выходная строка обработана неправильно.</p><h3>Причина проблемы</h3><p>F-строка выполняет интерполяцию до того, как результат попадает в dedent. К этому моменту функция не может понять, как выглядела исходная строка до подстановки значений.</p><p>F-строка взяла строку без общих отступов (code) и поместила её внутрь строки с отступами. Когда итоговая строка попала в dedent, функция не смогла корректно определить, что нужно было сначала добавить отступы к подставляемому значению, а потом убрать общие отступы.</p><p>Функция dedent не может посмотреть историю и понять структуру исходной f-строки.</p><h2>Как работают t-строки</h2><h3>T-строки возвращают объекты Template</h3><p>F-строка возвращает готовую строку:</p><p>T-строка возвращает объект Template:</p><p>Итерация по объекту Template даёт смесь строковых фрагментов и объектов интерполяции:</p><h4>Применение t-строк</h4><p>Объект Template позволяет библиотекам предварительно обрабатывать интерполируемые части перед финальной сборкой строки.</p><h2>Решение проблемы dedent с t-строками</h2><p>Используем t-строку вместо f-строки:</p><p>Корректный результат:</p><p>Версия dedent, работающая с t-строками, видит, что подставляемое значение имело относительные отступы внутри более крупной строки, но само содержимое не было с отступами. Функция корректно применяет отступы к подставляемому значению перед удалением общих отступов у всей строки.</p><h2>Реализация dedent для t-строк</h2><p>Кастомная версия dedent для работы с t-строками:</p><p>Функция выполняет следующие операции:</p><ol><li>Использует стандартный dedent из модуля textwrap</li><li>Обрабатывает каждое интерполируемое значение в зависимости от его содержимого</li><li>Учитывает позицию значения внутри более крупной строки</li><li>Корректно применяет отступы перед финальной обработкой</li></ol><p>Эта реализация доступна в виде библиотеки better-dedent в индексе пакетов Python:</p><p>Автор предупреждает, что библиотека может содержать баги, поэтому сообщайте о найденных проблемах в репозитории проекта.</p><h3>Вывод по t-строкам: нужны или нет</h3><h4>Писать t-строки просто</h4><p>Синтаксис t-строки идентичен f-строке, меняется только префикс:</p><h4>Работать с Template сложнее</h4><p>Работа с объектом Template, который возвращает t-строка, требует понимания его структуры: нужно уметь итерироваться по частям и обрабатывать интерполяции.</p><p>В большинстве случаев вы не будете напрямую работать с t-строками и объектами Template в повседневном коде. Вы будете передавать их в библиотеки, которые специально разработаны для приёма t-строк.</p><p>Если библиотека поддерживает t-строки — передайте ей t-строку. Всё остальное библиотека обработает сама.</p><h4>Перспективы t-строк</h4><p>Python 3.14 вышел недавно, поэтому примеров использования t-строк в реальных проектах пока немного. Создатели t-строк ведут список <a href="https://github.com/t-strings/awesome-t-strings">awesome t-string</a> для тех, кто хочет следить за развитием экосистемы.</p><p>Следите за обновлениями библиотек, которыми вы пользуетесь — возможно, скоро они начнут поддерживать t-строки для более гибкой работы со строками.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как встроить OCR бухгалтерских документов в мобильное приложение на iOS и Android</title>
      <link>https://tproger.ru/articles/kak-vstroit-ocr-buhgalterskih-dokumentov-v-mobilnoe-prilozhenie-na-ios-i-android</link>
      <comments>https://tproger.ru/articles/kak-vstroit-ocr-buhgalterskih-dokumentov-v-mobilnoe-prilozhenie-na-ios-i-android?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Smart Engines]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-vstroit-ocr-buhgalterskih-dokumentov-v-mobilnoe-prilozhenie-na-ios-i-android</guid>
      <description><![CDATA[<p>Объясняем, как перенести возможности ИИ для распознавания бухгалтерских документов в мобильное приложение для iOS и Android</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-vstroit-ocr-buhgalterskih-dokumentov-v-mobilnoe-prilozhenie-na-ios-i-android">Как встроить OCR бухгалтерских документов в мобильное приложение на iOS и Android</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Android]]></category>
      <category><![CDATA[iOS]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[ЭДО]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 27 Nov 2025 14:10:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Сегодня мы продолжим разбираться, как встраивать технологии распознавания (OCR) в нативные мобильные приложения. Ранее мы уже показывали, как интегрировать <a href="https://tproger.ru/articles/kak-vstroit-raspoznavanie-pasporta-rf-v-android--powagovoe-rukovodstvo">распознавание паспорта</a>, а также <a href="https://tproger.ru/articles/kak-vstroit-raspoznavanie-dokumentov-v-android--powagovoe-rukovodstvo">документов с жесткими и гибкими формами</a> в Android. На очереди не менее важный класс документов – бухгалтерских, куда входят акты, счета, справки и накладные. А в качестве дополнения мы рассмотрим, как реализовать распознавание этих документов в приложении на iOS. Начинаем!</p><h2>Первичка и не только</h2><p>Когда мы говорим «бухгалтерские документы», мы имеем в виду не пару стандартных бланков, а множество первичных, учредительных, учетных и распорядительных документов, полуструктурированных и гибких форм. Среди них счета-фактуры, УПД, формы ТОРГ-12, транспортные накладные, акты, УКД, КСФ, ИСФ, уставы, приказы, бухгалтерский баланс, отчеты о финансовых результатах и многие другие.</p><p>Визуальный контроль и ручная перепечатка этих документов в системы бухучета – одна из наиболее времязатратных задач бухгалтерии. Даже при выборочной проверке и среднем уровне автоматизации сотрудник успевает обработать около 200-300 документов в день, в то время как объем документооборота у крупных компаний исчисляется десятками и сотнями тысяч страниц.</p><p>Снять практически 100% нагрузки в части ввода и проверки данных из бумажных документов и поступающих по ЭДО сканов можно при помощи OCR-систем. Автоматическое <a href="https://smartengines.ru/intelligent-document-recognition/">распознавание документов</a> исключает человеческий фактор и связанные с ним ошибки. Если сотрудник может банально устать или некорректно перенести информацию из документа, то ИИ, напротив, обеспечивает высочайшую точность извлечения данных.</p><h2>Возможности ИИ для работы с бухгалтерскими документами</h2><p>Для автоматизации работы с бухгалтерскими документами недостаточно простого полнотекстового распознавания. Чтобы действительно принести видимый экономический эффект, система OCR должна классифицировать документ, обнаруживать и считывать таблицы, чекбоксы и штрихкоды, извлекать даты, суммы, данные контрагентов, контролировать наличие подписей в документах, а также поддерживать распознавание многостраничных форм. Только такой комплекс возможностей ИИ способен внести реальный вклад в упрощение бухучета, учета НДС и налогов по УСН, ускорить делопроизводство и сэкономить часы времени сотрудников.</p><p>Мы в Smart Engines занимаемся разработкой таких решений. Наш флагманский продукт для <a href="https://smartengines.ru/intelligent-document-recognition/">распознавания документов</a> Smart Document Engine способен выполнить месячный объем работы отдела из 10 бухгалтеров всего за 1 час. Система обрабатывает изображения документов без передачи данных в облака, на внешние серверы или краудсорсинговые платформы. Это означает, что содержание документов не покидает устройство сотрудника – бизнес при этом получает гарантию сохранения коммерческой тайны.</p><p>Интеграция системы распознавания в мобильные приложения позволяет получить доступ к возможностям ИИ прямо со смартфона – без необходимости в компьютерах и сканерах. Для извлечения структурированных данных достаточно просто загрузить скан или сфотографировать документ в приложении. У интеграции нашей системы в iOS и Android есть еще одно преимущество – благодаря ей банк может развернуть мобильный сервис для бухгалтерского сопровождения малого бизнеса и ИП, у которых нет на эти задачи штатных сотрудников.</p><h2>Интеграция в Android</h2><p>Перейдем к главному. Поскольку мы специализируемся в распознавании на клиенте, интеграция нашего SDK в Android осуществляется обычным способом подключения локальных библиотек.</p><p>Вы переносите библиотеки (архитектурные срезы), бандл (набор документов, необходимых для распознавания) и jar-файл (интерфейс библиотеки) к себе в приложение. Подключаете jar-файл в вашей конфигурации gradle и после этого вы уже можете использовать наше API.</p><p>На этом этапе мы должны подготовить изображение для передачи в сессию. Мы создаем изображение класса se.common.Image с помощью соответствующих методов API.</p><p>Например, вы выбираете из галереи что-то в формате HEIC и система возвращает вам bitmap</p><p>Объект result содержит в себе не только распознанные поля документа, но и изображение документа: исправленное по перспективе и обрезанное по шаблону, уровень уверенности распознавания каждого поля и т.п.</p><h2>Интеграция в iOS</h2><p>Процесс интеграции в iOS-приложение тоже не вызывает сложностей, но имеет несколько вариантов из-за долгого отсутствия в экосистеме нормального пакетного менеджера зависимостей.</p><p>Первый вариант интеграции – ручной.</p><p>Вы перетаскиваете себе в проект две папки, одна из них содержит xcframework, обертку на objc и бандл. Вторая - готовый UI-контроллер, который можно вызывать из своего проекта.</p><p>Также необходимо в проекте прописать пути к заголовкам обертки и указать путь к файлу *-Bridging-Header.h, для раскрытия делегатов в swift из нашего контроллера.</p><p>Более удобные для интеграции SPM и Cocoapods мы тоже поддерживаем.</p><p>Сценарий взаимодействие с библиотекой на iOS точно такой же как и на Android, но в iOS мы имеем больше инкапсулированной логики. Для начала следует добавить в ваш класс два протокола SmartDocumentEngineDelegate, SmartDocumentEngineInitializationDelegate</p><p>Приведем сразу коллбек imagePicker, где реализована основная логика распознавания после выбора изображения из галереи.</p><p>Ожидать результата следует в делегате.</p><p>Объект результата по структуре идентичен объекту, который вы получаете в Android.</p><h2>Подведем итоги</h2><p>Как вы видите, интеграция нашего распознающего ИИ в мобильные приложения происходит быстро и бесшовно, а механика для iOS и Android отличается незначительно.</p><p>Помимо мобильных телефонов, наши технологии можно встроить и на компьютеры, планшеты или сервера компании, однако на смартфоне весь бухгалтерский документооборот становится проще и доступнее для сотрудников.</p><p>Подробнее с нашими решениями можно ознакомиться на <a href="https://smartengines.ru/">сайте Smart Engines</a>. А если вам понравился материал, предлагаем к прочтению нашу предыдущую <a href="https://tproger.ru/articles/kak-rewat-lyubye-zadachi-raspoznavaniya-v-miniappah">статью</a> про распознавание документов в мессенджерах.</p>]]></content:encoded>
    </item>
    <item>
      <title>В Python 3.17 предложили сделать Rust обязательным. CPython ждет крупнейшая реформа за 10 лет</title>
      <link>https://tproger.ru/news/v-python-3-17-predlozhili-sdelat-rust-obyazatelnym--cpython-zhdet-krupnejwaya-reforma-za-10-let</link>
      <comments>https://tproger.ru/news/v-python-3-17-predlozhili-sdelat-rust-obyazatelnym--cpython-zhdet-krupnejwaya-reforma-za-10-let?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/v-python-3-17-predlozhili-sdelat-rust-obyazatelnym--cpython-zhdet-krupnejwaya-reforma-za-10-let</guid>
      <description><![CDATA[<p>Python 3.17 может сделать Rust обязательным: CPython готовят к крупнейшей реформе за десятилетие — ради безопасности, скорости и будущего без GIL</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/v-python-3-17-predlozhili-sdelat-rust-obyazatelnym--cpython-zhdet-krupnejwaya-reforma-za-10-let">В Python 3.17 предложили сделать Rust обязательным. CPython ждет крупнейшая реформа за 10 лет</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Android]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Rust]]></category>
      <category><![CDATA[Firefox]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 18 Nov 2025 09:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Команда CPython <a href="https://discuss.python.org/t/pre-pep-rust-for-cpython/104906">обсуждает</a> предложение (pre-PEP), которое может радикально изменить процесс сборки интерпретатора: <b>Rust предлагают сделать обязательной зависимостью уже в Python 3.17</b>.</p><p>Если PEP примут, Python впервые за историю станет «двуязычным» проектом — частично на C, частично на Rust.</p><h2>Зачем Python нужен Rust</h2><p>Разработчики приводят несколько причин:</p><ul><li><b>Безопасность памяти.</b> Rust устраняет категории ошибок, привычные для C: use-after-free, гонки, переполнения.</li><li><b>Подготовка к free-threaded Python.</b> Переход к работе без GIL требует безопасных примитивов — Rust подходит идеально.</li><li><b>Производительность.</b> Rust позволяет создавать быстрые структуры данных без ручного менеджмента памяти.</li><li><b>Современный стек.</b> Linux, Android и Firefox уже используют Rust в системных компонентах — Python догоняет тренд.</li><li><b>Поддержка долгосрочного развития CPython.</b> Сложность кода растет, а Rust упрощает сопровождение.</li></ul><h2>Что именно планируют делать</h2><p>Стоит отметить, что Rust не планируют использовать в качестве полной замены C — появится возможность использовать оба языка. В идеале, должен получиться симбиоз:</p><ul><li><b>Crate</b> cpython-sys. Это набор автоматически сгенерированных привязок (FFI-слоя), которые позволяют Rust-коду безопасно «общаться» с внутренним API CPython.</li><li><b>Поддержка модулей на Rust.</b> Некоторые части стандартной библиотеки можно будет писать и подключать так же, как C-модули — только на Rust.</li><li><b>Прозрачное разделение зон безопасности.</b> «Безопасный» Rust будет использоваться по максимуму, а unsafe — только там, где нужно напрямую взаимодействовать с C-частями интерпретатора.</li></ul><p>Уже есть рабочий пример — модуль _base64 на Rust, который оказался быстрее варианта на C.</p><h2>Переходный план</h2><p>Если PEP утвердят, переход займет <b>три релиза</b>:</p><ul><li><b>Python 3.15</b> — предупреждение при сборке без Rust.</li><li><b>Python 3.16</b> — Rust остается опциональным, но его отключение потребует отдельного флага.</li><li><b>Python 3.17</b> — Rust становится <b>обязательной частью сборки </b>CPython.</li></ul><p>То есть через два релиза Python не соберется там, где нет Rust.</p><h2>Какие есть проблемы</h2><p>В обсуждении упоминают несколько рисков. Например, <b>циклическая зависимость при сборке</b> — Rust требует Python, Python требует Rust.</p><p>Вместе с тем, внедрение нового языка приведет и к <b>повышению порога входа</b> для новых участников разработки CPython. Как минимум потому, что им придется изучить Rust.</p><p><b>Появятся и сложности со сборкой в ограниченных средах</b>, например embedded-системах. При этом остается <b>неясной судьба Rust-API для сторонних расширений</b> — скорее всего, его не откроют.</p><h2>Что это значит для сообщества</h2><p>Для пользователей Python почти ничего не изменится. А вот для разработчиков интерпретатора это станет одним из самых крупных сдвигов в истории проекта.</p><p>Так, Python наконец-то станет сильно безопаснее. При этом CPython получит более надежный фундамент для будущих фич вроде полного отказа от GIL.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как open-source библиотеки помогают выстраивать комьюнити вокруг продукта</title>
      <link>https://tproger.ru/articles/kak-open-source-biblioteki-pomogayut-vystraivat-komyuniti-vokrug-produkta</link>
      <comments>https://tproger.ru/articles/kak-open-source-biblioteki-pomogayut-vystraivat-komyuniti-vokrug-produkta?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Сергей Востриков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-open-source-biblioteki-pomogayut-vystraivat-komyuniti-vokrug-produkta</guid>
      <description><![CDATA[<p>Сергей Востриков, руководитель направления «Маркетплейс и интеграции» Битрикс24 о том, как компании используют open-source для развития продуктов и какие возможности это открывает для бизнеса</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-open-source-biblioteki-pomogayut-vystraivat-komyuniti-vokrug-produkta">Как open-source библиотеки помогают выстраивать комьюнити вокруг продукта</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Инфраструктура]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 07 Nov 2025 14:00:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>Open-source перестал быть уделом энтузиастов, которые выкладывают код «чтобы было полезно другим». Сегодня это осознанная стратегия компаний, которые формируют будущее технологий. Когда Google открывает TensorFlow, Meta — React, а «Яндекс» — CatBoost, они строят экосистемы, вокруг которых растут сообщества инженеров, исследователей и интеграторов. Эти комьюнити становятся средой, где рождаются новые практики, а технологии эволюционируют быстрее, чем внутри любой отдельной корпорации.</p><p><i>О том, как компании используют open-source для развития продуктов и какие возможности это открывает для бизнеса, расскажет Сергей Востриков, руководитель направления «Маркетплейс и интеграции» Битрикс24.</i></p><h2>Почему вокруг библиотек формируется комьюнити</h2><p>Сообщества не возникают вокруг библиотек случайно. Они формируются там, где инструмент становится стандартом, а его создатели — открыты к диалогу и улучшениям. Так случилось с React от Meta, который определил язык фронтенд-разработки на годы вперёд. Или с Kubernetes, начавшимся как внутренняя инфраструктура Google, а со временем превратившимся в экосистему с тысячами плагинов и сервисов. FastAPI, созданный Себастьяном Рамиресом, получил поддержку благодаря простоте и продуманной архитектуре — контрибьюторы пришли сами, потому что инструмент был ясен и полезен.</p><p>В экосистеме Битрикс24 открытая модель работает по тем же законам. Компания публикует документацию по REST API, SDK для популярных языков, инструменты для интеграций и тестирования. Это позволяет внешним разработчикам создавать собственные решения — от платёжных модулей до отраслевых сервисов, которые точно отвечают запросам локального бизнеса. В результате формируется живая сеть партнёров и интеграторов — люди вкладываются в продукт, потому что видят в этом устойчивую ценность и пространство для роста. Даже если компания делится не самим ядром продукта, а вспомогательными инструментами, эффект оказывается значительным — появляется среда, где развитие идей становится совместным усилием.</p><h2>В чем выгода бизнеса</h2><p>Когда вокруг продукта формируется сообщество, бизнес получает дополнительный двигатель развития. Внешние разработчики берут на себя десятки мелких, но критичных задач — от адаптации под локальные рынки до создания интеграций с нишевыми сервисами. Это ускоряет эволюцию продукта — обновления появляются чаще, решения становятся точнее, а пользователи видят, что система живёт и развивается.</p><p>Открытая архитектура снижает порог входа для партнёров и клиентов. Чем прозрачнее внутренняя логика платформы, тем проще выстраивать интеграции и доверять данным, которые через неё проходят. При этом сообщество выполняет маркетинговую работу без бюджета — контрибьюторы обсуждают продукт, создают обучающие материалы, делятся кейсами. Репутация бренда растёт органично, а стоимость привлечения новых пользователей снижается.</p><p>Есть и кадровый эффект. Активные участники сообщества становятся естественным кадровым резервом. Они уже знают продукт изнутри, умеют работать с его API, понимают архитектуру и бизнес-логику. Для компании это способ пополнять команду людьми, которые разделяют ценности продукта и умеют его развивать.</p><h2>Экономическая логика open-source</h2><p>Open-source давно перестал быть жестом альтруизма. За ним стоит чёткая экономическая логика. Когда ядро продукта доступно бесплатно, компания переносит монетизацию на уровень сервисов, инфраструктуры и качества опыта. Пользователь получает гибкость и надёжность, бизнес — масштаб без роста издержек. Такая модель делает код открытым, но ценность — платной.</p><p>Сила open-source — в сетевом эффекте. Каждый новый плагин, библиотека или интеграция увеличивают полезность продукта и усложняют его замену. Экосистема начинает жить собственной жизнью — контрибьюторы расширяют функциональность, компании создают коммерческие надстройки, а ценность бренда растёт за счёт активности сообщества. Поддержка распределяется между тысячами участников, снижая нагрузку на core-команду и ускоряя внедрение новшеств.</p><p>Есть и долгосрочный дивиденд — репутация. Популярный open-source-проект становится витриной инженерной культуры компании. Он облегчает найм, укрепляет доверие к бренду и даёт компании влияние на технологические стандарты рынка. Так формируется экономика вокруг продукта, где вклад в общее развитие напрямую повышает устойчивость бизнеса.</p><h2>Типичные ошибки</h2><p>Формальная открытость — когда репозиторий доступен, но ключевые решения принимаются за закрытыми дверями — убивает мотивацию сообщества быстрее, чем технические ошибки. Лицензии с ограничениями, запутанные правила участия, непрозрачные процессы ревью — всё это создаёт ощущение, что разработчики нужны не как партнёры, а как бесплатный ресурс.</p><p>Слабая документация и отсутствие лидерства приводят к тому, что даже талантливые контрибьюторы теряют интерес. Если вход в проект требует недель разбирательств, а направление развития не обозначено, экосистема начинает распадаться. Открытый код живёт, только когда есть понятная архитектура взаимодействия, чёткие правила коммуникации и модерация, которая обеспечивает баланс между свободой и порядком.</p><p>По сути, успешный open-source управляется так же, как зрелая продуктовая команда — через цели, процессы, ответственность, прозрачность. Разница лишь в том, что всё это работает не в рамках одного офиса, а в распределённой среде, где людей объединяет общий интерес.</p><p>Open-source стал одной из редких моделей технологического сотрудничества, где интересы бизнеса и профессионального сообщества совпадают естественным образом. Компании получают инструмент ускорения развития, а разработчики — среду, в которой можно расти, делиться опытом и влиять на технологическую повестку. Такой обмен создаёт эффект синергии. Чем активнее сообщество, тем устойчивее продукт и тем выше ценность всей экосистемы.</p><p>Для зрелых компаний открытость становится частью управленческой культуры. Она формирует привычку действовать через сотрудничество, поддерживать среду, в которой развитие продукта не останавливается даже за пределами офиса. В этом и состоит главная сила open-source — он превращает технологию в живую систему, способную расти вместе с людьми, которые её создают.</p>]]></content:encoded>
    </item>
    <item>
      <title>«Я решал LeetCode 600 дней подряд»: разработчик рассказал, что из этого вышло</title>
      <link>https://tproger.ru/news/-ya-rewal-leetcode-600-dnej-podryad---razrabotchik-rasskazal--chto-iz-etogo-vywlo</link>
      <comments>https://tproger.ru/news/-ya-rewal-leetcode-600-dnej-podryad---razrabotchik-rasskazal--chto-iz-etogo-vywlo?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/-ya-rewal-leetcode-600-dnej-podryad---razrabotchik-rasskazal--chto-iz-etogo-vywlo</guid>
      <description><![CDATA[<p>Разработчик решал задачи на LeetCode 600 дней подряд и поделился, как это изменило его навыки, мышление и отношение к программированию</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/-ya-rewal-leetcode-600-dnej-podryad---razrabotchik-rasskazal--chto-iz-etogo-vywlo">«Я решал LeetCode 600 дней подряд»: разработчик рассказал, что из этого вышло</a>»</p>]]></description>
      <category><![CDATA[Языки программирования]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Навыки]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 29 Oct 2025 10:38:31 GMT</pubDate>
      <content:encoded><![CDATA[<p>Разработчик <a href="https://habr.com/ru/companies/betboom/articles/959246/">поделился</a> впечатлениями после <b>600 дней непрерывных тренировок на LeetCode</b> — платформе, где программисты решают алгоритмические задачи. Нужно это, чтобы подготовиться к собеседованиям или просто прокачать навыки.</p><p>Все началось с дружеского спора: автор и его знакомый решили за месяц решить 100 задач, чтобы проверить, насколько это реально. Цель была достигнута быстро — и стала привычкой.</p><p>Спустя полтора года у него за плечами <b>700+ решенных задач</b> и впечатляющий <b>стрик длиной в 600 дней</b>.</p><blockquote><i>«Сначала это было в кайф, потом — дисциплина. Где-то после 200-го дня я уже просто не мог сбить стрик. Каждый вечер садился и решал хотя бы одну задачу — хоть легкую, хоть любую»,</i> — пишет он.</blockquote><h2>«LeetCode — это спорт»</h2><p>По словам разработчика, примерно после сотни задач он заметил, как мозг начинает видеть паттерны: «алгоритмы перестают быть абстракцией и становятся шаблонами действий».</p><p>После 300 задач появилась уверенность, а к 600 — автоматизм: больше не страшно видеть длинные цепочки функций, не путаешься в деревьях и графах, а выбор структуры данных становится интуитивным.</p><p>Он выделяет три типа решений на платформе:</p><ul><li><b>Производительные и сложные</b>, где «изобретают велосипед» ради скорости;</li><li><b>Элегантные, но непроизводительные</b>, зато читаемые и похожие на реальный продакшн-код;</li><li><b>«Чтобы просто работало»</b> — типичные решения новичков без оптимизаций.</li></ul><figure><img src="https://media.tproger.ru/user-uploads/111041/2025-10-29/54fae254-bd28-471c-97ca-cd60e3ad116a.jpeg" alt="" /></figure><p>Сам разработчик предпочитает второй вариант: чистый код, пусть и не самый быстрый.</p><h2>Стоило ли того?</h2><p>По мнению автора поста, LeetCode помогает тем, кто хочет попасть в <b>биг-тех</b>, разобраться в <b>алгоритмах</b>, или просто тренировать мозг. Но для повседневной работы в типичном проекте навыки из LeetCode пригодятся разве что косвенно — как понимание сложности операций или знание стандартной библиотеки.</p><blockquote><i>«После 200+ дней это превращается в рутину — задача ради задачи. Но привычка сильнее мотивации. Делая по одной задаче в день, можно дойти до любого уровня».</i></blockquote><p>Среди советов начинающим — не гнаться за hard-задачами, смотреть чужие решения и помнить, что прогресс измеряется не количеством, а осознанностью.</p><p>В итоге разработчик делает вывод, знакомый каждому, кто сталкивался с LeetCode:</p><blockquote><i>«Это отдельный мир. В нем свои правила и не так много связи с реальностью. Но он точно покажет, что такое алгоритмы — и нужны ли они именно тебе».</i></blockquote>]]></content:encoded>
    </item>
    <item>
      <title>Типы языков программирования: от низкоуровневых до высокоуровневых — как выбрать для новичка</title>
      <link>https://tproger.ru/articles/tipy-yazykov-programmirovaniya--ot-nizkourovnevyh-do-vysokourovnevyh---kak-vybrat-dlya-novichka</link>
      <comments>https://tproger.ru/articles/tipy-yazykov-programmirovaniya--ot-nizkourovnevyh-do-vysokourovnevyh---kak-vybrat-dlya-novichka?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Татьяна Жукова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/tipy-yazykov-programmirovaniya--ot-nizkourovnevyh-do-vysokourovnevyh---kak-vybrat-dlya-novichka</guid>
      <description><![CDATA[<p>Выбираете первый язык программирования? Узнайте о низкоуровневых (C, C++), среднеуровневых (Java, C#) и высокоуровневых (Python, JavaScript) языках: плюсы, минусы и примеры применения. Чек-лист от экспертов поможет новичкам выбрать язык для веб, мобильной разработки или игр.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/tipy-yazykov-programmirovaniya--ot-nizkourovnevyh-do-vysokourovnevyh---kak-vybrat-dlya-novichka">Типы языков программирования: от низкоуровневых до высокоуровневых — как выбрать для новичка</a>»</p>]]></description>
      <category><![CDATA[Низкоуровневое программирование]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Ruby]]></category>
      <category><![CDATA[PHP]]></category>
      <category><![CDATA[.NET]]></category>
      <category><![CDATA[Windows]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[TypeScript]]></category>
      <category><![CDATA[Xamarin]]></category>
      <category><![CDATA[Data Science]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[QA]]></category>
      <category><![CDATA[Бэкенд]]></category>
      <category><![CDATA[Аналитика]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Dart]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 28 Oct 2025 14:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Для погружения в программирование нужно всего 3 вещи:</p><ul><li>Решить, с какого языка/технологии вы хотите начать.</li><li>Решить, на каком ресурсе вы хотите обучаться.</li><li>Выделить время на само программирование.</li></ul><p>Звучит просто, однако у вас уйдёт много времени на исследования, чтобы решить, что вам подходит и на каком ресурсе обучаться.</p><p>Некоторые люди начинают с относительно низкоуровневого программирования на C и C++. Другие выбирают более традиционный путь, изучая Java или C#. Есть и те, кто начинает с высокоуровневых или скриптовых языков вроде Python, Ruby или JavaScript.</p><p>Мы классифицируем языки по уровню абстракции. Для новичков: низкоуровневые — как ручная сборка машины (контроль, но сложный); среднеуровневые — как готовый конструктор с инструкцией (сохраняем баланс); высокоуровневые — как приложение на смартфоне (быстро, но меньше контроля). Ниже разберём плюсы и минусы и поможем сделать правильный выбор.</p><h2>Низкоуровневые языки: близко к «железу»</h2><p>Это языки, где вы напрямую работаете с памятью компьютера. Нет автоматической уборки ненужных данных, <b>всё под вашим контролем</b>. Подходят для системного ПО, игр или устройств (например, микроконтроллеров).</p><p>Примеры: C (для ОС вроде Linux), C++ (для игр на движке вроде Unreal Engine), Assembler (для оптимизации критических частей кода).</p><p><b>Плюсы:</b></p><ul><li>Полный контроль: вы решаете, как использовать ресурсы. Так, в C++ можно вручную выделять память для массивов, избегая ненужных копий данных.</li><li>Высокая скорость: прямой доступ к памяти позволяет писать код, который работает быстрее (это важно для работы с играми или серверами).</li><li>Основы основ: такие языки учат, как компьютер работает изнутри, чтобы в будущем ценить удобства других языков. Например, вы узнаёте, почему «утечка памяти» — это проблема.</li><li>Эффективность: низкоуровневые языки мотивируют думать об оптимизации заранее, снижая расход батареи или CPU.</li><li>Компактность: минимальная библиотека, приложения получаются лёгкими (идеально для embedded-систем, как в IoT-устройствах).</li></ul><p>Минусы:</p><ul><li>Всё-таки это сложно: рутинные задачи (например, чтение файла) требуют больше кода и внимания к деталям, рискуя ошибками вроде переполненного буфера.</li><li>Ручное управление памятью: можно легко «забыть» освободить память, вызвав утечки или краши. Например, в C нужно использовать malloc/free, иначе программа съест всю RAM.</li><li>Много копипасты: придётся писать шаблонный код, и делать это часто.</li><li>Платформо-зависимость: код для Windows может не работать на Linux без правок.</li></ul><h2>Среднеуровневые языки: баланс контроля и удобства</h2><p>Эти языки предлагают готовые инструменты, упрощающие работу, но требуют строгой проверки типов данных. Для их запуска нужна специальная программа (среда выполнения). Они идеальны для приложений, серверов и игр.</p><p>Примеры: Java (для Android-приложений), C# (для Unity-игр или .NET-серверов).</p><p>Плюсы:</p><ul><li>Автоматическая память: память очищается автоматически благодаря сборщику мусора, что избавляет от ручной работы и снижает вероятность ошибок, вроде утечек памяти в больших проектах. При этом можно получить доступ к низкоуровневым функциям для особых задач, например, через специальные инструменты в Java.</li><li>Богатые библиотеки: готовые инструменты для сетей, GUI или баз данных. Пример: Java’s Spring для веб-серверов.</li><li>Кроссплатформенность: компиляция в байт-код (JVM для Java) позволяет запускать код везде. Например, пишешь на Windows, запускаешь на Linux.</li><li>Безопасность: язык проверяет типы данных перед запуском программы, помогая заранее найти ошибки. Среда выполнения защищает от опасных сбоев, например, от переполненной памяти.</li><li>Масштабируемость: встроенные инструменты для параллельных вычислений позволяют легко создавать программы, которые одновременно выполняют много задач (серверы для тысяч пользователей и т.п.).</li></ul><p>Минусы:</p><ul><li>Дополнительная нагрузка от рантайма: Среда выполнения и автоматическая очистка памяти создают дополнительную нагрузку. Сборщик мусора может ненадолго останавливать программу, что заметно в играх или при обработке видео.</li><li>Меньше контроля: абстракции скрывают детали памяти, усложняя оптимизацию (например, в Java сложно избежать боксинга примитивов).</li><li>Повторяющийся код, которого много: приходится писать повторяющийся код и тренировать свою усидчивость, например, для доступа к данным объекта. Кстати, инструменты вроде Lombok могут упростить эту задачу.</li><li>Зависимость от среды: для запуска программ нужна специальная среда (например, JVM для Java), что влияет на размер программ и замедляет их старт.</li><li>Сложность интеграции: подключение кода на других языках, например, на C, требует писать специальные обёртки, что усложняет работу и снижает скорость.</li></ul><h2>Высокоуровневые языки: удобство и скорость разработки</h2><p>Эти языки скрывают технические детали, позволяя сосредоточиться на создании <b>логики программы</b>. Подходят для веба, data science или скриптов.</p><p>Примеры: Python (для ML), Ruby (для веб-разработки), JavaScript (для фронтенда).</p><p>Плюсы:</p><ul><li>Простота: сложные задачи решаются в пару строк. Так, в JS async/await упрощает API-запросы.</li><li>Быстрая разработка: динамическая типизация позволяет быстро писать и тестировать код без необходимости его компиляции.</li><li>Богатые экосистемы: есть библиотеки для всего (к примеру, NumPy для данных в Python).</li><li>Гибкость: легко менять код, идеально для прототипов или стартапов.</li></ul><p>Минусы:</p><ul><li>Низкая производительность: абстракции добавляют нагрузки. Например, циклы в Python медленнее, чем в C.</li><li>Ошибки на рантайме: из-за слабой типизации ошибки выявляются только при запуске программы, что усложняет отладку.</li><li>Риск «спагетти-кода»: лёгкость изменений может привести к хаосу без дисциплины.</li><li>Скрытые проблемы: абстракции маскируют баги.</li><li>Зависимость от интерпретатора: программы требуют установленного интерпретатора, что замедляет их запуск и добавляет зависимость от дополнительного ПО.</li></ul><h2>Чек-лист: как выбрать язык программирования для новичка</h2><p>Этот чек-лист основан на советах экспертов, чтобы помочь новичкам выбрать первый язык программирования. Каждый пункт включает конкретные рекомендации.</p><ol><li><b>Определите, что вас вдохновляет, и выберите сферу.</b> Подумайте, что вы хотите создавать: сайты, игры, мобильные приложения или серверы. Разные сферы требуют разных языков. Например, для веб-разработки подойдут JavaScript или Python, для мобильных приложений — Java, Kotlin, Swift или Dart, а для игр — C# или C++. Составьте список идей (например, сайт-визитка, игра, аналитика данных) и найдите, какие языки для них используют. <br />— Аня Жаркова, руководитель мобильной разработки в USETECH</li><li><b>Ищите язык с широким применением.</b> Выбирайте языки, которые используются в разных областях, чтобы легче переключаться между задачами. Например, Kotlin подходит для мобильной разработки, веба и серверов, а C# — для десктоп-приложений, игр (Unity) и бэкенда. Это даёт гибкость и упрощает изучение новых языков в будущем.<br />— Аня Жаркова, руководитель мобильной разработки в USETECH</li><li><b>Проверьте спрос на рынке труда. </b>Если цель — смена профессии, изучите вакансии на HH.ru или LinkedIn. Введите «junior Python», «junior Java» и сравните, где больше предложений и какие требования. Избегайте языков с низким спросом, если хотите быстро найти работу. Например, Java, Kotlin, Python и JavaScript популярны для найма.<br />— Владислав Масунов, Head of Development</li><li><b>Опробуйте языки на практике.</b> Напишите простые программы (например, "Hello World" или калькулятор) на нескольких языках, чтобы понять, какой синтаксис вам ближе. Используйте онлайн-редакторы вроде Replit или CodePen. Например, попробуйте TypeScript для веба (он поддерживает типизацию и разные подходы к программированию) или C++ для понимания работы с памятью. Это поможет почувствовать, к чему лежит душа.<br />— Рома Троицкий, фронтенд-инженер в Сбер B2C, член ПК HolyJS &amp; MoscowCSS; Евгений Антонов, ИТ-консультант, автор тг-канала <a href="https://t.me/general_it_talks">@general_it_talks</a></li><li><b>Выберите язык с хорошей документацией и сообществом.</b> Убедитесь, что у языка много обучающих материалов и активное сообщество. Например, TypeScript имеет богатую документацию и поддержку, что упрощает старт. Проверьте ресурсы вроде LearnPython.org, freeCodeCamp для JavaScript или Telegram-чаты для C++. Это поможет быстрее решать вопросы.<br />— Рома Троицкий, фронтенд-инженер в Сбер B2C, член ПК HolyJS &amp; MoscowCSS</li><li><b>Учитывайте сложность и карьерные цели.</b> Для небольших проектов или быстрого старта берите Python или PHP — они проще и подходят для веб-разработки или скриптов. Для сложных задач с высокой нагрузкой (например, серверы или оптимизация) попробуйте C++ или Go. Если цель — работа в крупных компаниях, Java и Kotlin востребованы и часто используются с ИИ-инструментами. Выбирайте, исходя из сложности и ваших амбиций.<br />— Евгений Антонов, ИТ-консультант, автор тг-канала <a href="https://t.me/general_it_talks">@general_it_talks</a></li><li><b>Смотрите на универсальность и переход к другим языкам. </b>Выбирайте язык, который учит основам программирования и упрощает переход к другим. Например, изучение C# может помочь освоить Java, а затем — Android-разработку. TypeScript учит объектно-ориентированному и функциональному программированию, что полезно для разных задач. Это создаёт базу для дальнейшего роста.<br />— Аня Жаркова, руководитель мобильной разработки в USETECH; Рома Троицкий, фронтенд-инженер в Сбер B2C, член ПК HolyJS &amp; MoscowCSS</li><li><b>Не гонитесь за гилти плежа.</b> Избегайте языков, которые изучают «для удовольствия» без практического применения. Выбирайте те, которые можно применить в реальных проектах или которые востребованы в индустрии. Например, вместо нишевых языков берите Python, Java или Kotlin: они имеют чёткие сценарии использования.<br />— Аня Жаркова, руководитель мобильной разработки в USETECH</li><li><b>Практикуйтесь с ИИ-инструментами.</b> Если хотите работать в крупных компаниях, освойте язык, который хорошо сочетается с ИИ-инструментами (например, Go или Java). Практикуйтесь с ИИ-агентами по типу GitHub Copilot для автоматизации задач — это ценится работодателями.<br />— Евгений Антонов, ИТ-консультант, автор тг-канала <a href="https://t.me/general_it_talks">@general_it_talks</a></li><li><b>Составьте план развития.</b> Создайте roadmap: определите, какие проекты хотите делать через 3-6 месяцев (например, мобильное приложение или веб-сервис), и подберите язык под эти цели. Если выбрали C#, начните с десктоп-приложений, затем попробуйте Xamarin для кроссплатформенной разработки. Постепенно добавляйте новые языки, опираясь на первый.<br />— Аня Жаркова, руководитель мобильной разработки в USETECH</li></ol><p>Если не определились, предлагаем пройти квиз и расставить всё по полочкам:</p>]]></content:encoded>
    </item>
    <item>
      <title>Google пообещала, что до конца года все смогут вайб-кодить видеоигры с помощью ИИ</title>
      <link>https://tproger.ru/news/google-poobeshhala--chto-do-konca-goda-vse-smogut-vajb-kodit-videoigry-s-pomoshhyu-ii</link>
      <comments>https://tproger.ru/news/google-poobeshhala--chto-do-konca-goda-vse-smogut-vajb-kodit-videoigry-s-pomoshhyu-ii?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/google-poobeshhala--chto-do-konca-goda-vse-smogut-vajb-kodit-videoigry-s-pomoshhyu-ii</guid>
      <description><![CDATA[<p>Google обещает, что до конца 2025 года любой сможет вайб-кодить видеоигры с ИИ — создавать их словами без единой строчки кода</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/google-poobeshhala--chto-do-konca-goda-vse-smogut-vajb-kodit-videoigry-s-pomoshhyu-ii">Google пообещала, что до конца года все смогут вайб-кодить видеоигры с помощью ИИ</a>»</p>]]></description>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[C#]]></category>
      <category><![CDATA[Google]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[Игра]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 28 Oct 2025 06:00:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>Google <a href="https://www.bleepingcomputer.com/news/google/google-says-everyone-will-be-able-to-vibe-code-video-games/">заявила</a>, что уже к концу 2025 года любой пользователь сможет вайб-кодить собственные видеоигры — буквально создавать их, просто описывая идею словами.</p><p>Об этом рассказал Логан Килпатрик, продакт-лид Google AI Studio, в посте на X.</p><h2>Что такое вайб-кодинг</h2><p>Термин vibe coding (от англ. vibe — «ощущение», «настроение») появился в 2024 году и описывает подход к программированию, где разработчик не пишет код вручную, а общается с ИИ в свободной форме, задавая лишь общие направления: «сделай RPG про кота-самурая», «добавь погодные эффекты», «пусть враги становятся умнее».</p><p>Пока этот подход работал только с простыми проектами вроде сайтов и мобильных приложений, но Google обещает вывести его на новый уровень.</p><h2>Что умеет новый AI Studio</h2><p>По словам компании, обновленный <b>Google AI Studio</b> «понимает задачу и автоматически подбирает нужные модели, API и инструменты».</p><p>Например, если пользователь захочет сделать приложение, генерирующее изображения по промтам, AI Studio сам подключит соответствующий API (в данном случае — Nano Banana API) и настроит всю инфраструктуру.</p><blockquote><i>«Мы сделали процесс создания мощных, функциональных и ИИ-дополненных приложений максимально простым»,</i> — говорится в блоге Google.</blockquote><p>Теперь платформа сможет не только генерировать код, но и <b>автоматически подключать нужные сервисы, базы данных и библиотеки</b>, превращая процесс в полноценный гибрид no-code подхода с вайб-кодингом.</p><h2>Теперь и для игр</h2><p>Килпатрик уточнил, что уже к концу года пользователи смогут вайб-кодить не только веб-приложения, но и простенькие видеоигры.</p><blockquote><i>«Это откроет путь для новых 100 млн разработчиков. Многие мечтают сделать игру, но спотыкаются о C++, C# и Unreal Engine. Теперь они смогут создавать истории, персонажей и геймплей — без единой строчки кода»,</i> — написал он.</blockquote><p>Разумеется, до уровня <i>Civilization</i> или <i>Baldur’s Gate</i> дело не дойдет. По словам Килпатрика, речь идет о «небольших проектах для друзей», где игроки сами управляют сюжетом и механикой.</p><h2>Скепсис и ожидания</h2><p>Пока даже самые продвинутые ИИ-инструменты едва справляются с генерацией простых 2D-игр вроде <i>Wordle</i> или <i>Flappy Bird</i>.</p><p>Поэтому эксперты воспринимают обещания Google с осторожностью — для по-настоящему автономного вайб-кодинга нужно, чтобы ИИ умел проектировать архитектуру, писать оптимизированный код и тестировать его без участия человека.</p><p>Тем не менее, Google, по слухам, готовит к релизу <b>Gemini 3.0</b>, который может радикально улучшить креативные и кодогенерационные возможности.</p><p>Если планы компании сбудутся, то к концу года видеоигра мечты может начаться не с кода, а с фразы:</p><blockquote><i>«Сделай мне космический шутер, где коты сражаются против пылесосов».</i></blockquote>]]></content:encoded>
    </item>
    <item>
      <title>Создание стильных интерфейсов на Python с использованием GIMP</title>
      <link>https://tproger.ru/articles/sozdanie-stilnyh-interfejsov-na-python-s-ispolzovaniem-gimp</link>
      <comments>https://tproger.ru/articles/sozdanie-stilnyh-interfejsov-na-python-s-ispolzovaniem-gimp?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Татьяна Жукова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/sozdanie-stilnyh-interfejsov-na-python-s-ispolzovaniem-gimp</guid>
      <description><![CDATA[<p>Узнайте, как создавать стильные интерфейсы для Python-приложений с помощью библиотеки Маниша Катурии и графического редактора GIMP или MS Paint. Простое решение для интерактивных GUI с поддержкой нестандартных элементов.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/sozdanie-stilnyh-interfejsov-na-python-s-ispolzovaniem-gimp">Создание стильных интерфейсов на Python с использованием GIMP</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Дизайн]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sat, 04 Oct 2025 10:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Разработка графических пользовательских интерфейсов (GUI) может быть сложной задачей, требующей специализированных инструментов и подходящей библиотеки. Для тех, кто ищет простое и легковесное решение, стоит<a href="https://hackaday.com/2025/09/29/creating-python-guis-with-gimp/"> рассмотреть комбинацию</a> графического редактора и библиотеки Python, созданной Манишем Катурией.</p><p>Целью Маниша было разработать инструмент для создания визуально привлекательных интерфейсов, который был бы прост в использовании. Он считал, что популярные библиотеки по типу Tkinter, требуют большого объема кода и часто дают неудовлетворительные результаты. Его решение позволяет применять любые графические элементы в качестве объектов интерфейса, открывая широкие возможности для дизайна. Особое внимание уделено поддержке нестандартных элементов управления — кнопки и слайдеры необычной формы, что недоступно во многих других инструментах.</p><p>Библиотека работает с многослойными изображениями, позволяя создавать интерактивные интерфейсы с минимальным количеством кода для настройки их параметров и поведения. При этом нет привязки к конкретному редактору — например, в некоторых демонстрациях используется MS Paint вместо GIMP. Видео <a href="https://github.com/GIMPyWidgetUI/GIMPyWidgetUI-Demo">доступны на GitHub</a> для всех желающих протестировать библиотеку. Публикуем одно из них:</p><p>Также можно узнать и о других инструментах для разработки GUI, например, о библиотеке для встраиваемых систем. Подробности и демонстрацию работы можно посмотреть <a href="https://hackaday.com/2025/06/18/zpui-could-be-your-tiny-embedded-gui/">здесь</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Space Invaders «с нуля» — Часть 1, создаём окно</title>
      <link>https://tproger.ru/articles/space-invaders--s-nulya----chast-1--sozdayom-okno</link>
      <comments>https://tproger.ru/articles/space-invaders--s-nulya----chast-1--sozdayom-okno?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Даровская Маша]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/space-invaders--s-nulya----chast-1--sozdayom-okno</guid>
      <description><![CDATA[<p>Старт серии по созданию клона Space Invaders на C++: настраиваем окно и контекст OpenGL 3.3 с GLFW и GLEW, собираем проект и запускаем первый «красный» кадр.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/space-invaders--s-nulya----chast-1--sozdayom-okno">Space Invaders «с нуля» — Часть 1, создаём окно</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[OpenGL]]></category>
      <category><![CDATA[HTML]]></category>
      <category><![CDATA[macOS]]></category>
      <category><![CDATA[Игра]]></category>
      <category><![CDATA[Xcode]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[1C]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 02 Oct 2025 12:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Это перевод <a href="https://nicktasios.nl/posts/space-invaders-from-scratch-part-1.html">статьи</a> автора Nick Tasios.</p><p>Автор написал клон классической аркады Space Invaders на C++, опираясь всего на пару зависимостей. В этой части мы подготовим окно и контекст OpenGL 3.3, используя GLFW и GLEW — это единственные внешние библиотеки, которые понадобятся на старте.</p><h2>Что такое Space Invaders</h2><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-10-01/491e2f60-9c59-4936-bd1e-0932e65000be.png" alt="" /></figure><p>Space Invaders — аркадная игра 1978 года. Это 2D-шутер с горизонтальным управлением: игрок двигает пушку вдоль нижней границы экрана и стреляет по строю инопланетян. За каждого сбитого врага начисляются очки. Периодически по верхней части экрана пролетает НЛО — если сбить, получите бонусные очки. По мере уничтожения инопланетян игра ускоряется. Враги тоже стреляют случайно, приближаясь к низу экрана; попадание по игроку отнимает жизнь. Пушку частично прикрывают бункеры, но они постепенно разрушаются как под выстрелами врагов, так и самим игроком. После зачистки волны появляется новая, а бункеры восстанавливаются. Игра заканчивается, если бункеры полностью разрушены, инопланетяне достигли низа экрана или у игрока закончились жизни.</p><h3>Постановка целей</h3><p>Важно определить цели до начала проекта. Мы не собираемся дотошно воссоздавать оригинал — сделаем «space-invaders-like» прототип с базовыми элементами. В геймдеве обычно сначала собирают «грубый» прототип, чтобы проверить ядро механик, а «полировать» будем позже.</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-10-01/721c66cf-7153-45fb-90a7-655561da422e.png" alt="" /></figure><p>В прототипе нужны:</p><ul><li>управляемая игроком пушка;</li><li>волны инопланетян, которые постепенно движутся к пушке;</li><li>стрельба у обеих сторон.</li></ul><p>НЛО и бункеры на первом этапе опустим (их несложно добавить потом).</p><p>Почти любую игру можно разложить на базовые элементы (очень советую <a href="https://www.youtube.com/watch?v=zyVTxGpEO30">доклад</a> Raph Koster). В Space Invaders это движение и стрельба (а значит — детекция столкновений). Даже простой клон поможет прокачать понимание геймлупа, коллизий и правил игры.</p><p>Поехали!</p><h2>Hello Window</h2><p>Окно можно создать по-разному: нативные API (Cocoa/X11/WinAPI) или кроссплатформенные библиотеки (Qt, GLFW). Нативный путь даёт полный контроль, но ради простоты и кроссплатформенности возьмём GLFW: лёгкая, простая C-API.</p><p>Подключим заголовки (стандартный ввод/вывод и GLFW):</p><p>Это откроет окно 640×480 с заголовком Space Invaders и контекстом OpenGL. Два последних параметра glfwCreateWindow — монитор для фуллскрина и «шаринг» контекста между окнами. При неудаче вызываем glfwTerminate(). Важно: нужно «привязать» контекст текущему потоку (glfwMakeContextCurrent), чтобы последующие вызовы OpenGL применялись к нему.</p><p>По умолчанию версия контекста не гарантируется — попросим минимум 3.3 Core (задать до создания окна):</p><p>Почему нужен загрузчик функций OpenGL. OpenGL — это спецификация; реализация зависит от GPU/драйвера/ОС. Множество функций нужно загружать в рантайме. Делать это вручную неудобно, поэтому используют лоадеры. Здесь — GLEW (можно и GLAD, но в статье выбран GLEW).</p><p>Важно: подключаем GLEW до glfw3.h:</p><h2>Игровой цикл (Game loop)</h2><p>Если запустить код сейчас, окно мигнёт и программа завершится. Нужен бесконечный game loop, где мы обрабатываем ввод, обновляем состояние и рисуем кадр:</p><ul><li>Буферы. Современный OpenGL рисует в «задний» буфер, а «передний» отображается на экране. glfwSwapBuffers() меняет их местами.</li><li>События. glfwPollEvents() вынимает накопившиеся события (клавиатура, мышь, закрытие окна).</li><li>Выход. glfwWindowShouldClose() станет true, если пользователь нажал «крестик».</li></ul><p>В конце корректно освобождаем ресурсы:</p><h2>Компиляция</h2><p>Ниже — команды из оригинала (C++11), плюс современные примечания.</p><p>Обратите внимание, что позже мы будем использовать некоторые функции C++11, поэтому компилируем с помощью -std=c++11. В обоих случаях убедитесь, что у вас установлен GLFW 3. В Linux, в зависимости от вашего дистрибутива, вы можете использовать менеджер пакетов. Например, в Ubuntu GLFW можно установить с помощью следующей команды:</p><p>На Mac OS X автор предпочитает использовать <a href="https://brew.sh/">Homebrew</a>:</p><p>Возможно, <a href="https://www.monocilindro.com/2017/02/14/how-to-install-glfw-library-on-visual-studio-c-2015/">эта статья</a> поможет вам настроить проект GLFW в Visual Studio.</p><p>Если всё собрано успешно, вы увидите красное окно с заголовком Space Invaders.</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-10-01/49e56b4a-e080-4074-91b4-b289af58fba1.png" alt="" /></figure><h2>Итоги</h2><p>Даже просто «поднять окно» с контекстом OpenGL на C++ — задача не из быстрых, несмотря на помощь GLFW. Мы пока ничего не рисуем; настройка простейшего рендера в современном OpenGL тоже требует подготовки. Хорошая новость — делать это придётся один раз, а дальше вы переиспользуете базу в следующих частях (шейдеры, VBO/VAO, спрайты, коллизии и т. д.).</p><p>Вторая часть статьи — <a href="https://tproger.ru/articles/space-invaders--s-nulya----chast-2--nastraivaem-wejdery-opengl-i-risuem-sprajt-priwelca">здесь</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Глава 1.1. Развертывание StarRocks — сборка из исходников</title>
      <link>https://tproger.ru/articles/glava-1-1--razvertyvanie-starrocks---sborka-iz-ishodnikov</link>
      <comments>https://tproger.ru/articles/glava-1-1--razvertyvanie-starrocks---sborka-iz-ishodnikov?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[StarRocks]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/glava-1-1--razvertyvanie-starrocks---sborka-iz-ishodnikov</guid>
      <description><![CDATA[<p>Как выбрать релиз StarRocks, настроить Docker и собрать из исходников (FE/BE и Broker): dev-env, build.sh, ACR image accelerator, containerd, советы по AVX2/ARM.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/glava-1-1--razvertyvanie-starrocks---sborka-iz-ishodnikov">Глава 1.1. Развертывание StarRocks — сборка из исходников</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[Docker]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 28 Sep 2025 10:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Перед развертыванием StarRocks часто встает вопрос выбора версии. На GitHub доступны архивы исходных кодов всех релизов, а на официальном сайте публикуются готовые бинарные пакеты для x86 (CentOS 7+). Рекомендуем ориентироваться на следующие принципы:</p><ul><li>Тестовая среда: используйте последний стабильный релиз (например, 3.5.6; см. страницу Tags на GitHub).</li><li>Staging (предпроизводственная) и Production (производственная) среды: используйте последний минорный релиз предыдущей стабильной ветки.</li><li>Если требуется новый функционал или критическая фиксация, можно собрать из актуального кода ветки main, используя официальный Docker-образ сборочного окружения.</li><li>Компонент BE (Backend) требует CPU с поддержкой AVX2. Возможна сборка без AVX2 (работоспособно, но не рекомендуется — нет полноценного покрытия тестами).</li><li>Начиная с 1.19 StarRocks поддерживает ARM, но потребует самостоятельной сборки на ARM-хосте (официальные готовые бинарники под ARM пока не публикуются).</li></ul><p>Справочные ссылки:</p><ul><li>Страница Tags (например, 3.5.6, 4.0.0-rc01): <a href="https://github.com/StarRocks/starrocks/tags">https://github.com/StarRocks/starrocks/tags</a></li><li>Release Notes 1.19 (сообщество): <a href="https://forum.mirrorship.cn/t/topic/552">https://forum.mirrorship.cn/t/topic/552</a></li></ul><p>Ниже — пример сборки из актуального кода ветки main с использованием официального Docker-образа.</p><h2>1. Установка Docker и загрузка сборочного образа</h2><p>Для примера используется CentOS 7.6 в виртуальной машине (рекомендуется ≥2 vCPU и ≥4 ГБ RAM). Во время сборки требуется стабильное сетевое подключение.</p><h3>1.1 Установка Docker</h3><h3>1.2 Запуск Docker и автозапуск</h3><h3>1.3 Проверка установки</h3><p>При успешном выполнении отобразится сообщение “Hello from Docker!”.</p><h3>1.4 Ускорение загрузки образов (для нестабильных каналов)</h3><p>Если загрузка официальных образов Docker медленная/нестабильная, можно использовать сервисы Alibaba Cloud Container Registry (ACR). Важно: официальный <a href="https://help.aliyun.com/zh/acr/user-guide/accelerate-the-pulls-of-docker-official-images">ACR image accelerator</a> больше не синхронизирует последние образы. Если образ не скачивается или тег latest не содержит актуальную версию, воспользуйтесь альтернативами:</p><ul><li>Подписка в ACR на зарубежные исходные образы (subscription of overseas source images).</li><li>Использование GA (Global Accelerator) для ускорения прямого доступа к зарубежным реестрам.</li></ul><p>Рекомендация для Production: минимизируйте зависимость от Docker Hub из‑за сетевых рисков.</p><p>Если вы используете containerd:</p><ul><li>Убедитесь, что в /etc/containerd/config.toml задан config_path, например:
[plugins."io.containerd.grpc.v1.cri".registry]
  config_path = "/etc/containerd/certs.d"
</li><li>Уберите конфликтующие mirrors (если есть), перезапустите containerd:
sudo systemctl restart containerd
</li><li>При ошибке старта изучите вывод:
journalctl -u containerd
</li><li>Создайте файл /etc/containerd/certs.d/docker.io/hosts.toml:
server = "https://registry-1.docker.io"

[host."https://&lt;your-ACR-accelerator-address&gt;"]
  capabilities = ["pull", "resolve", "push"]
</li></ul><h3>1.5 Загрузка сборочного образа StarRocks</h3><p>Выбирайте тег образа в соответствии с веткой/версией исходников (для ветки main — тег main; для ветки 3.5 — тег 3.5 и т. п.):</p><h3>1.6 Просмотр локальных образов</h3><h2>2. Получение исходников StarRocks</h2><h3>2.1 Клонирование из GitHub или скачивание архива</h3><p>Стандартно:</p><p>Если из‑за сетевых ограничений возникают ошибки (например, EOF), можно:</p><ul><li>использовать зеркало GitHub (пример):
git clone https://github.com.cnpmjs.org/StarRocks/starrocks.git
</li><li>либо скачать архив кода из браузера:
<a href="https://github.com/StarRocks/starrocks">https://github.com/StarRocks/starrocks</a></li><li>архив конкретного релиза:
<a href="https://github.com/StarRocks/starrocks/tags">https://github.com/StarRocks/starrocks/tags</a></li></ul><p>Чтобы ускорить клонирование, добавьте --depth 1 (если не требуется полная история).</p><h3>2.2 Загрузка архива на сервер и распаковка (вариант с ZIP)</h3><h3>2.3 Запуск контейнера со сборочным окружением и монтированием кэшей</h3><p>Рекомендуется смонтировать локальный Maven-кэш (~/.m2) для ускорения повторных сборок.</p><p>(Опционально — подключите ccache, смонтировав ~/.ccache, если это поддерживается образом.)</p><h3>2.4 Проверка запущенных контейнеров</h3><h3>2.5 Вход в контейнер</h3><h3>2.6 Переход в каталог исходников</h3><h3>2.7 Сборка FE и BE</h3><p>Скрипт скачает зависимости и выполнит сборку (может занять значительное время). Благодаря монтированию ~/.m2 зависимости будут переиспользованы в следующих сборках.</p><p>Результаты сборки — в каталоге output/:</p><h3>Сборка без AVX2 (только при необходимости; не рекомендуется)</h3><p>Измените build.sh, чтобы принудительно отключить AVX2:</p><p>Измените сборку сторонней библиотеки в thirdparty/build-thirdparty.sh (блок croaring):</p><p>Повторно выполните ./build.sh. Учтите: такой вариант не имеет полноценного покрытия тестами.</p><p><b>Полезные опции build.sh</b></p><h3>2.8 Сборка Broker</h3><p>Broker не собирается шагом выше — его нужно собирать отдельно:</p><p>Готовые файлы появятся в</p><p>.</p><h3>2.9 Выход и повторный запуск контейнера при необходимости</h3><p>Так как каталог с исходниками смонтирован в контейнер, результаты сборки доступны на хосте.</p><h2>Примечания и рекомендации</h2><ul><li>FE (Frontend) и BE (Backend) — основные компоненты StarRocks, сборка которых выполняется скриптом build.sh.</li><li>Для воспроизводимости привязывайте тег сборочного Docker-образа к ветке/версии исходников (например, starrocks/dev-env:3.5 для ветки 3.5.x).</li><li>Для ускорения повторных сборок используйте кэш Maven (~/.m2) и, при возможности, ccache для C++.</li><li>ARM: официальный сборочный Docker-образ пока не рассчитан на ARM. Для ARM-сборки потребуется нативный ARM-хост и корректные версии зависимостей (JDK, CMake и др.).</li><li>Список актуальных релизов и тегов: <a href="https://github.com/StarRocks/starrocks/tags">https://github.com/StarRocks/starrocks/tags</a></li><li>Release Notes 1.19 (сообщество): <a href="https://forum.mirrorship.cn/t/topic/552">https://forum.mirrorship.cn/t/topic/552</a></li></ul><p>После этих шагов у вас будут собранные бинарные артефакты FE/BE и Broker, готовые к дальнейшему развертыванию кластера StarRocks.</p>]]></content:encoded>
    </item>
    <item>
      <title>2 млрд загрузок под ударом: в npm нашли вредоносные версии chalk, debug и еще 16 пакетов</title>
      <link>https://tproger.ru/news/--2-mlrd-zagruzok-pod-udarom--v-npm-nawli-vredonosnye-versii-chalk--debug-i-eshhe-16-paketov</link>
      <comments>https://tproger.ru/news/--2-mlrd-zagruzok-pod-udarom--v-npm-nawli-vredonosnye-versii-chalk--debug-i-eshhe-16-paketov?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/--2-mlrd-zagruzok-pod-udarom--v-npm-nawli-vredonosnye-versii-chalk--debug-i-eshhe-16-paketov</guid>
      <description><![CDATA[<p>В npm обнаружили вредоносные версии chalk, debug и ещё 16 пакетов: заражение коснулось проектов с 2 млрд загрузок, цель атаки — кража криптовалют</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/--2-mlrd-zagruzok-pod-udarom--v-npm-nawli-vredonosnye-versii-chalk--debug-i-eshhe-16-paketov">2 млрд загрузок под ударом: в npm нашли вредоносные версии chalk, debug и еще 16 пакетов</a>»</p>]]></description>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[JSON]]></category>
      <category><![CDATA[Ethereum]]></category>
      <category><![CDATA[Взлом]]></category>
      <category><![CDATA[Уязвимость]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 09 Sep 2025 04:29:19 GMT</pubDate>
      <content:encoded><![CDATA[<p>Компания Aikido Security <a href="https://www.aikido.dev/blog/npm-debug-and-chalk-packages-compromised">выявила</a> масштабную атаку на экосистему npm. Злоумышленники опубликовали вредоносные версии 18 популярных JavaScript-библиотек, включая chalk, debug, supports-color, ansi-styles, strip-ansi и другие.</p><p>Эти пакеты используются в миллионах проектов по всему миру — общее количество загрузок только за неделю превышает 2 млрд.</p><h2>Как работал вредоносный код</h2><p>Внедренный JavaScript-код маскировался внутри библиотек и выполнялся исключительно в браузерной среде. Основная цель — перехват криптовалютных транзакций через подмену данных:</p><ul><li>внедрение в методы fetch, XMLHttpRequest, а также Web3-объекты (window.ethereum и др.);</li><li>отслеживание и подмена адресов кошельков при вызовах вроде sendTransaction, approve, transfer;</li><li>использование «похожих» адресов для подмены без визуального отличия;</li><li>манипуляции с параметрами транзакций на этапе подписи;</li><li>сохранение внешней «нормальности» интерфейса, чтобы пользователь ничего не заметил.</li></ul><p>Таким образом, атака была нацелена на незаметное хищение криптоактивов прямо из интерфейсов Web3-приложений.</p><h2>Как злоумышленники получили доступ</h2><p>Один из мейнтейнеров, обладающий доступом к части библиотек, стал жертвой фишинговой атаки.</p><p>Он получил письмо с поддельного адреса support@npmjs.help, зарегистрированного 5 сентября 2025 года. После компрометации аккаунта были опубликованы вредоносные версии пакетов.</p><p>Автор позднее подтвердил взлом и удалил некоторые версии, но часть вредоносных сборок осталась доступной, включая simple-swizzle.</p><h2>Список затронутых пакетов</h2><p>Наиболее популярные зараженные библиотеки:</p><ul><li>chalk</li><li>debug</li><li>supports-color</li><li>strip-ansi</li><li>ansi-regex</li><li>wrap-ansi</li><li>color-name</li><li>color-convert</li><li>color-string</li><li>chalk-template</li><li>has-flag</li><li>has-ansi</li><li>slice-ansi</li><li>error-ex</li><li>simple-swizzle</li><li>backslash</li><li>и другие</li></ul><p>Большинство из них используются транзитивно — через другие зависимости.</p><h2>Что делать разработчикам</h2><ol><li>Проверить package-lock.json или yarn.lock на наличие зараженных версий.</li><li>Использовать npm audit, snyk, Safe Chain или аналогичные инструменты для анализа зависимостей.</li><li>Обновить или зафиксировать безопасные версии пакетов.</li><li>Если проект работает с криптовалютой, проверить, не было ли компрометации в процессе использования.</li></ol><h2>Почему это важно</h2><p>Эта атака стала одной из крупнейших в истории JavaScript-экосистемы и подчеркивает уязвимость цепочек поставки (supply chain) в open-source.</p><p>Даже небольшая уязвимость или фишинговая атака на одного мейнтейнера может поставить под угрозу миллионы пользователей по всему миру.</p>]]></content:encoded>
    </item>
    <item>
      <title>SolidJS и Qwik: фронтенд нового поколения</title>
      <link>https://tproger.ru/articles/solidjs-i-qwik--frontend-novogo-pokoleniya</link>
      <comments>https://tproger.ru/articles/solidjs-i-qwik--frontend-novogo-pokoleniya?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Вадим Егорцев]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/solidjs-i-qwik--frontend-novogo-pokoleniya</guid>
      <description><![CDATA[<p>Обзор SolidJS и Qwik — плюсы и минусы фреймворков. Сравнение SolidJS и Qwik, практические рекомендации по переходу и тенденция отказа от React/Vue.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/solidjs-i-qwik--frontend-novogo-pokoleniya">SolidJS и Qwik: фронтенд нового поколения</a>»</p>]]></description>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[CSS]]></category>
      <category><![CDATA[React]]></category>
      <category><![CDATA[Фреймворки и библиотеки]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[Angular]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Vue]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 03 Sep 2025 12:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p><b>Помните, когда впервые попробовали React/Vue после JS и jQuery?</b> Тот момент, когда всё встало на свои места, и вы поняли — вот оно, будущее фронтенда. В 2025 году разработчики <a href="https://www.reddit.com/r/solidjs/comments/1m4hlzj/im_really_impressed_with_solid/">испытывают</a> похожие чувства с SolidJS и Qwik.</p><h2>Последний рубеж React и Vue</h2><p><b>Согласны, что VDOM превратился в бюрократическую прослойку?</b> Изменили состояние в одном месте — получите полный пересчёт дерева компонентов. Фреймворки заставляют загружать всё сразу, тащат багаж служебного кода. И пока этот код не загрузится, пользователь смотрит на белый экран.</p><p>SSR <a href="https://tproger.ru/translations/rendering-on-the-web">ускоряет</a> загрузку страницы: сервер рендерит HTML, пользователь видит контент и пытается с ним взаимодействовать. Но пока JavaScript не загрузится, ничего не заработает.</p><p>Потом JS наконец подгружается и начинает гидратацию. По сути, он заново создаёт в памяти то же дерево компонентов, которое сервер уже отрендерил в HTML. Выполняется двойная работа. Кстати, в это время пользователь тыкает неработающие кнопки — дотерпит ли он до полной загрузки?</p><p>Системные проблемы не исправить очередным хуком или новой версией фреймворка, поэтому появление SolidJS и Qwik — было вопросом времени.</p><blockquote>Поиск новых решений — здоровый признак развития фронтенда. В конце концов, и Vue был создан потому, что Эвану Ю не хватало облегченной альтернативы AngularJS. Большая тройка фреймворков решает огромный спектр задач, имеет колоссальную поддержку сообщества, но их нельзя назвать идеальным инструментом на все случаи жизни.</blockquote><h2>Обзор SolidJS</h2><p>SolidJS во многом похож на React. Самое интересное — его подход к обновлению интерфейса:</p><ul><li><b>Отсутствие виртуального DOM</b> — Solid напрямую обновляет только те DOM-узлы, которые действительно изменились.</li><li><b>Компоненты как функции инициализации</b> — каждый компонент вызывается только один раз для настройки реактивности.</li><li><b>Сигналы вместо хуков</b> — состояние управляется через createSignal(), который возвращает геттер/сеттер пару.</li></ul><p>Например, когда срабатывает счётчик, Solid не перерисовывает весь компонент. Он точечно обновляет только текст внутри &lt;p&gt;, где используется count():</p><h3>Преимущества SolidJS</h3><p>👍 <b>Производительность и размер бандла</b></p><p>Благодаря отсутствию виртуального DOM и мелкозернистым обновлениям, приложения <a href="https://www.reddit.com/r/reactjs/comments/tsx8hw/solidjs_devex_compared_to_react/?tl=ru">работают</a> быстрее аналогов на React.</p><p>👍 <b>Простота освоения</b></p><p>Синтаксис SolidJS похож на React. Функциональные компоненты, JSX, концепции вроде Suspense и Error Boundaries — всё это есть в Solid. Изучение основ <a href="https://www.reddit.com/r/solidjs/comments/1len1pf/comment/myi8qci/?utm_source=share&amp;utm_medium=web3x&amp;utm_name=web3xcss&amp;utm_term=1&amp;utm_content=share_button">займёт</a> 1-2 дня, если есть опыт с MobX/effector/RxJS.</p><p>👍 <b>Стабильность</b></p><p>Фреймворк находится на стабильной версии 1.x. Это означает отсутствие кардинальных изменений API, в отличие, например, от ситуации со Svelte, где сосуществуют версии 4 и 5 с разными подходами.</p><p>👍 <b>Совместимость с React</b></p><p>SolidJS совместим с экосистемой React. Можно переиспользовать дизайн-системы и компоненты в legacy-приложениях.</p><p>👍 <b>Удобное управление состоянием</b></p><p>Функционал сигналов и сторов покрывают 90% потребностей в управлении состоянием без необходимости подключать внешние библиотеки.</p><h3>Минусы SolidJS</h3><p>👎 <b>Ограниченная экосистема</b></p><p>Выбор готовых компонентов и библиотек значительно меньше, чем у React. Команды тратят больше времени на создание компонентов с нуля: тяжко при работе с таблицами, гридами, формами, валидацией.</p><p>👎 <b>Кривая обучения</b></p><p>Несмотря на знакомый синтаксис, модель реактивности SolidJS отличается от React. Разработчики должны усвоить следующие принципы:</p><ul><li>Избегать условных конструкций непосредственно в компонентах.</li><li>Не деструктурировать пропсы и сторы, чтобы сохранить реактивность.</li><li>Не использовать асинхронный код внутри createEffect.</li></ul><p>👎 <b>Проблемы с инструментарием</b></p><p>Возникают сложности с настройкой компилятора в нестандартных окружениях — монорепозиториях, при запуске тестов или интеграции с другими инструментами. DevTools не дотягивает до аналога у React.</p><p>👎 <b>SolidStart всё ещё развивается</b></p><p>SSR-решение SolidStart пока не достигло зрелости Next.js или Nuxt. Разработчики <a href="https://www.reddit.com/r/solidjs/comments/1len1pf/comment/myml5tt/?utm_source=share&amp;utm_medium=web3x&amp;utm_name=web3xcss&amp;utm_term=1&amp;utm_content=share_button">сообщают</a> о проблемах с гидратацией и других сложностях при работе с серверным рендерингом.</p><h2>Обзор Qwik</h2><p>Qwik — это проект Мишко Хевери (создателя Angular). Идея фреймворка заключается в возможности возобновить работу приложения на клиенте без повторного выполнения кода, который уже был выполнен на сервере.</p><p>В Qwik радикально решили проблему гидратации — полностью отказались от неё. Время до интерактивности (TTI) падает в разы. Пользователь может кликать на кнопки сразу после загрузки HTML, без ожидания разогрева всего приложения.</p><p>Qwik автоматически разбивает код на мелкие чанки и загружает их только при необходимости. Символ $ в коде указывает на границы ленивой загрузки.</p><h3>Плюсы Qwik</h3><p>👍 <b>Мгновенная загрузка</b></p><p>Практически нулевой JavaScript при первоначальной загрузке, следовательно отличные показатели Core Web Vitals.</p><p>👍 <b>Автоматическая оптимизация</b></p><p>Оптимизация на уровне компилятора, умная предзагрузка критических ресурсов. Не нужно думать о разделении кода — Qwik делает это автоматически.</p><p>👍 <b>Знакомый синтаксис</b></p><p>👍 <b>Спасибо за SEO</b></p><p>Быстрая загрузка улучшает ранжирование за счёт полноценного SSR из коробки.</p><h3>Минусы Qwik</h3><p>👎 <b>Молодая экосистема</b></p><p>Ограниченное количество библиотек, мало готовых решений и компонентов. Небольшое сообщество разработчиков (если сравнивать с React/Vue).</p><p>👎 <b>Кривая обучения</b></p><p>Придётся изучать новые концепции. Из-за ленивой загрузки усложняется отладка.</p><blockquote>Qwik — это радикально новая ментальная модель. У фреймворка высокий порог входа: вас ждёт переобучение команды и сложности ручной оптимизации. Чтобы Qwik работал идеально, разработчик должен вручную указывать, что можно лениво загружать, а что нет.</blockquote><p>👎 <b>Сложность интеграции</b></p><p>Трудно интегрировать существующие React/Vue компоненты и ограниченная поддержка сторонних библиотек. Скорее всего, придётся с нуля переписывать код существующего проекта.</p><h2>Экосистема и готовность к продакшену</h2><p>Если сравнивать с React, то экосистема — самое слабое место обоих фреймворков.</p><p>SolidJS имеет SolidStart — метафреймворк с роутингом, SSR и серверными функциями. <a href="https://docs.solidjs.com/quick-start">Документация</a> качественная, сообщество активное. Большинство React-библиотек можно адаптировать без особых проблем, для популярных UI-китов есть готовые порты.</p><p>Qwik развивается в связке с <a href="https://qwik.dev/docs/qwikcity/">Qwik City</a>, который покрывает типовые задачи веб-разработки. <a href="https://www.builder.io/m/qwik">Builder.io</a> активно инвестирует в экосистему, регулярно выходят обновления и новые интеграции.</p><p>Риски есть, но они управляемые. Меньший размер сообщества означает меньше готовых решений и ответов на Stack Overflow. Если не боитесь изучать новое, то выигрыш в производительности перевесит неудобства.</p><h2>Сравнение SolidJS и Qwik</h2><p>SolidJS повышает производительность обновлений. Если данные меняются часто и непредсказуемо — графики, мониторинги, редакторы — Solid даст максимальную отзывчивость.</p><p>Qwik повышает производительность загрузки. Если бизнес зависит от первого впечатления, Qwik обеспечит мгновенный старт.</p><p><b>Медиа</b>, <b>блоги</b> с жёсткими требованиями к TTFB/TTI/INP будут лучше работать на Qwik. Пользователи смогут читать и скроллить без задержки. Интерактив добавляется дозированно — это лучшая стартовая стоимость.</p><p><b>E-commerce</b>, <b>каталоги </b>с SEO и карточками рекомендуется разрабатывать на Qwik. Особенно если на главной тяжёлые модули, а клиенты приходят с поисковиков. Вы выигрываете у конкурентов буквально на первом взаимодействии.</p><p><b>Сложный SPA</b> или <b>дашборд </b>с живыми виджетами и апдейтами будет лучше работать на SolidJS. Точечная реактивность упростит жизнь и снизит цену апдейтов. Solid сияет в проектах, где происходят сотни мелких изменений в секунду.</p><blockquote>Solid хорош для аналогов десктопных приложений в браузере — Figma, Miro. Здесь приложение загружается один раз, а потом работает долго и должно быть максимально отзывчивым. Также Solid будет хорош там, где важна плавность анимаций.</blockquote><p><b>Лэндинги</b>, <b>мобильные приложения</b>, <b>визитки</b> — здесь Solid даст сверхбыструю реактивность и облегчит сборку.</p><p>Оба фреймворка умеют SSR/SSG и стриминг. Solid снижает стоимость обновлений, Qwik — стоимость старта. Для LCP/TTI/INP в контентных сценариях выигрывает Qwik. Для интенсивных интерактивных сценариев Solid удерживает FPS и снижает CPU.</p><p>Оба дружат с серверными платформами. SolidStart имеет адаптеры для Vercel/Netlify, Qwik City — тоже.</p><blockquote>Выбирайте Solid.js, если вы создаете сервис, куда пользователь заходит надолго, и ему важна отзывчивость после загрузки. Выбирайте Qwik, если вы создаете сайт, куда пользователь приходит за контентом, и важно показать ему этот контент мгновенно.</blockquote><p>Немного выводов:</p><ul><li>Solidjs быстрее Qwik при рендеринге. Qwik быстрее Solidjs при загрузке страниц.</li><li>У Solidjs документация лучше, чем у Qwik.</li><li>С нуля код на Qwik писать проще и быстрее, чем на SolidJS.</li><li>Typescript в SolidJS может быть головной болью, в Qwik об этом можно не беспокоиться.</li></ul><h2>Практические рекомендации по переходу на SolidJS и Qwik</h2><ol><li><b>Начните с аудита текущих проблем</b>. Посмотрите метрики сайта: сколько времени занимает гидратация? Тормозят ли обновления интерфейса? Где именно проблема — на старте или в процессе работы?</li><li><b>Выберите изолированную часть проекта</b>. Возьмите один виджет, одну страницу, один компонент и реализуйте его на новом фреймворке. Измерьте разницу в производительности и удобстве разработки.</li><li><b>Если проблема в медленной загрузке</b> — попробуйте Qwik. Соберите прототип лендинга или каталога, включите SSG с resumability и протестируйте на медленном соединении.</li><li><b>Если проблема в тормозах интерфейса</b> — попробуйте Solid. Перепишите самый страдальный компонент с частыми обновлениями, уберите мемоизации и посмотрите на результат.</li></ol><p>Оба фреймворка собираются через Vite, имеют TypeScript из коробки и хорошую интеграцию с популярными инструментами. Стоимость эксперимента низкая, а потенциальная выгода высокая.</p><h2>Тенденция отказа от React/Vue</h2><blockquote>Компании и разработчики не столько отказываются от популярных решений, сколько перестают использовать их для всех задач подряд. Раньше выбора практически не было, и эти фреймворки были молотком, для которого любая задача — гвоздь.</blockquote><p><i>А вы что думаете? Готовы попробовать модные фреймворки SolidJS и Qwik в следующем проекте?</i></p>]]></content:encoded>
    </item>
    <item>
      <title>Как бэкдор в xz чуть не стал самой масштабной атакой на Linux в истории</title>
      <link>https://tproger.ru/news/kak-bekdor-v-xz-chut-ne-stal-samoj-maswtabnoj-atakoj-na-linux-v-istorii</link>
      <comments>https://tproger.ru/news/kak-bekdor-v-xz-chut-ne-stal-samoj-maswtabnoj-atakoj-na-linux-v-istorii?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/kak-bekdor-v-xz-chut-ne-stal-samoj-maswtabnoj-atakoj-na-linux-v-istorii</guid>
      <description><![CDATA[<p>Бэкдор в xz едва не стал крупнейшей атакой на Linux: злоумышленники три года внедрялись в проект, а уязвимость спас случайно найденная задержка SSH</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/kak-bekdor-v-xz-chut-ne-stal-samoj-maswtabnoj-atakoj-na-linux-v-istorii">Как бэкдор в xz чуть не стал самой масштабной атакой на Linux в истории</a>»</p>]]></description>
      <category><![CDATA[Интернет]]></category>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Microsoft]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Взлом]]></category>
      <category><![CDATA[Уязвимость]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 02 Sep 2025 09:29:37 GMT</pubDate>
      <content:encoded><![CDATA[<p>29 марта инженер Microsoft Андрес Фройнд заметил, что SSH-подключение к его тестовой машине на Debian стало медленнее на 500 мс. И эта задержка спасла интернет. В сети появился материал, который <a href="https://fastcode.io/2025/09/02/the-hidden-vulnerabilities-of-open-source/">описал</a> эту интересную историю.</p><p>Так, проведя диагностику, Фройнд обнаружил скрытый вредоносный код в библиотеке <i>xz</i> — она используется практически во всех дистрибутивах Linux и задействуется при работе с SSH.</p><p><b>Бэкдор позволял обойти аутентификацию и получить полный удалённый доступ к системе без следов в логах.</b></p><p>Под ударом оказались Fedora, Debian, openSUSE, Arch и готовящийся релиз Ubuntu 24.04. Его внедрение произошло в xz версий 5.6.0 и 5.6.1 в феврале и марте 2024 года. Если бы Фройнд не заметил задержку — миллионы серверов оказались бы взломаны.</p><h2>Атака на человека, не на код</h2><p>Самое страшное, что атака эта длилась <b>три года</b> и была направлена <b>не на уязвимость в коде</b>. Она целилась <b>на уязвимость в человеке</b> — <i>Лассе Коллине</i>. Это доброволец, который в одиночку поддерживал xz с 2005 года.</p><p>Под именем <i>Jia Tan</i> злоумышленники создали фейкового разработчика, который годами отправлял мелкие патчи, завоёвывал доверие и постепенно получал доступы.</p><p>Параллельно фальшивые аккаунты вроде <i>Jigar Kumar</i> и <i>Dennis Ens</i> психологически давили на Коллина — критиковали его за медленные релизы, упрекали за проблемы с ментальным здоровьем и требовали передать проект «более активным» участникам.</p><p>В итоге выгоревший Коллин отдал проект в руки атакующих. К 2024 году у Jia Tan был полный контроль: доступ к репозиторию, релизам и даже сайту проекта. Остальное — дело техники.</p><h2>«Синдром Небраски»: когда критическую инфраструктуру тащит один человек</h2><p>История с xz — не исключение, а симптом. Open-source в целом как явление держится на людях, которые <b>годами бесплатно поддерживают критически важные библиотеки</b>. Например:</p><ul><li>OpenSSL (Heartbleed) — один разработчик и $2000 бюджета в год;</li><li>Express.js — десятки миллионов скачиваний, один мейнтейнер;</li><li>curl — десятилетия работы Даниэля Стенберга;</li><li>Log4j — критическая уязвимость в библиотеке, которую поддерживал один человек.</li></ul><p>Вот и атака на xz не совсем история про лобовой эксплойт. Это скорее история про системную усталость. Уязвимость была в доверии и выгорании.</p><h2>Мы живем на доброй воле и это проблема</h2><p>Вообще, произошедшее сложно назвать «сбоем open-source». Это сбой модели поддержки подобного софта. <b>Проекты, от которых зависят миллиарды людей, поддерживаются на энтузиазме одного или двух человек</b>. И мы никак это не компенсируем.</p><p>Виноваты не разработчики, а система, где:</p><ul><li>корпорации получают триллионы на бесплатном ПО;</li><li>мало кто инвестирует в его поддержку;</li><li>кризис выгорания решается атаками на выгоревших.</li></ul><h2>Что с этим делать?</h2><p>Некоторые страны и компании уже делают шаги:</p><ul><li><b>Германия</b> выделила €23 млн на поддержку OSS;</li><li><b>ЕС</b> обсуждает фонд в €350 млн;</li><li><b>GitHub</b> и <b>Tidelift</b> пытаются создать модели устойчивого финансирования.</li></ul><p>Но пока это капля в море. Тысячи проектов критичны, а финансируются десятки. И сколько еще таких историй, как атака на xz, нас ждет — покажет лишь время...</p>]]></content:encoded>
    </item>
    <item>
      <title>Куда двигаться после изучения Django: советы для Python-разработчиков</title>
      <link>https://tproger.ru/articles/kuda-dvigatsya-posle-izucheniya-django--sovety-dlya-python-razrabotchikov-257299</link>
      <comments>https://tproger.ru/articles/kuda-dvigatsya-posle-izucheniya-django--sovety-dlya-python-razrabotchikov-257299?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгения Епихина]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kuda-dvigatsya-posle-izucheniya-django--sovety-dlya-python-razrabotchikov-257299</guid>
      <description><![CDATA[<p>В статье разбираемся, почему Django — далеко не финиш в карьере, и в каких направлениях можно двигаться Python-разработчику.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kuda-dvigatsya-posle-izucheniya-django--sovety-dlya-python-razrabotchikov-257299">Куда двигаться после изучения Django: советы для Python-разработчиков</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Парсинг]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[MySQL]]></category>
      <category><![CDATA[Машинное обучение]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Raspberry Pi]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Советы]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Навыки]]></category>
      <category><![CDATA[Django]]></category>
      <category><![CDATA[Docker]]></category>
      <category><![CDATA[Асинхронное программирование]]></category>
      <category><![CDATA[Data Science]]></category>
      <category><![CDATA[NoSQL]]></category>
      <category><![CDATA[Redis]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[аналитик]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Neo4j]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 12 Aug 2025 14:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Django — это веб-фреймворк на языке Python, который позволяет быстро создавать сложные веб-приложения. Он включает в себя готовые компоненты для работы с базами данных, маршрутизацией URL, обработкой форм, аутентификацией пользователей и админ-панелями, что значительно ускоряет разработку и упрощает поддержку проектов.</p><p>Владение Django — это старт, а не финиш. Чтобы оставаться востребованным, нужно постоянно расширять знания и навыки. В этой статье разберем пути и направления для улучшения своих компетенций.</p><h2>Почему владение Django — не предел для разработчика</h2><h2>Особенности Django</h2><p>Django используют для разработки веб-приложений разной сложности: при работе с большими базами данных, для создания сервисов, способных обслуживать большое количество пользователей. На нём создают соцсети, новостные сайты, веб-версии приложений, онлайн-магазины.</p><p>Основные плюсы:</p><ul><li><b>Полноценный стек</b>: ORM для работы с базой, мощная система маршрутизации URL, шаблоны для рендеринга, встроенная админка, формы, система аутентификации и авторизации.</li><li><b>Архитектура MTV (Model-Template-View)</b>: похожа на классический MVC, но с особенностями, которые упрощают разделение логики, представления и данных.</li><li><b>Безопасность</b>: Django автоматически защищает от CSRF, XSS, SQL-инъекций и других распространенных атак. Не нужно писать много дополнительного кода.</li><li><b>Активное сообщество и экосистема</b>: тысячи сторонних пакетов, расширений и готовых решений.</li><li><b>Поддержка нескольких баз данны</b>х: PostgreSQL, MySQL, SQLite, Oracle и др.</li></ul><p>Ограничения:</p><ul><li><b>Синхронная природа Django</b>.</li><li><b>Монолитность</b>: архитектура фреймворка ориентирована на создание крупных приложений, но в микросервисах может быть избыточна.</li><li><b>Ограниченная гибкость ORM</b>: нестандартные SQL-запросы иногда сложно выразить средствами ORM, приходится использовать raw SQL или сторонние библиотеки для запросов.</li><li><b>Строгие правила организации кода</b>: требуют дисциплины и могут ограничивать свободу в архитектурных решениях.</li><li><b>Недостаточная производительность</b>: уступает лёгким асинхронным фреймворкам (например, FastAPI), особенно под высокими нагрузками. Но для большинства проектов пока это не критично.</li></ul><h2>В каком направлении двигаться после изучения Django</h2><blockquote>Задача — создавать продукт, который будет нужен конечному потребителю.</blockquote><h3>Первое направление для развития — расширить инструментарий для решения разных задач в веб-разработке</h3><p>Возможные пути:</p><ul><li>Изучить другие веб-фреймворки (Flask, FastAPI)</li><li>Углубиться в асинхронное программирование (asyncio, aiohttp)</li><li>Работать с API и микросервисами</li></ul><h4>Flask и FastAPI</h4><p>Flask — минималистичный микрофреймворк, даёт полную свободу в выборе компонентов. Используют для небольших приложений и микросервисов.</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-08-12/bbe7c040-14de-426d-9a10-c556f7319bee.png" alt="" /><figcaption>Пример простой команды на Flask</figcaption></figure><p>FastAPI — современный асинхронный фреймворк, ориентирован на создание высокопроизводительных API. Поддерживает стандарт OpenAPI и автоматическую генерацию документации. Он быстрее Flask и Django благодаря asyncio и Pydantic.</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-08-12/33a27277-5136-4a03-8af2-f436db42fa99.png" alt="" /><figcaption>Пример простого API на FastAPI</figcaption></figure><h4>Асинхронное программирование</h4><p>Веб-разработка всё активнее использует асинхронные технологии. Django не всегда справляется с задачами высокой конкурентной нагрузки.</p><p>Поэтому изучение asyncio — стандартной библиотеки Python для асинхронного программирования — откроет перед вами новые возможности. Вместе с aiohttp или тем же FastAPI вы сможете создавать приложения, которые обрабатывают тысячи одновременных соединений. Это особенно важно для real-time сервисов, чат-приложений и систем с интенсивным обменом данными.</p><h3>Второе направление — расширить навыки в смежных областях</h3><p>Можно пойти по пути расширения компетенций за пределы основной специализации. Важно не только уметь писать код, но и понимать, как приложения разворачиваются и работают в продакшене. Знание DevOps-практик помогает наладить эффективное взаимодействие между разработкой и эксплуатацией.</p><h4>Изучение DevOps и контейнеризации</h4><p>Контейнеры позволяют запускать приложения в изолированной среде, это упрощает настройку и развертывание. Например, Docker помогает упаковать приложение с зависимостями в один контейнер, а Kubernetes — управлять такими контейнерами в продакшене. Знание этих технологий улучшит взаимодействие с операционной командой и ускорит выпуск новых версий приложений.</p><h4>CI/CD и автоматизация процессов</h4><p>Непрерывная интеграция (Continuous Integration) и непрерывное развертывание (Continuous Deployment) — ключевые практики современной разработки ПО. Они позволяют автоматизировать сборку, тестирование и доставку приложений, масштабировать процессы.</p><p>Инструменты CI/CD (например, Jenkins, GitLab CI/CD, GitHub Actions) помогают настроить автоматические пайплайны, которые обеспечивают быструю обратную связь и минимизируют человеческий фактор в релизах. Автоматизация процессов снижает количество ошибок и позволяет сосредоточиться на разработке новых функций.</p><p>Настройка непрерывной интеграции и доставки (Continuous Integration / Continuous Delivery) снижает поток ошибок при релизах и экономит время. Пример: GitHub Actions для автоматического запуска тестов и сборки проекта при каждом коммите.</p><h4>Больше знаний в области баз данных</h4><p>Помимо классических реляционных баз данных (PostgreSQL, MySQL), современные приложения часто используют NoSQL для специфичных задач. MongoDB, Redis, Cassandra обеспечивают гибкость в хранении данных, горизонтальное масштабирование и высокую производительность при работе с большими объемами информации.</p><p>Графовые базы данных (Neo4j, ArangoDB) предназначены для эффективного хранения и анализа связей между объектами, что важно для социальных сетей, рекомендательных систем и других приложений с богатой структурой.</p><p>Так, Redis хорошо подходит для кэширования данных, а Neo4j — для сложных связей между объектами.</p><h3>Третье направление — переход к другим аспектам Python-разработки</h3><p>Рассмотрим четыре варианта карьерного развития для Python-программиста: Data Science и машинное обучение, автоматизация бизнес-процессов, разработка десктопных приложений и встраиваемые системы (IoT).</p><p>Почему стоит попробовать?</p><ul><li>Высокий спрос на специалистов. Они востребованы в банках и инвестиционных компаниях, в сфере медицины и биотехнологии, в консалтинге,  автомобильной промышленности и т.д..</li><li>Широкий набор библиотек: pandas, NumPy, scikit-learn, TensorFlow, PyTorch.</li><li>Возможность работать с реальными задачами: от бизнеса до науки.</li></ul><h4>Автоматизация и скрипты для бизнеса</h4><p>Python часто используется для автоматизации рутинных задач: парсинга данных, обработки файлов, интеграции систем, генерации отчетов. Создание скриптов для автоматизации бизнес-процессов помогает повысить эффективность работы и снизить количество ошибок.</p><p>Знание таких библиотек, как openpyxl (работа с Excel), requests (HTTP-запросы), BeautifulSoup и Scrapy (парсинг веб-страниц), а также умение писать скрипты под конкретные задачи, делают разработчика ценным специалистом в корпоративной среде.</p><p>Примеры задач:</p><ul><li>Автоматическая загрузка данных из Excel и их преобразование</li><li>Скрипты для отправки email-рассылок</li><li>Интеграция с CRM и другими сервисами через API</li></ul><h4>Разработка десктопных приложений (PyQt, Kivy)</h4><p>Хотя сейчас популярность уходит к вебу и мобильным платформам, десктопные приложения на Python востребованы в таких сферах: инструменты для анализа, редакторы, утилиты.</p><p>Инструменты для создания:</p><ul><li>PyQt — мощный фреймворк для создания кроссплатформенных GUI.</li><li>Kivy — библиотека для разработки приложений с поддержкой сенсорных экранов.</li></ul><p>Этот путь подходит тем, кто хочет создавать удобные инструменты с графическим интерфейсом для пользователей на Windows, macOS или Linux.</p><h4>Встраиваемые системы и IoT</h4><p>В области IoT и встроенных систем Python набирает популярность благодаря легкости освоения и поддержке на маломощных устройствах. Помогают в этом  платформы по типу Raspberry Pi и MicroPython.</p><p>Изучение этого направления открывает возможности работы с аппаратным обеспечением, созданием прототипов и внедрением инновационных решений в промышленности и бытовой технике.</p><p>Например, с помощью Python на Raspberry Pi можно  разрабатывать датчики для мониторинга состояния оборудования на производстве и разрабатывать прототипы носимых устройств для сбора данных о здоровье.</p><blockquote>Если рассматривать профессию “Python-разработчик на Django”, то сразу получится сужение до конкретной библиотеки на конкретном языке. Если же в резюме у специалиста стоит, что он “разработчик Python”, возможностей сильно больше. Если написать про себя “разработчик”, будет не понятно, разработчик чего. Но изменив резюме на “DevOps инженера”, становится понятен карьерный трек.</blockquote>]]></content:encoded>
    </item>
    <item>
      <title>«Этот код точно писал ИИ»: разработчик объяснил, как LLM ломают культуру командной разработки</title>
      <link>https://tproger.ru/news/-etot-kod-tochno-pisal-ii---razrabotchik-obyasnil--kak-llm-lomayut-kulturu-komandnoj-razrabotki</link>
      <comments>https://tproger.ru/news/-etot-kod-tochno-pisal-ii---razrabotchik-obyasnil--kak-llm-lomayut-kulturu-komandnoj-razrabotki?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/-etot-kod-tochno-pisal-ii---razrabotchik-obyasnil--kak-llm-lomayut-kulturu-komandnoj-razrabotki</guid>
      <description><![CDATA[<p>ИИ меняет стиль кода в команде: рабочий, но «чужой» код ломает архитектуру, стандарты и культуру долгосрочной разработки</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/-etot-kod-tochno-pisal-ii---razrabotchik-obyasnil--kak-llm-lomayut-kulturu-komandnoj-razrabotki">«Этот код точно писал ИИ»: разработчик объяснил, как LLM ломают культуру командной разработки</a>»</p>]]></description>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 31 Jul 2025 04:30:25 GMT</pubDate>
      <content:encoded><![CDATA[<p>Разработчик <a href="https://alexkondov.com/i-know-when-youre-vibe-coding/">поделился</a> наблюдением: все чаще в коде коллег появляется что-то, что не похоже на стиль команды.</p><p>Код рабочий, понятный, покрыт тестами — но его структура, решения и стиль не вписываются в принятую архитектуру проекта.</p><p>По словам автора, он почти наверняка знает, что такие фрагменты были сгенерированы с помощью больших языковых моделей (LLM), вроде ChatGPT или GitHub Copilot.</p><p>И проблема не в том, что код плохой. Проблема в том, что он — чужой. Его будто писали не члены команды, а кто-то извне, не знающий, как у них принято.</p><h2>LLM игнорируют контекст проекта</h2><p>В команде договорились использовать определенную библиотеку для загрузки данных — а ИИ пишет свой собственный обработчик.</p><p>Везде используется функциональный подход — а LLM сгенерировал класс. Уже есть модуль с нужными утилитами — но модель пишет их заново. Такие случаи множатся.</p><p>И вроде подобные решения выглядит разумно, но на деле идут вразрез с архитектурой, принципами и здравым смыслом команды. Это превращает проект в набор несовместимых кусков, ухудшает читаемость и усложняет поддержку.</p><h2>ИИ — мощный инструмент, но он не заменяет инженера</h2><p>Автор подчеркивает: ему все равно, как код попал в IDE — был он написан вручную, скопирован с форума или сгенерирован ИИ. Важно то, что попадает в кодовую базу.</p><p>И если ты пользуешься LLM, то будь инженером, а не оператором. Ставь четкие задачи, указывай нужные библиотеки, приводи примеры, ограничивай объем кода.</p><p>Важно не скорость, а качество. Времена «быстрее значит лучше» уже показывают свою цену. Как новичок в кофейне, пытающийся угнаться за очередью, программисты спешат выпустить фичу, не думая о последствиях.</p><h2>Разработка — это про долгосрочность</h2><p>По словам автора, софт должен быть не просто рабочим, а поддерживаемым годами.</p><p>Именно ради этого сообщества создавали паттерны, стандарты и правила. ИИ может предложить решение, но не знает, как живет ваш проект и чего от него ждет команда.</p>]]></content:encoded>
    </item>
    <item>
      <title>DRM, ИИ и форензика: гид по защите видеоконтента от пиратов и хакеров</title>
      <link>https://tproger.ru/articles/drm--ii-i-forenzika--gid-po-zashhite-videokontenta-ot-piratov-i-hakerov</link>
      <comments>https://tproger.ru/articles/drm--ii-i-forenzika--gid-po-zashhite-videokontenta-ot-piratov-i-hakerov?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Татьяна Жукова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/drm--ii-i-forenzika--gid-po-zashhite-videokontenta-ot-piratov-i-hakerov</guid>
      <description><![CDATA[<p>Вместе с Александром Павлычевым, сооснователем видеохостинга Kinescope, рассмотрим, как защитить видеоконтент от киберугроз и пиратства.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/drm--ii-i-forenzika--gid-po-zashhite-videokontenta-ot-piratov-i-hakerov">DRM, ИИ и форензика: гид по защите видеоконтента от пиратов и хакеров</a>»</p>]]></description>
      <category><![CDATA[Интернет]]></category>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Android]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Apple]]></category>
      <category><![CDATA[Опрос]]></category>
      <category><![CDATA[Google]]></category>
      <category><![CDATA[PHP]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[Windows]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Opera]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[Xbox]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[Firefox]]></category>
      <category><![CDATA[Маркетинг]]></category>
      <category><![CDATA[Хакеры]]></category>
      <category><![CDATA[YouTube]]></category>
      <category><![CDATA[Взлом]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Kubernetes]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Машин]]></category>
      <category><![CDATA[аналитик]]></category>
      <category><![CDATA[1C]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[CDN]]></category>
      <category><![CDATA[Стриминговые сервисы]]></category>
      <category><![CDATA[Видеоконтент]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 21 Jul 2025 14:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Пиратство
и кибератаки ежегодно обходятся бизнесу в миллиарды долларов, а утечки
видеоконтента угрожают не только стриминговым платформам, но и компаниям,
использующим видео для обучения, маркетинга или внутренних процессов. Как
выстроить защиту видеоконтента от кражи? 
Александр Павлычев, сооснователь видеохостинга Kinescope, рассказывает
про многоуровневую стратегию, DRM, цифровую форензику и ИИ-мониторинг, которые
помогут разработчикам и бизнесу остановить пиратов и хакеров.</p><p>Цифровой контент — актив, который требует
защиты не меньше, чем банковские данные. Многие привыкли, что свежий сериал или
долгожданный фильм оказывается в сети за неделю до премьеры или в день релиза,
а дорогостоящий курс можно скачать бесплатно на «складчинах». В 2024 году
пиратство нанесло российским правообладателям ущерб в <a href="https://www.tadviser.ru/index.php/%D0%A1%D1%82%D0%B0%D1%82%D1%8C%D1%8F:%D0%9F%D0%B8%D1%80%D0%B0%D1%82%D1%81%D0%BA%D0%B8%D0%B5_%D1%81%D0%B0%D0%B9%D1%82%D1%8B_%D0%B8_%D0%B7%D0%B0%D1%89%D0%B8%D1%82%D0%B0_%D0%B0%D0%B2%D1%82%D0%BE%D1%80%D1%81%D0%BA%D0%BE%D0%B3%D0%BE_%D0%BF%D1%80%D0%B0%D0%B2%D0%B0_%D0%B2_%D0%A0%D0%BE%D1%81%D1%81%D0%B8%D0%B8#.2A.D0.9E.D0.B1.D1.8A.D0.B5.D0.BC_.D1.80.D1.8B.D0.BD.D0.BA.D0.B0_.D0.BE.D0.BD.D0.BB.D0.B0.D0.B9.D0.BD-.D0.BF.D0.B8.D1.80.D0.B0.D1.82.D1.81.D1.82.D0.B2.D0.B0_.D0.B2_.D0.A0.D0.BE.D1.81.D1.81.D0.B8.D0.B8_.D1.81.D0.BD.D0.B8.D0.B7.D0.B8.D0.BB.D1.81.D1.8F__.D0.BD.D0.B0_4.2C2.25_.D0.B4.D0.BE_.E2.82.BD3.2C36_.D0.BC.D0.BB.D1.80.D0.B4">3,36 млрд</a> рублей, а глобальные потери
медиаиндустрии превысили <a href="https://www.forbes.com/sites/niallmccarthy/2019/06/26/pirated-video-gets-viewed-over-200-billion-times-a-year-infographic/">$71 миллиард</a>. Утечки контента происходят через
уязвимости в системах доставки, запись экрана или взлом серверов.</p><p>Но угрозы безопасности видеконтента не
ограничиваются пиратством. Кибератаки добавляют новый уровень сложности: в
отличие от пиратов, которые стремятся монетизировать контент через нелегальное
распространение, хакеры могут преследовать иные цели — от вымогательства до
саботажа инфраструктуры. Например, говорить, что в их распоряжении есть
интимные видеозаписи жертвы (ещё лучше, если это CEO известной компании) и
вымогать крупную сумму денег. Или <a href="https://www.forbes.ru/tekhnologii/465207-servis-poprostu-udalilsa-kak-vzlomali-rutube-i-cto-budet-s-videohostingom-dal-se">взломать Rutube</a> и саботировать инфраструктуру
сервиса, как это было в 2022 году. Киберугрозы также могут включать DDoS-атаки,
эксплуатацию уязвимостей в API или кражу пользовательских данных, что приводит
к последствиям:</p><ul><li>Коммерческие риски: снижение выручки, подрыв
бизнес-модели, что особенно актуально для премиальных и эксклюзивных материалов
и сервисов.</li><li>Правовые последствия: иски от правообладателей
или штрафы за утечку персональных данных.</li><li>Репутационные издержки: утрата доверия
пользователей и партнеров, особенно если платформа позиционируется как
безопасная.</li></ul><p>Важно понимать, что защита должна
учитывать не только копирование контента, но и целостность всей экосистемы — от
API до клиентского плеера.</p><h2>Многоуровневая защита: из
чего она состоит</h2><p>Механизмы пиратства
и кибератак многогранны: злоумышленники используют разные методы, от простого
скачивания до сложных схем обхода защиты. Поэтому стратегия должна
включать несколько уровней.</p><p><b>1. Защита от несанкционированного
доступа и копирования</b></p><p>Первый барьер —
ограниченный доступ к контенту:</p><ul><li>Шифрование: AES-128 или AES-256 для защиты видеопотоков.</li><li>Авторизация: токены JWT или OAuth для проверки прав пользователей.</li><li>Системы управления цифровыми правами (DRM) устанавливают ограничения на воспроизведение контента — по устройствам, географическому положению и времени. Если отсутствует соответствующий ключ шифрования, выдаваемый лицензионным сервером, воспроизведение может быть заблокировано.</li></ul><p><b>2. Пиратские копии</b></p><p>Даже если контент
уже украден, важно оперативно выявить его нелегальное распространение.
Технологии AI-мониторинга
и цифровой форензики сканируют даркнет, соцсети и пиратские сайты. ИИ
распознает видео по фрагментам, даже если оно перекодировано.</p><p><b>Технический нюанс</b>: ИИ-системы используют сверточные нейросети (CNN) для анализа визуальных и
аудиохарактеристик. Разработчикам стоит интегрировать такие решения через API, например, от Google Cloud Vision или специализированных
вендоров.</p><p><b>3. Отслеживание источника утечки</b></p><p>Ключевой вопрос при
утечке: кто и как получил доступ к контенту? Водяные знаки и «цифровые
отпечатки» (fingerprinting) позволяют встраивать уникальные идентификаторы в видеофайлы. Fingerprinting, например, создает хэши
аудио- и видеофрагментов для поиска копий.</p><p><b>Технический нюанс</b>: сессионные водяные знаки добавляют задержку в
стриминг. Проблема решается предварительной обработкой сегментов для HLS/DASH-протоколов.</p><p><b>4. Противодействие пиратским
ресурсам</b></p><p>Удалить копии после
обнаружения можно через:</p><ul><li>Обращение в РКН и к платформе, где появилось видео. Если реакции от платформы нет, РКН или провайдер хостинга заблокируют сайт по запросу.</li><li>Автоматическую блокировку ссылок через API хостингов.</li><li>Юридическое давление на пиратские платформы.</li></ul><h2>Технологии против
пиратов: DRM, ИИ, водяные знаки и «цифровые
отпечатки»</h2><p>Современные решения
для защиты видео объединяют несколько технологий, каждая из которых решает
определенные задачи. Рассмотрим их подробнее.</p><p><b>DRM</b><b> (управление цифровыми правами)</b></p><p>DRM-системы шифруют контент и управляют лицензиями на доступ к видеопотоку. DRM защищает контент на
уровне клиента и сервера, предотвращая неавторизованный доступ и перехват.
Такие системы интегрируются в плееры и платформы и показывают контент только
авторизованным пользователям.</p><p>DRM-системы опираются на три ключевых компонента:</p><ol><li>Лицензионный сервер отвечает за выдачу и проверку ключей расшифровки контента.</li><li>Клиентская часть DRM (Content Decryption Module, CDM) интегрирована в браузер/плеер.</li><li>Упаковщик контента (Packager) подготавливает видеопотоки для защищенной доставки.</li></ol><p>Но есть техническая проблема совместимости — DRM-системы неоднородны по платформам:</p><ul><li>Widevine (Android, Chrome, Firefox, Opera);</li><li>PlayReady (Windows, Xbox, некоторые Smart TV);</li><li>FairPlay (экосистема Apple);</li><li>WisePlay DRM (экосистема Huawei).</li></ul><p>Решение — мульти-DRM упаковщики, поддерживающие все стандарты через единую интеграцию. Используйте библиотеки, например, Shaka Player, для упрощенной интеграции мульти-DRM.</p><p><b>Водяные знаки (Digital</b><b> Watermarking</b><b>)</b></p><p>Водяные знаки —
метки, встроенные в видео, которые содержат информацию о правообладателе или
пользователе, что помогает отследить источник утечки, если контент появляется
на пиратских ресурсах. Они могут быть видимыми или незаметными: первые
отпугивают пиратов, а вторые помогают отследить источник утечки.</p><p><b>Отслеживание «цифровых следов» (Fingerprinting</b><b>)</b></p><p>В отличие от водяных
знаков, которые внедряются в контент, технология фингерпринтинга генерирует
хэши фрагментов видео и аудио для поиска копий в сети без модификации самих
файлов. Это позволяет находить пиратские копии, даже если они были изменены
(например, перекодированы или обрезаны). Работает это так: система создает
«цифровой отпечаток» оригинального видео и затем автоматически сканирует
интернет в поисках материалов с похожими характеристиками.</p><p>Например, YouTube Content ID верифицирует права на
материалы и затем в автоматическом режиме отслеживает загрузки на платформе.
Когда пользователь загружает видео, Content ID сравнивает его с базой отпечатков, и, если
обнаруживает совпадение с материалами, может заблокировать ролик за нарушение
авторских прав, перенаправить доход от рекламы правообладателю или уведомить
владельца контента.</p><p><b>Цифровая форензика</b></p><p>Цифровая форензика —
это сбор и исследование данных для раскрытия цифровых преступлений. Проще
говоря, цифровая криминалистика. Специалисты-форензики анализируют источники
пиратских копий через анализ метаданных, характеристик кодирования, артефактов
сжатия и других цифровых «улик», чтобы выявить, как и когда произошла утечка.
Например, уникальные артефакты в H.264-кодеке могут указать на устройство, с
которого записали экран.</p><p><b>AI</b><b>-мониторинг</b></p><p>Искусственный
интеллект ускоряет поиск пиратских копий через анализ огромных массивов данных
в интернете с помощью компьютерного зрения и машинного обучения. ИИ-системы
мониторинга используют сверточные нейросети (CNN), которые способны распознавать визуальные
образы и алгоритмы, такие как Mel-Frequency Cepstral Coefficients (MFCC) (используется для распознавания речи). С их
помощью можно находить копии даже при перекодировании или обрезке.</p><p>Уже существует
множество готовых решений на основе ИИ. Например, Red Points постоянно мониторит соцсети, видеоплатформы и
пиратские сайты с применением машинного обучения, компьютерного зрения и
распознавания изображений, а при обнаружении совпадений автоматически
отправляет запросы на удаление через API. Piracymeter и Bytescare анализируют списки доменов, поисковые результаты Google и торрент-трекеров. Bytescare также может
находить пиратские копии ПО.</p><p>Такие решения
быстрее ручного мониторинга и больше подходят для больших каталогов видео. Они
могут работать автономно или подключаться через REST API, но требуют настройки для снижения ложных
срабатываний.</p><h3>Пример комплексного подхода к защите видео</h3><p>Для защиты
видеоконтента компании всё чаще используют решения, которые сочетают несколько
технологий. Например, разработчик систем безопасности GS Labs совместно с видеохостингом Kinescope создал <a href="https://www.cnews.ru/news/line/2025-04-30_gs_labs_i_kinescope_realizuyut_sovmestnye">систему</a>, интегрирующую DRM, водяные знаки и цифровую форензику. Она
позволяет шифровать контент, встраивать уникальные идентификаторы для
отслеживания утечек и анализировать источники пиратских копий. Такое решение
работает как в облаке, что даёт стриминговым платформам масштабируемость, так и
локально, что важно для компаний с собственной инфраструктурой.</p><h2>Модели внедрения технологий защиты видеоконтента</h2><p>Выбор модели
внедрения зависит от потребностей компании, ее бюджета и технических
возможностей. Рассмотрим три основные модели.</p><h2>Локальные
решения (on-premises)</h2><p>Локальные системы
устанавливаются на серверах компании, что подходит для крупных медиакомпаний с
собственной инфраструктурой. Их преимущества — полный контроль над данными и
независимость от внешних провайдеров. Из минусов — высокие затраты на
оборудование, обслуживание и персонал.</p><h2>Облачные/SaaS-решения</h2><p>Облачные платформы
минимизируют затраты, предлагают гибкость и масштабируемость. Они идеальны для
стартапов и онлайн-кинотеатров, которые не хотят инвестировать в собственные
серверы. SaaS-модель
позволяет быстро внедрить защиту, минимизируя затраты на инфраструктуру.</p><p><b>Совет</b>: используйте облачные решения с SOC 2 или ISO 27001 сертификацией для защиты данных.</p><h2>Гибридные
модели</h2><p>Гибридные решения
сочетают локальные и облачные компоненты. Например, компания может хранить
критически важные данные на своих серверах, а для мониторинга и аналитики
использовать облачные сервисы. Такая модель обеспечивает баланс между контролем
и масштабируемостью, но требует внимательной интеграции.</p><p><b>Совет: </b>используйте Kubernetes для оркестрации гибридных систем и минимизации downtime.</p><h2>Что стоит сделать прямо сейчас, чтобы защитить видеоконтент</h2><ol><li>Подобрать постоянное комплексное решение: исследуйте вендоров и технологии на рынке.</li><li>Провести аудит инфраструктуры: проверьте уязвимости в CDN, API и плеере, например, с помощью OWASP ZAP.</li><li>Интегрировать DRM: выберите мульти-DRM решение, совместимое с Widevine, PlayReady и FairPlay.</li><li>Внедрить мониторинг: подключите ИИ через API для поиска копий.</li><li>Провести пентесты в BurpSuite, симулируя пиратские атаки и взлом.</li><li>Отработать реакцию на инциденты.</li></ol><p>Если вы тоже
работаете с видео и хотите усилить его безопасность, начните с анализа текущих
процессов: какие технологии уже задействованы, где есть пробелы и какие решения
помогут закрыть их в первую очередь. Такой системный подход создаст барьер
против киберугроз, нелегального копирования и распространения видеоконтента.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как встроить распознавание банковской карты в браузер</title>
      <link>https://tproger.ru/articles/raspoznavanie-bankovskoj-karty-v-brauzere--kak-s-pomoshhyu-tehnologii-webassembly-integrirovat-raspoznavanie-v-veb-stranicu</link>
      <comments>https://tproger.ru/articles/raspoznavanie-bankovskoj-karty-v-brauzere--kak-s-pomoshhyu-tehnologii-webassembly-integrirovat-raspoznavanie-v-veb-stranicu?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Smart Engines]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/raspoznavanie-bankovskoj-karty-v-brauzere--kak-s-pomoshhyu-tehnologii-webassembly-integrirovat-raspoznavanie-v-veb-stranicu</guid>
      <description><![CDATA[<p>Рассказываем, как с помощью технологии WebAssembly интегрировать распознавание в веб-страницу</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/raspoznavanie-bankovskoj-karty-v-brauzere--kak-s-pomoshhyu-tehnologii-webassembly-integrirovat-raspoznavanie-v-veb-stranicu">Как встроить распознавание банковской карты в браузер</a>»</p>]]></description>
      <category><![CDATA[Интернет]]></category>
      <category><![CDATA[Android]]></category>
      <category><![CDATA[Распознавание]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[Финтех]]></category>
      <category><![CDATA[WebAssembly]]></category>
      <category><![CDATA[Мессенджер]]></category>
      <category><![CDATA[GTK]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 18 Jul 2025 07:00:04 GMT</pubDate>
      <content:encoded><![CDATA[<p>Привет, Tproger!</p><p>Мы в Smart Engines занимаемся разработкой интеллектуальных систем для распознавания документов. Мы уже рассказывали вам, как просто и быстро интегрировать наши решения для <a href="https://tproger.ru/articles/kak-vstroit-raspoznavanie-pasporta-rf-v-android--powagovoe-rukovodstvo">распознавания паспорта</a>, а также <a href="https://tproger.ru/articles/kak-vstroit-raspoznavanie-dokumentov-v-android--powagovoe-rukovodstvo">распознавания жестких и гибких форм</a> в Android.</p><p>Сегодня речь пойдет про браузерное распознавание. Оно в последние несколько лет пользуется колоссальным спросом со стороны рынка – прежде всего у  финтеха. Кроме того, развертывание PWA-приложений понадобится компаниям при интеграции функциональности в новый отечественный мессенджер MAX.</p><p>Поговорим о том, в чем плюсы распознавания в вебе и главное – как его развернуть на примере банковской карты.</p><h2>Исторический экскурс</h2><p>Технология WebAssembly (WASM) появилась в 2015 году и два года спустя была реализована во всех основных браузерах. Тогда же ученые Smart Engines начали проводить с WASM первые эксперименты.</p><p>Немного похвастаемся: в 2021 году мы первыми в стране представили промышленные технологии для распознавания документов в вебе. Это оказалось очень кстати, поскольку на фоне удаления мобильных приложений из магазинов к интерес к технологиям распознавания QR и банковских карт в браузере вырос.</p><p>Банки и финтех стали искать способы, как перенести привычную для пользователя функциональность – платежи по QR, распознавание номера телефона, распознавание банковской карты – из мобильного приложения в веб.</p><p>Ответ нашелся быстро – WASM и Smart Engines.</p><h2>В чем плюсы?</h2><p>Браузерное распознавание имеет очень много преимуществ. <b>Во-первых</b>, это все преимущества веб приложения:</p><ul><li>Кроссплатформенность;</li><li>Возможность доступа к приложению из любой точки с интернет-соединением</li><li><b>Мгновенное</b> развертывание и обновление приложения, что <b>позволяет пользователям всегда работать с актуальной версией</b>.</li></ul><p><b>Во-вторых</b>, предусматривает совершенно иной уровень защиты персональных данных. Пользователь не выгружает свои данные на сервер для распознавания, а, напротив, загружает модуль для распознавания изображений с персональными данными себе.</p><p>И, <b>в-третьих</b>, позволяет в сжатые сроки реализовать фронтэнд-интеграцию силами web-разработчиков.</p><p>Все преимущества браузерного распознавания уже оценили наши партнёры, нацеленные на развитие своих интернет-сервисов. Среди них – Альфа-Банк, Газпромбанк и другие.</p><h2>Распознавание кодифицированных объектов</h2><p>Одним из самых востребованных направлений в OCR сейчас является распознавание кодифицированных объектов, таких как баркоды, номера телефонов, банковских карт и прочие машиночитаемые зоны.</p><p>В своё время мы выделили распознавание таких объектов в отдельный продукт <a href="https://smartengines.ru/smart-code-engine/">Smart Code Engine</a> для того, чтобы иметь возможность гибче работать с различными сценариями распознавания, а также иметь возможность пойти дальше в деле оптимизации скорости и размера библиотеки. В результате появился Smart Code Engine 2.0 – продукт получил новый интерфейс и возможность максимально гибко настраивать поведение для получения лучшего качества распознавания.</p><p>Библиотека Smart Code Engine написана на С++ и портировалась в веб с помощью инструмента Emscripten. Поскольку вся кодовая база, от низкоуровневых вычисления над изображениями до архитектуры поисковой сети, поддерживается нашим научным отделом, качественное портирование не составляло особых проблем.</p><p>Js-интерфейс библиотеки представляет собой практически зеркальный С++ интерфейс и с его помощью распознавание банковской карты реализуется вот так:</p><p>Этот код необходимо поместить в веб-воркер, чтобы не нагружать UI поток браузера лишними вычислениями.</p><p>Передача изображений в библиотеку осуществляется прямо с чтения пикселей элемента canvas, где вы выводите изображения с камеры устройства или прикрепленного файла PDF.</p><p>В процессе работы распознавания у вас есть возможность нарисовать поверх изображения найденные элементы документа за мгновение до распознавания.</p><p>Вот как это выглядит на выходе:</p><figure><img src="https://media.tproger.ru/user-uploads/110363/2025-07-17/fd81bc20-66a7-4d20-90ee-ce1bf5a93827.gif" alt="Автоматический ввод данных банковской карты в браузере" /><figcaption>Распознавание банковской карты в браузере при помощи Smart Code Engine</figcaption></figure><p>Как вы можете заметить, интеграция Smart Code Engine SDK не вызывает сложностей – внедрение происходит практически мгновенно, а скорость распознавания сопоставима с нативными библиотеками.</p>]]></content:encoded>
    </item>
    <item>
      <title>10 библиотек Python, которые меняют карьеру</title>
      <link>https://tproger.ru/articles/10-bibliotek-python--kotorye-menyayut-kareru</link>
      <comments>https://tproger.ru/articles/10-bibliotek-python--kotorye-menyayut-kareru?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Татьяна Жукова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/10-bibliotek-python--kotorye-menyayut-kareru</guid>
      <description><![CDATA[<p>10 библиотек Python, которые помогут прокачаться в аналитике, ML и разработке. Как они работают и почему меняют карьеру.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/10-bibliotek-python--kotorye-menyayut-kareru">10 библиотек Python, которые меняют карьеру</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Тестирование]]></category>
      <category><![CDATA[Парсинг]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[JSON]]></category>
      <category><![CDATA[MySQL]]></category>
      <category><![CDATA[Отладка]]></category>
      <category><![CDATA[Нейронные сети]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Навыки]]></category>
      <category><![CDATA[Django]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[Jupyter Notebook]]></category>
      <category><![CDATA[Визуализация]]></category>
      <category><![CDATA[Образование]]></category>
      <category><![CDATA[OpenAI]]></category>
      <category><![CDATA[Анализ данных]]></category>
      <category><![CDATA[Бэкенд]]></category>
      <category><![CDATA[Аналитика]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[аналитик]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 17 Jul 2025 14:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>У Python тысячи библиотек, но лишь немногие действительно меняют карьеру. Они помогают не просто решать задачи, а ускорять проекты, прокачивать навыки и выходить на следующий уровень в аналитике, машинном обучении и разработке. В этом материале мы собрали 10 библиотек, которые помогут зарабатывать на Python и развивать навыки.</p><h2>1. Pandas</h2><p>Pandas — библиотека для работы с данными в Python, позволяющая легко загружать, анализировать, очищать и преобразовывать числовую информацию в удобной табличной форме. По сути, это Excel, который смог, и позволяет делать всё автоматизировано и на порядки быстрее.</p><p>Библиотека строится вокруг двух ключевых структур: <b>Series</b> (одномерный массив с индексами); <b>DataFrame </b>(таблица с индексами и колонками).</p><h3>Какие задачи решает библиотека</h3><p>Pandas полезна для следующих задач:</p><ul><li>Сам анализ данных: можно быстро фильтровать, группировать, агрегировать и строить сводные таблицы.</li><li>Очистка данных: удаляем пустые строки, заменяем значения, приводим типы.</li><li>Загрузка данных из CSV, Excel, SQL.</li><li>Визуальная разведка данных (EDA) перед построением моделей.</li><li>Подготовка данных для ML и отчётов.</li><li>Автоматизация отчётов и ETL-пайплайнов.</li></ul><p>Благодаря Pandas аналитик превращается в инженера данных, а ML-специалист может сосредоточиться на моделях, а не на ручной подготовке датасетов.</p><h3>Как пользоваться</h3><p>Ниже разберём простейший кейс: нужно загрузить данные о зарплатах разработчиков из CSV, посчитать среднюю зарплату по языкам программирования и отобрать топ-5.</p><h3>Почему это меняет карьеру</h3><p>Работа с Pandas становится границей между знанием Python и умением решать задачи бизнеса. Для <b>джуна </b>это шанс сразу показать практическую пользу: выгрузки, отчёты и базовый анализ можно делать в десятки раз быстрее и аккуратнее, чем вручную в эксельке.</p><p>Для <b>аналитика</b> Pandas превращается в главный рабочий инструмент, позволяя не просто проверять гипотезы и делать сводные таблицы, а строить полноценные отчётные пайплайны, автоматизировать рутинные выгрузки и концентрироваться на сути данных, а не на правках ручками.</p><p>Для <b>ML-инженера</b> владеть Pandas — значит уметь готовить датасеты качественно; быстро очищать и приводить данные к нужному виду, что напрямую влияет на результат моделей. Без этого работа над проектами машинного обучения часто превращается в бесконечную возню с данными.</p><p>Наконец, даже для <b>разработчиков</b> Pandas может стать неожиданным бустом в карьере. Например, когда нужно автоматизировать отчёты для бизнеса или быстро анализировать логи и данные из БД без поднятия дашбордов — Pandas даёт гибкость и скорость, которые редко даёт что-то ещё в экосистеме Python.</p><h2>2. Django</h2><p>Django — фреймворк для веб-разработки на Python, который позволяет быстро создавать надежные и масштабируемые веб-приложения. Он следует принципам DRY (Don’t Repeat Yourself — не повторяй себя), предоставляя разработчику ORM, роутинг, систему авторизации, админку, работу с формами, шаблонами и инструментами безопасности из коробки.</p><p>Django подходит как стартапам, которым нужно быстро выйти на рынок, так и крупным проектам с миллионами пользователей. Это не просто библиотека, а полноценный каркас для построения и сопровождения веб-сервисов.</p><h3>Какие задачи решает библиотека</h3><p>Каркас, действительно, каркасный. Задачи следующие:</p><ul><li>Создание веб-приложений и API любой сложности.</li><li>Быстрая разработка MVP, прототипов и коммерческих проектов.</li><li>Упрощение работы с базами данных через ORM, без написания сырого SQL.</li><li>Построение административных панелей для управления данными без ручной разработки.</li><li>Гибкая маршрутизация и работа с формами, валидацией и шаблонами.</li><li>Реализация аутентификации, авторизации и защиты приложений.</li></ul><p>Django позволяет сосредоточиться на бизнес-логике и продукте, не тратить недели на настройку инфраструктуры.</p><h3>Как пользоваться</h3><p>Устанавливаем:</p><p>Создаем проект и приложение:</p><p>Пример модели:</p><p>Миграция базы данных:</p><p>Создание админки:</p><p>После этого можно запустить сервер:</p><p>И перейти по адресу http://127.0.0.1:8000/admin для управления записями через готовую админ-панель.</p><h2>3. PyTorch</h2><p>PyTorch — мощная библиотека Python. Она позволяет строить и обучать нейронные сети, проводить вычисления с автоматическим дифференцированием и работать с GPU для ускорения самих вычислений.</p><p>Главное отличие PyTorch от других ML-фреймворков — динамическая вычислительная графика (define-by-run): модель строится и изменяется во время выполнения кода, что даёт гибкость при создании и отладке сложных моделей.</p><p>Сегодня PyTorch используется в продакшен системах, научных исследованиях, компьютерном зрении, NLP и генеративных моделях, занимая ведущее место в индустрии.</p><h3>Какие задачи решает библиотека</h3><p>В функционал PyTorch входят:</p><ul><li>Построение нейронных сетей любой сложности (CNN, RNN, трансформеры);</li><li>Обучение и тестирование моделей на CPU и GPU;</li><li>Реализация кастомных слоёв и loss-функций;</li><li>Разработка и деплой ML/AI моделей в продакшен;</li><li>Быстрая итерация гипотез с удобной отладкой.</li></ul><p>С PyTorch можно начать с простых нейронных сетей, а затем перейти к реализации современных архитектур.</p><h3>Как пользоваться</h3><p>Установим PyTorch (на CPU, для GPU потребуется версия с CUDA):</p><p>Рассмотрим кейс обучения простой нейронной сети для классификации рукописных цифр MNIST.</p><p>После обучения можно использовать torch.save() для сохранения модели и torch.load() для загрузки в продакшн.</p><h3>Почему это меняет карьеру</h3><p>PyTorch — билет в мир современной разработки AI и машинного обучения. Владение инструментом даёт <b>разработчику</b> возможность уверенно войти в области, которые продолжают оставаться топовыми на рынке: искусственный интеллект, компьютерное зрение, NLP, генерация изображений и видео и т.д.</p><p>Для <b>начинающего ML/AI-специалиста </b>PyTorch помогает лучше понять, как устроены нейронные сети, и под капотом увидеть, как происходят вычисления. Это ускоряет рост навыков и делает разработчика востребованным в исследованиях и R&amp;D-проектах.</p><p>Для <b>дата-сайентистов</b> PyTorch позволяет превратить исследовательские ноутбуки в готовые к деплою модели, благодаря PyTorch Lightning, TorchScript и ONNX.</p><p>Для<b> разработчиков, которые хотят выйти на рынок AI</b>, PyTorch — это мастхев: проекты в стартапах и крупных компаниях всё чаще строятся вокруг него. Умение писать кастомные loss-функции, проектировать сложные пайплайны обучения, настраивать обучение на кластерах и GPU — компетенции, которые существенно бустят зарплату.</p><p>PyTorch в целом помогает расширять портфолио: с ним можно создавать генеративные модели, строить LLM, участвовать в соревнованиях и работать с самыми современными подходами в машинном обучении.</p><h2>4. Polars</h2><p>Polars — современная библиотека для обработки данных в Python, созданная как альтернатива Pandas. Она использует колоночную архитектуру и многопоточность, что позволяет работать с большими объёмами данных значительно быстрее и с меньшим потреблением памяти.</p><p>Polars вдохновлена Pandas, но её API оптимизировано для производительности и удобства, а также даёт разработчику возможность писать цепочки ленивых вычислений, которые оптимизируются перед выполнением. Это делает её отличным инструментом для аналитиков, дата-инженеров и дата-сайентистов, которым нужно обрабатывать данные быстро.</p><h3>Какие задачи решает библиотека</h3><p>Polars явно есть, чем гордиться:</p><ul><li>Загрузка, очистка и преобразование больших датасетов;</li><li>Анализ данных с использованием цепочек преобразований;</li><li>Быстрая агрегация и группировка данных;</li><li>Ленивые вычисления: построение пайплайнов преобразования данных, которые выполняются только при вызове collect().</li><li>Обработка данных, которые не помещаются в память, за счёт эффективности и колоночной архитектуры.</li></ul><p>Если Pandas начинает притормаживаться на данных в несколько гигабайт, Polars обычно продолжает работать быстро, позволяя без боли обрабатывать большие CSV.</p><h3>Как пользоваться</h3><p>Установка:</p><p>Давайте загрузим данные и проведем базовые трансформации:</p><p>А вот и пример ленивых вычислений:</p><p>В чем особенность:</p><ul><li>pl.read_csv загружает данные сразу.</li><li>pl.scan_csv создаёт план вычислений для последующей оптимизации.</li><li>Используются выражения (pl.col, .with_columns, .agg), которые композируются без создания промежуточных копий, это ускоряет процесс.</li></ul><h3>Почему это меняет карьеру</h3><p>Polars меняет карьеру, потому что даёт преимущество в скорости и эффективности при работе с данными. Там, где Pandas уже не справляется, полярный медведь приходит на помощь.</p><p>Для <b>дата-инженеров</b> Polars полезен при построении ETL и пайплайнов обработки данных, где важна скорость и предсказуемое потребление ресурсов. Его можно использовать в продакшен-скриптах, для подготовки данных к ML и для автоматизации отчётности.</p><p>Для <b>дата-сайентистов </b>Polars даёт возможность анализировать больше данных за меньшее время, быстро итерировать гипотезы и ускорять исследования. Его API достаточно близок к Pandas, поэтому переход не требует месяцев переучивания.</p><p>Освоение Polars показывает работодателям, что ты не просто знаешь стандартные инструменты, но умеешь выбирать оптимальные решения для реальных задач, повышая эффективность работы команды. В эпоху роста данных это критично для любого Python-разработчика, работающего с аналитикой и машинным обучением.</p><h2>5. FastAPI</h2><p>FastAPI — современный фреймворк для создания API на Python, заточенный под скорость, асинхронность и валидацию данных из коробки. Он построен на Starlette и Pydantic, автоматически создаёт OpenAPI-документацию, поддерживает асинхронное программирование и позволяет писать производительные REST и WebSocket API с минимальным количеством кода.</p><p>Вместо долгой настройки, как у Flask или Django, в FastAPI многое готово изначально: удобная работа с запросами и ответами, декларативная валидация, документация Swagger, асинхронность и высокая производительность без лишних усилий.</p><h3>Какие задачи решает</h3><p>Задач, действительно, много:</p><ul><li>Быстрая разработка REST API для мобильных и веб-приложений;</li><li>Создание бэкенда для ML/DS моделей (деплой моделей в виде API);</li><li>Построение микросервисов с хорошей производительностью;</li><li>Реализация websocket-серверов и асинхронных API;</li><li>Подготовка внутренних инструментов или бэкендов для MVP.</li></ul><p>FastAPI помогает быстро запускать API и уверенно масштабировать его в полевых условиях. Это один из немногих фреймворков Python, который по скорости работы сопоставим с Node.js и Go.</p><h3>Как пользоваться</h3><p>Во-первых, нужно установить FastAPI и Uvicorn (используем ASGI-сервер для запуска):</p><p>Простейший API-пример с эндпоинтом GET /:</p><p>Запускаем сам сервер:</p><p>После запуска API будет доступен по адресу http://127.0.0.1:8000/. Автоматически доступна интерактивная документация Swagger по адресу http://127.0.0.1:8000/docs.</p><p>FastAPI поддерживает валидацию параметров запроса, тел запросов и путей прямо через типы Python. Например, простой эндпоинт с параметром:</p><p>При вызове http://127.0.0.1:8000/items/10?q=test FastAPI автоматически проверит, что item_id — это число, и распарсит q как строку.</p><h3>Почему это меняет карьеру</h3><p>FastAPI — билет в мир бэкенда, где скорость и чистота кода имеют довольно высокое значение. Для <b>Python-разработчика </b>это возможность быстро освоить создание API и микросервисов, не увязнув в громоздкой настройке, как в Django, и при этом получить систему, готовую к продакшену.</p><p>Для <b>ML-специалиста</b> FastAPI становится инструментом для деплоя моделей: можно обернуть пайплайн предсказаний в API, подключить авторизацию или логирование и получить работающий сервис за считанные дни.</p><p>Вообще умение быстро поднимать и поддерживать API — навык, который ценят в бигтехе и стартапах. На разработчиков, которые владеют FastAPI, часто равняются: они умеют превращать идеи бизнеса в работающие сервисы за минимальное время.</p><h2>6. Typer</h2><p>Typer — современная библиотека для создания CLI-приложений на Python с минимальным количеством кода и автоматической генерацией документации. Автор библиотеки — Себастьян Рамирес, создатель FastAPI.</p><p>Главная особенность Typer — использование type hints для автоматического парсинга аргументов командной строки. Вы получаете удобную и читаемую CLI с поддержкой автодополнения и цветного вывода за считанные минуты.</p><h3>Какие задачи решает библиотека</h3><p>Список задач такой:</p><ul><li>Создание CLI-утилит любого уровня сложности.</li><li>Быстрое прототипирование и упаковка Python-скриптов в удобные инструменты для продакшена.</li><li>Генерация подробной справки (--help) и автодополнения команд.</li><li>Облегченная поддержка и масштабирование CLI за счёт структуры и читаемого кода.</li><li>Организация CLI с подкомандами, вложенными аргументами и обработкой ошибок.</li></ul><p>Typer использует аннотацию типов и минимум шаблонного кода.</p><h3>Как пользоваться</h3><p>Установка:</p><p>Пример минимальной CLI:</p><p>Теперь можно запустить из консоли:</p><p>Результат будет такой: Привет, Алиса! Тебе 25 лет.</p><h3>Почему это меняет карьеру</h3><p>Typer меняет карьеру тем, что открывает путь к созданию удобных CLI-инструментов, которые автоматизируют рутину и повышают продуктивность.</p><p>С Typer можно быстро превращать свои Python-скрипты в надежные утилиты, которыми удобно пользоваться и другим разработчикам, и сотрудникам из других отделов. CLI-приложения часто становятся клеем инфраструктуры: они позволяют автоматизировать деплой, миграции БД, сбор данных, интеграцию с внешними API и локальную разработку.</p><p>Если вы <b>Data Scientist или ML-инженер</b>, Typer позволяет оборачивать пайплайны в CLI, которые легко запускать из Jenkins, Airflow или вручную. Если вы <b>DevOps или Backend-инженер</b>, можете создавать CLI для работы с инфраструктурой и сервисами без сложных зависимостей.</p><p>Кроме того, работа с Typer улучшает навык структурирования кода, понимание CLI, использования type hints и разработки инструментов, которые делают работу проще для других. А это, очевидно, ценится в любой команде и повышает востребованность специалиста.</p><h2>7. Rich</h2><p>Rich — библиотека Python для красивого форматирования и интерактивного отображения информации в терминале. С её помощью можно выводить цветные таблицы, маркдаун, прогресс-бары, подсвеченный синтаксис кода, деревья каталогов и логирование в понятной и привлекательной форме.</p><p>Rich создана для того, чтобы «оживить» консоль Python, сделать логи удобными для восприятия, а CLI-инструменты — профессионально выглядящими без лишних усилий. Это библиотека, которая улучшает и UX, и DX.</p><h3>Какие задачи решает</h3><p>Про красоту не забываем! Задачи следующие:</p><ul><li>Цветное и структурированное логирование, понятное при чтении логов в реальном времени.</li><li>Отображение прогресс-баров для долгих операций.</li><li>Вывод таблиц, деревьев каталогов, JSON прямо в терминале.</li><li>Подсветка синтаксиса кода для CLI-инструментов.</li><li>Создание CLI-интерфейсов, которые выглядят профессионально и современно.</li><li>Улучшение читаемости при отладке скриптов.</li></ul><p>С помощью Rich можно быстро сделать понятными даже сложные данные при отладке или демонстрации.</p><h3>Как пользоваться</h3><p>Установка Rich:</p><p>Для примера выведем таблицу с подсветкой в консоли:</p><p>В результате в терминале получится цветная таблица, которая выглядит понятно и презентабельно.</p><h3>Почему это меняет карьеру</h3><p>Rich — это библиотека, которая помогает быстро повысить качество любого CLI-инструмента или дев-опыт в команде. <b>Разработчик</b>, который использует Rich, делает свои инструменты удобными не только для себя, но и для коллег: логирование становится понятным, а отладка скриптов — наглядной.</p><p>Во многих стартапах и продвинутых командах важна скорость обратной связи при тестировании пайплайнов и автоматизаций, и Rich помогает выводить ключевую информацию максимально читаемо.</p><p>Кроме того, Rich позволяет быстро создавать CLI-интерфейсы, которые выглядят как продакшен-продукты, даже если это внутренние инструменты. Руководство будет радоваться и думать о вас как о крутом разрабе.</p><p>Для <b>дата-инженеров и разработчиков DevOps</b> Rich полезна при создании админ-утилит и при мониторинге пайплайнов, для <b>Python-разработчиков</b> — при создании библиотек и фреймворков с CLI.</p><h2>8. LangChain</h2><p>LangChain — фреймворк для создания приложений на базе LLM, например, GPT, Claude, Mistral, Gemini. Он позволяет строить цепочки обработки запросов, интегрировать LLM с данными и инструментами, добавлять память и управление состояниями, а также связывать работу модели с внешними API и базами знаний.</p><p>LangChain предоставляет удобный слой абстракции над вызовами LLM и ускоряет разработку чат-ботов, RAG-приложений, агентов с инструментами, систем анализа документов и других AI-сервисов.</p><h3>Какие задачи решает</h3><p>Список внушительный:</p><ul><li>Интеграция LLM в Python-приложения без необходимости писать тот самый клеевой код вручную.</li><li>Построение цепочек с последовательной обработкой сообщений, включая преобразования и вызовы внешних функций.</li><li>Добавление памяти в чат-боты для сохранения истории общения и контекста.</li><li>Использование агентов для динамического вызова инструментов (веб-поиск, базы данных, API).</li><li>Создание RAG-систем с интеграцией LLM и векторных БД.</li><li>Быстрая сборка прототипов LLM-приложений, которые можно развернуть в продакшен.</li></ul><h3>Как пользоваться</h3><p>Установка:</p><p>Создадим простую цепочку с чатом GPT:</p><p>Благодаря единым абстракциям, можно гибко комбинировать цепочки, память и вызов внешних инструментов, не усложняя код.</p><h3>Почему это меняет карьеру</h3><p>LangChain меняет карьеру, потому что открывает новый пласт Python-разработки в AI и LLM-инженерии, быстро превращая пользователя GPT в создателя полноценных AI-приложений. Вместо того чтобы писать хаотичный клеевой код, вы начинаете системно проектировать цепочки запросов, учитесь строить продуманные промпты и объединять их с инструментами, памятью и внешними API.</p><p>Работа с LangChain погружает в практическую LLM-инженерию: вы начинаете создавать RAG-приложения, которые умеют искать и анализировать данные перед генерацией ответа и строить агентов. Это востребовано в продуктах, где нужно подключать ИИ к базам знаний, автоматизировать задачи и разрабатывать интерактивные системы, которые реально используют модели в продакшене.</p><p>LangChain позволяет быстро собирать и запускать MVP AI-продуктов, что дает конкурентное преимущество при создании стартапов или внутренних сервисов. А ещё учит мыслить структурами и проектировать масштабируемую архитектуру LLM-приложений и видеть, как генеративный ИИ можно превратить в рабочий инструмент.</p><h2>9. SQLAlchemy</h2><p>SQLAlchemy — это мощная ORM и toolkit для работы с базами данных в Python, позволяющая писать SQL-запросы декларативно, создавать модели таблиц и управлять транзакциями в Python-коде без ручного написания SQL.</p><p>Библиотека даёт разработчику два уровня контроля:</p><ul><li>Core: низкоуровневая работа с SQL выражениями и соединениями;</li><li>ORM: высокоуровневая декларативная работа с моделями, классами и связями между таблицами.</li></ul><p>SQLAlchemy поддерживает PostgreSQL, MySQL, SQLite, Oracle и другие СУБД, давая единую абстракцию, без привязки к конкретному движку.</p><h3>Какие задачи решает</h3><p>Пул задач следующий:</p><ul><li>Описание таблиц в виде Python-классов и управление ими через сессии;</li><li>Создание, чтение, обновление и удаление данных;</li><li>Миграция SQL на декларативный стиль без потери гибкости;</li><li>Полный контроль над транзакциями и выполнением запросов;</li><li>Работа с асинхронными приложениями при создании FastAPI/Django-приложений;</li><li>Экранирование параметров, которое снижает вероятность SQL-инъекций и ошибок.</li></ul><h3>Как пользоваться</h3><p>Создадим минимальный пример для SQLite с таблицей пользователей:</p><p>Этот код создаёт базу example.db, таблицу users, добавляет туда одного пользователя и выводит всех пользователей в базе. При необходимости можно использовать SQLAlchemy Core для написания гибких запросов вручную, если нужно работать ближе к SQL.</p><h3>Почему это меняет карьеру</h3><p>SQLAlchemy меняет карьеру <b>Python-разработчика</b> тем, что даёт понимание системной работы с данными, архитектуры приложений и взаимодействия с реальными базами данных. Вы учитесь строить продуманные бэкенды, которые работают с транзакциями, миграциями, связями между таблицами и сложными выборками.</p><p>Знание SQLAlchemy открывает дорогу в мир API, микросервисов и продуктов, где требуется качественное управление данными и гибкая логика работы с БД. Работа с SQL теперь совсем не страшная.</p><h2>10. Seaborn</h2><p>Seaborn — библиотека для визуализации данных на Python, построенная поверх Matplotlib и упрощающая создание информативных и стильных графиков с минимальным количеством кода.</p><p>Она автоматически заботится о красивых стилях, цветах, разметке графиков, легендах и позволяет легко строить распределения, линейные графики, тепловые карты и другие визуализации.</p><p>Библиотека тесно интегрируется с Pandas DataFrame, позволяя использовать колонки данных напрямую для построения графиков, что делает её идеальной для EDA (разведочного анализа данных) и подготовки визуализаций для отчётов и презентаций.</p><h2>Какие задачи решает</h2><p>Визуализация безумно важна, особенно в контексте дата-аналитики. Seaborn отвечает за:</p><ul><li>Быстрое построение информативных графиков для анализа данных и поиска инсайтов;</li><li>Автоматическую обработку ошибок отображения и масштабирования, что экономит время;</li><li>Поддержку сложных визуализаций по типу ящиков с усами или тепловых карт без десятков строк кода;</li><li>Стилизацию графиков без ручных настроек Matplotlib;</li><li>Возможность добавлять статистические элементы (линию регрессии, KDE, распределение);</li><li>Интеграцию с Jupyter Notebook для интерактивного анализа данных.</li></ul><h3>Как пользоваться</h3><p>Допустим, у нас есть датасет с данными о чаевых:</p><p>В три строки мы получаем чистый и читаемый ящик с усами, показывающий, как счет за ужин распределяется по дням недели.</p><p>Для построения более сложных графиков можно использовать диаграмму рассеяния:</p><p>Тут мы добавляем цветовую кодировку по полу, чтобы увидеть зависимости между переменными.</p><h3>Почему это меняет карьеру</h3><p>Seaborn меняет карьеру, потому что даёт навык визуального анализа данных, что критично в современной аналитике и дата-инженерии. Умение быстро строить графики и видеть аномалии, распределения и взаимосвязи между переменными превращает работу с данными из слепого копания в числах в структурный анализ.</p><p>Использование Seaborn в Python-стеке помогает выделиться среди разработчиков, которые ограничиваются Pandas и текстовыми логами, ведь визуализация часто позволяет быстрее заметить закономерности и убедить команду или заказчика в правильности гипотезы.</p><p>Seaborn также учит пониманию данных через визуальные паттерны, что улучшает навыки построения моделей машинного обучения (так понятнее, какие признаки важны), и помогает создавать наглядные отчёты для продуктовых решений, где результат анализа нужно доносить до людей не из айти-индустрии.</p><p><i>А какими библиотеками пользуетесь вы? Делитесь в комментариях!</i></p>]]></content:encoded>
    </item>
    <item>
      <title>Типизированная навигация в React Router</title>
      <link>https://tproger.ru/articles/tipizirovannaya-navigaciya-v-react-router</link>
      <comments>https://tproger.ru/articles/tipizirovannaya-navigaciya-v-react-router?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Михаил Сахаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/tipizirovannaya-navigaciya-v-react-router</guid>
      <description><![CDATA[<p>Когда прочитаете эту статью, сможете настроить типобезопасную навигацию в своем проекте, забудете про сломанные ссылки после рефакторинга и перестанете нервничать на релизах.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/tipizirovannaya-navigaciya-v-react-router">Типизированная навигация в React Router</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[Рефакторинг]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[TypeScript]]></category>
      <category><![CDATA[React]]></category>
      <category><![CDATA[Redux]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 16 Jul 2025 10:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Типизированная навигация в React Router решает классические проблемы фронтенд-разработки: опечатки в путях, сломанные ссылки после рефакторинга и отсутствие автокомплита. Это полезно и джунам, которые хотят избежать глупых ошибок, и сеньорам, проектирующим большие проекты. Инструмент превращает строковые пути в типобезопасную систему навигации.</p><p>Представьте: пятница, 18:30. Релиз через час. Вы меняете один роут в конфиге — и внезапно половина приложения отлетает. Поздравляем, вы только что познакомились с классической болью фронтендеров.</p><p>Проблема кроется в самой природе JavaScript. Строковые пути вроде /users/profile/${id} существуют в коде как обычные строки — без проверок, автокомплита и гарантий корректности. Опечатался в /usres вместо /users — и твоя навигация сломалась, а TypeScript молчит как рыба.</p><p>Двадцать лет назад мы кликали по window.location.href, десять лет назад — радовались React Router, а сегодня пора переходить на типизированные решения.</p><p>Когда прочитаете эту статью, сможете настроить типобезопасную навигацию в своем проекте, забудете про сломанные ссылки после рефакторинга и перестанете нервничать на релизах.</p><h2>Суть проблемы</h2><p>Проблема очевидна: путь /admin/products размазан по всему коду. TypeScript не знает, что эти строки связаны с определенной директорией, поэтому не проверяет их корректность. Опечатка в product вместо products — и вылетает ошибка 404.</p><p>В больших проектах эта проблема критична. Приложение с 200+ путями, где навигация разбросана по сотне компонентов, превращается в минное поле. Один программист меняет структуру URL, а остальные даже не подозревают об этом. Команды используют TypeScript для типобезопасности, но навигация остается уязвимой.</p><h2>Что такое типизированная навигация?</h2><p>Типизированная навигация превращает строковые пути в типизированные объекты. Вместо /admin/products/123/edit программист работает с функциями, которые знают структуру приложения и проверяют корректность написания путей на этапе компиляции.</p><p>Представьте GPS-навигатор, который знает все адреса в городе. Вы не можете ввести несуществующую улицу — система сразу выдаст ошибку. Так работает типизированная навигация: TypeScript проверяет, что путь существует, параметры переданы правильно, а структура URL соответствует пути.</p><p>Три ключевых преимущества: автокомплит в IDE, проверка на этапе компиляции и безопасный рефакторинг. Поменяете пути в коде — TypeScript сразу покажет все места, которые нужно обновить.</p><p>Польза зависит от уровня разработчика:</p><ul><li>Джуны получают защиту от опечаток и автокомплит — меньше глупых ошибок и быструю разработку.</li><li>Миддлы ускоряют разработку благодаря надежному рефакторингу — можно смело менять структуру URL без страха что-то сломать.</li><li>Сеньоры используют типизацию для построения архитектуры приложения — создают переиспользуемые компоненты навигации, проверяют параметры и строят масштабируемые системы путей и директорий.</li></ul><p>Типизированная навигация превращает хрупкий код в надежную систему, где ошибки находятся до деплоя.</p><h2>Как использовать React Router вместе с TypeScript</h2><p>Для базовой типизации в React Router v6 сначала определите структуру путей. Создайте интерфейс, который описывает все пути в приложении:</p><p>Типизация параметров URL решает проблему с useParams. Вместо any получаете конкретные типы:</p><p>Query-параметры типизируются аналогично через useSearchParams. Создайте интерфейс для каждой страницы с query-параметрами и оберните хук.</p><p>Так система будет дополнять код в IDE, проверять все пути на этапе компиляции и защитит от опечаток. Полчаса настройки сэкономят вам часы отладки и целый вагон нервов.</p><h2>Как внедрить типизированную навигацию в проекты</h2><p>Централизованная система маршрутов облегчает управление навигацией в больших приложениях. Создайте отдельный файл с конфигурацией всех путей:</p><p>Конфигурация избавит от нужды дублировать код при генерации типов. TypeScript автоматически выведет все возможные пути и их параметры из одного объекта.</p><p>Современные библиотеки решают проблему из коробки.<a href="https://tanstack.com/router"> Например, Tanstack Router</a> предоставляет полностью типизированную систему путей с автогенерацией типов, а<a href="https://github.com/typehero/type-route"> Type-route</a> создает типобезопасные пути через API.</p><p>Библиотека<a href="https://github.com/typesafe-routes/typesafe-routes"> typesafe-routes</a> внедряется даже в крупные проекты без необходимости менять сотни строк кода.</p><p>Выбор инструмента зависит от размера программы. Если у вас небольшое приложение — быстрее написать хук в пару строк. Но если разрабатываете сложный сервис — используйте библиотеки.</p><h2>Как не сломать код при использовании типизированной навигации</h2><p>Не пытайтесь переписать весь проект за раз — создайте типизированные хуки для новых фич, а старый код обновляйте по мере рефакторинга.</p><p>Чеклист для код-ревью поможет не уронить прод:</p><ul><li>Все новые navigate() и  используют типизированные версии;</li><li>Параметры путей явно типизированы;</li><li>Нет магических строк в навигации;</li><li>Query-параметры описаны интерфейсами.</li></ul><p>Важно: не используйте одновременно строки и типизированные пути — выберите один подход для проекта и не допускайте высокого уровня вложенности в объектах.</p><p>Автоматизация упрощает процесс. ESLint правило no-hardcoded-routes запретит использование строк в навигации. Код-генераторы создают типы из OpenAPI схем или конфигурации роутера.</p><p>Производительность не страдает — типы исчезают после компиляции. Теряется немного времени на компиляцию TypeScript, но экономия на отладке перекрывает затраты.</p><h2>Где применять типизированную навигацию</h2><p>SPA-приложения получают максимальную пользу от типизированных путей. В дашбордах с десятками страниц навигация становится еще важнее — один сломанный путь может уронить проект.</p><p>E-commerce проекты выигрывают от типизации каталогов и фильтров. Пути вроде /catalog/:category/:subcategory?filters=price,brand содержат много параметров, которые легко сломать при рефакторинге.</p><p>Интеграция с Redux и Zustand упрощает синхронизацию состояния с URL. Типизированные селекторы автоматически обновляются при изменении роутов:</p><p>Вложенные директории требуют особого внимания. Каждый уровень вложенности усложняет типизацию — планируйте структуру заранее, а не рефакторьте задним числом.</p><p>Типизированная навигация — стандарт современной разработки. Команды, которые до сих пор полагаются на строковые пути, тратят лишнее время на поиск багов. Программисты увереннее рефакторят код, не боятся мелких ошибок и не роняют прод в пятницу вечером из-за одного символа в пути.</p>]]></content:encoded>
    </item>
    <item>
      <title>В Сети нашли каталог из 3200+ готовых ИИ-агентов под любые задачи. Можно запускать в один клик без кода</title>
      <link>https://tproger.ru/news/v-seti-nawli-katalog-iz-3200--gotovyh-ii-agentov-pod-lyubye-zadachi--mozhno-zapuskat-v-odin-klik-bez-koda</link>
      <comments>https://tproger.ru/news/v-seti-nawli-katalog-iz-3200--gotovyh-ii-agentov-pod-lyubye-zadachi--mozhno-zapuskat-v-odin-klik-bez-koda?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Татьяна Жукова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/v-seti-nawli-katalog-iz-3200--gotovyh-ii-agentov-pod-lyubye-zadachi--mozhno-zapuskat-v-odin-klik-bez-koda</guid>
      <description><![CDATA[<p>Каталог из 3200+ ИИ-агентов и готовых автоматизаций на n8n доступен бесплатно: запускаем в один клик.  </p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/v-seti-nawli-katalog-iz-3200--gotovyh-ii-agentov-pod-lyubye-zadachi--mozhno-zapuskat-v-odin-klik-bez-koda">В Сети нашли каталог из 3200+ готовых ИИ-агентов под любые задачи. Можно запускать в один клик без кода</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Парсинг]]></category>
      <category><![CDATA[Slack]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[TypeScript]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[Telegram]]></category>
      <category><![CDATA[Intel]]></category>
      <category><![CDATA[Маркетинг]]></category>
      <category><![CDATA[Аналитика]]></category>
      <category><![CDATA[Discord]]></category>
      <category><![CDATA[Дизайн]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[аналитик]]></category>
      <category><![CDATA[1C]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Notion]]></category>
      <category><![CDATA[CI/CD]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 07 Jul 2025 12:19:01 GMT</pubDate>
      <content:encoded><![CDATA[<p>В Сети обнаружили огромный <a href="https://n8nworkflows.xyz/">каталог </a>из более чем 3200 готовых рабочих процессов и ИИ-агентов для автоматизации рутинных задач через визуальный конструктор n8n. Сервис позволяет запускать агентов в один клик, настраивать пайплайны под свои потребности и быстро собирать целые «команды» из нейросетей для маркетинга, разработки, продаж, кибербезопасности, дизайна и исследования рынков.</p><p>Больше новостей — в нашем тг-канале <a href="https://t.me/+WYtyV4-XYmdhZTMy">Представляешь</a></p><h2>Что такое n8n</h2><p>Рост использования ИИ в рутине разработки, маркетинга и бизнеса приводит к потребности в простых и гибких инструментах, которые позволяют быстро соединять модели, API и данные в работающие пайплайны. Каталог n8n даёт инженерам и продуктовым командам фору: можно за день собрать MVP своего ассистента или системы автоматизации, сократив месяцы разработки.</p><p>Кроме того, открытый характер библиотеки помогает командам учиться на чужих кейсах, улучшать процессы и участвовать в развитии сообщества.</p><p>На данный момент на сайте доступно:</p><ul><li>457 простых пайплайнов для новичков;</li><li>1349 пайплайнов среднего уровня сложности;</li><li>1440 продвинутых решений для профессионалов и команд автоматизации.</li></ul><p>Каждый агент сопровождается документацией, описанием кейсов использования и рекомендациями по настройке. Также обновляется для совместимости с последними версиями n8n.</p><p>Запуск агента в n8n обычно занимает несколько минут:</p><ol><li>Вы выбираете нужный шаблон из каталога (например, автоматический парсинг HackerNews с публикацией в Telegram, автоматическую вёрстку в Notion, управление AWS-ключами через Slack или генерацию отчётов с помощью Claude).</li><li>Импортируете шаблон в свою среду n8n (SaaS или локально). Настраиваете ключи API или доступ к нужным сервисам (Telegram, Notion, Discord, AWS, HubSpot и др.).</li><li>Запускаете и получаете работающий агент, готовый к эксплуатации без написания кода.</li><li>Все процессы визуализированы, поэтому можно легко редактировать логику работы, добавлять свои шаги (например, постобработку с помощью GPT, уведомления в Slack или отправку в CRM) и адаптировать агента под свои задачи.</li></ol><h2>Какие задачи можно автоматизировать</h2><p>В каталоге есть ИИ-агенты и пайплайны для:</p><ul><li>SMM и маркетинга (сбор лидов, управление постингом, аналитика трендов);</li><li>Кибербезопасности (мониторинг SSL, автоматические алерты, управление ключами AWS);</li><li>Разработки (поддержка TypeScript Intellisense, автоматизация CI/CD);</li><li>Продуктивности (сбор и структурирование заметок в Notion, автоматизация писем, напоминания);</li><li>Исследований (поиск и структурирование данных с помощью ИИ, генерация дайджестов);</li><li>Дизайна (подготовка медиафайлов и управление рабочими процессами);</li><li>Продаж и клиентского сервиса (онбординг клиентов, автоматические уведомления и CRM-интеграции).</li></ul><p>Эти решения помогают запускать собственных ИИ-ассистентов для узких задач, ускорять работу команд и сокращать время на рутину.</p><h3>Что есть для разработчиков</h3><p>n8n остаётся платформой с открытым исходным кодом, поэтому разработчики могут:</p><ul><li>Клонировать и адаптировать любые из 3200+ рабочих процессов под свои нужды.</li><li>Интегрировать LLM (GPT-4o, Claude, Gemini) для создания сложных агентов с мультимодальными возможностями.</li><li>Выстраивать корпоративные пайплайны и автоматизированные рабочие места для команд.</li><li>Подключать плагины и собственные ноды для кастомных сценариев.</li><li>Запускать пайплайны локально или в облаке, сохраняя контроль над данными.</li></ul><p>Если вы строите собственных корпоративных ассистентов, хотите ускорить процессы или тестируете гипотезы, библиотека n8n может стать отличным полигоном для быстрой проверки решений без написания инфраструктурного кода.</p>]]></content:encoded>
    </item>
    <item>
      <title>Безопасное исполнение ненадёжного кода</title>
      <link>https://tproger.ru/articles/bezopasnoe-ispolnenie-nenadyozhnogo-koda</link>
      <comments>https://tproger.ru/articles/bezopasnoe-ispolnenie-nenadyozhnogo-koda?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Александр Межов]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/bezopasnoe-ispolnenie-nenadyozhnogo-koda</guid>
      <description><![CDATA[<p>Методы безопасного исполнения ненадёжного кода. Рассматриваются уровни изоляции кода, методы ограничения ресурсов процесса, проблемы жёсткого лимитирования и подходы к их решению. Обсуждаются вопросы управления песочницами, а также использование инструментов контейнеризации.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/bezopasnoe-ispolnenie-nenadyozhnogo-koda">Безопасное исполнение ненадёжного кода</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Тестирование]]></category>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Опрос]]></category>
      <category><![CDATA[Практика]]></category>
      <category><![CDATA[.NET]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[Docker]]></category>
      <category><![CDATA[Redis]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Kubernetes]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Машин]]></category>
      <category><![CDATA[микро]]></category>
      <category><![CDATA[Песочница]]></category>
      <category><![CDATA[1C]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[CI/CD]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 06 Jul 2025 09:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Мы привыкли к тому, что ведем разработку, используя лучшие инженерные практики, включая настройку CI/CD-конвейера. Сначала код проходит многоэтапные стадии проверки и тестирования, а только потом попадает в production-среду.</p><p>Давайте представим ситуацию, что нужно запустить код, минуя все эти стадии. Прям в production-среде. На первый взгляд — бред! Но если подумать, то на самом деле, не такая уж редкость. Например, некоторые системы предоставляют своим пользователям возможность расширять функциональность за счет прикладных скриптов. Наш любимый CI/CD-конвейер зачастую построен на пользовательских скриптах.</p><p>С одной стороны, для большинства подобная постановка вопроса — крайность. С другой, появляется возможность рассмотреть проблему с разных ракурсов. Уверен, что какие-то части общего решения, о котором пойдёт речь далее, могут быть использованы повторно и в других проектах.</p><p>Предлагаю по частям разобрать проблему безопасного исполнения ненадёжного кода. Последовательно рассмотрим вопросы, ответы на которые поворотные в выборе целевой архитектуры. Большая часть статьи касается разработки, но в конце сделаны важные акценты относительно администрирования и развертывания.</p><h2>Ненадёжный код</h2><p>Для начала определимся, что же считать ненадёжным кодом? На самом деле ответ зависит от решаемой задачи, правил и процессов, принятых в компании:</p><ul><li>Код, который не прошел CI, review и т.п.</li><li>Код из ненадёжного или неизвестного источника.</li><li>Закрытый (проприетарный) код.</li><li>Код, содержащий уязвимости.</li><li>Код, использующий запрещенные функции.</li><li>Любой код, который написал коллега:)</li></ul><p>Чтобы отделять код разрабатываемого приложения от ненадёжного, первый буду называть кодом приложения, а второй — <i>ненадёжным</i> или <i>внешним кодом</i>. Необходимость запуска ненадёжного кода в некоторых случаях буду называть <i>задачей</i>.</p><h2>Уровни изоляции кода</h2><p>Можно выделить три варианта запуска внешнего кода — три уровня изоляции. Каждый следующий увеличивает дистанцию между кодом приложения и запускаемым кодом. Чем выше уровень изоляции, тем меньше вероятность, что запускаемый код нанесет вред приложению и системе.</p><h3>Уровень 1: тот же процесс</h3><p>Запуск внешнего кода в адресном пространстве процесса приложения.</p><figure><img src="https://media.tproger.ru/user-uploads/115455/2025-06-18/191fd454-6837-4e91-abbf-c6d4a1fb6121.png" alt="Запуск внешнего кода в адресном пространстве процесса приложения." /><figcaption>Запуск внешнего кода в адресном пространстве процесса приложения.</figcaption></figure><p>Такой способ определяет самый слабый уровень изоляции, поскольку запущенный код теоретически имеет доступ ко всему тому, к чему имеет доступ код самого приложения.</p><p>Примером может служить использование интерпретаторов скриптов (<a href="https://github.com/mozilla/rhino">Rhino</a>, <a href="https://github.com/IronLanguages/ironpython3">IronPython</a>, <a href="https://github.com/jython/jython">Jython</a> и т.п.), визуальных языков программирования (workflow-движков) или подключение модулей расширения (плагинов).</p><p>Способов защиты на этом уровне не так много. Пожалуй, самым эффективным выступает (self-sandboxing), при котором приложение делает самозапрет на доступ к некоторым ресурсам системы. Например, сразу после инициализации — самозапрет на доступ к файловой системе.</p><p>Дополнительно запускаемый код можно подвергать строгому (синтаксическому) анализу, запрещая использование определенных функций, модулей, пакетов и т.п. Некоторые интерпретаторы имеют точки расширения, которые позволяют контролировать процесс исполнения. Если такой возможности нет, можно воспользоваться одной из техник самоизоляции — <a href="https://www.kernel.org/doc/html/latest/userspace-api/seccomp_filter.html">фильтрацией системных вызовов</a>.</p><p>Что же касается плагинов, то они призваны расширять возможности приложения, поэтому их использование изначально не предполагает сильной изоляции. Здесь можно предложить усилить контроль взаимодействия на уровне контракта (API). В идеале — если плагины будут публиковаться в некоторый центральный репозиторий, которому вы доверяете и который может производить дополнительные проверки и тестирование до этапа запуска кода плагина.</p><h3>Уровень 2: отдельный процесс</h3><p>Запуск внешнего кода на той же машине, но в отдельном процессе ОС.</p><figure><img src="https://media.tproger.ru/user-uploads/115455/2025-06-18/e0bf62de-65a9-4370-9986-ed21c6e63b8e.png" alt="Запуск внешнего кода на той же машине, но в отдельном процессе ОС." /><figcaption>Запуск внешнего кода на той же машине, но в отдельном процессе ОС.</figcaption></figure><p>Поскольку и приложение, и внешний код взаимодействуют в рамках одного узла, используя локальные ресурсы ОС (оперативная память, файловая система и т.п.), скорость межпроцессного взаимодействия очень высокая.</p><p>Этот уровень изоляции предполагает использование широкого арсенала возможностей. Как минимум, внешний код может быть запущен от имени менее привилегированного пользователя, с ограниченным доступом к ресурсам ОС. Сильные способы изоляции ограничивают ресурсы с помощью средств ОС или инструментов контейнеризации. Однако, чем сильнее контроль, тем больше накладных расходов на запуск и исполнение процесса, что при решении некоторых задач неприемлемо дорого или неоправданно сложно.</p><h3>Уровень 3: отдельная машина</h3><p>Запуск внешнего кода на отдельной машине — песочнице.</p><figure><img src="https://media.tproger.ru/user-uploads/115455/2025-06-18/5e48bc50-75c9-4789-9dc7-3bbf2c1659a7.png" alt="Запуск внешнего кода на отдельной машине — песочнице." /><figcaption>Запуск внешнего кода на отдельной машине — песочнице.</figcaption></figure><p>Это максимальный уровень изоляции из всех возможных. Здесь появляется возможность ограничить ресурсы самой песочницы (CPU, память, дисковое пространство, доступ к сети и т.п.). Если в результате исполнения внешнего кода песочница выйдет из строя, приложение продолжит свою работу.</p><p>Самый главный недостаток этого подхода — необходимость сетевого взаимодействия между узлом, на котором работает приложение, и песочницей. Передача входных данных в песочницу, запуск процесса внутри, ожидание окончания его исполнения, получение выходных данных — всё это сетевые обращения. Так существенно замедляется процесс исполнения, а само взаимодействие подвержено сетевым сбоям, что ведёт к нестабильности системы и получаемых результатов.</p><h2>Использование песочницы</h2><p>Предположим, требуется максимальный уровень изоляции ненадёжного кода, следовательно, нужно остановиться на варианте запуска на отдельной машине. Если так, то для принятия последующих архитектурных решений нужно ответить на следующую пару вопросов.</p><h3>Пересоздание или переиспользование песочницы</h3><p>Песочницу требуется пересоздавать перед исполнением каждой задачи, если требуется особенное окружение (например, определенная версия ОС, пакетов или ресурсов) или идентичность этого окружения (для стабильности получаемых результатов). Схожие вопросы возникают, например, при интеграционном тестировании: каждому тесту нужны свои предустановки.</p><p>Переиспользование песочницы становится возможным, если задачи могут исполняться в одном окружении и не оказывают влияния друг на друга (предыдущая задача не портит результаты последующей). Продолжая аналогию с интеграционным тестированием: всем тестам нужны одинаковые предустановки, и тесты могут запускаться повторно на одном стенде, демонстрируя один и тот же результат.</p><p>Основным преимуществом пересоздания песочницы выступает стабильность получаемых результатов. К недостаткам относится медленный запуск и перерасход ресурсов. На пересоздание песочницы уходят десятки секунд или даже минут, следовательно, большая часть ресурсов будет тратиться именно на это. Существует множество техник ускорения пересоздания, благодаря которым можно сократить время запуска. Прежде всего, сюда можно отнести backup/restore (snapshot песочницы, базы данных и т.п.). Также если поток задач небольшой и ресурсы позволяют, можно попробовать организовать пул песочниц и создавать их заранее.</p><p>Ставка на переиспользование делается в случае, когда поток задач большой и нужно сократить время ожидания их запуска. При этом возрастает вероятность получения нестабильных результатов и, возможно, требуется производить какую-то очистку окружения до или после исполнения очередной задачи.</p><h3>Последовательное или параллельное исполнение</h3><p>Теперь осталось ответить на вопрос, как именно можно или нужно исполнять задачи: последовательно или параллельно. Последовательное исполнение требуется в следующих случаях:</p><ul><li>важен порядок следования и исполнения задач;</li><li>задачам нужен эксклюзивный доступ к определенному ресурсу;</li><li>задачи ёмкие и их совместное исполнение вызовет нехватку ресурсов;</li><li>задачи могут мешать исполнению друг друга из-за борьбы за ресурсы.</li></ul><p>Например, шаги установки и настройки ПО; шаги CI/CD-конвейера; рендеринг изображения на GPU; интенсивные вычисления. Все эти задачи, скорее всего, придётся исполнять <b>последовательно</b>.</p><p>В остальных случаях допустимо <b>параллельное исполнение</b>. Яркой аналогией может служить одна из лучших практик в тестировании: тесты не должны оказывать влияние друг на друга, а порядок их запуска не должен иметь значения.</p><p>Последовательное исполнение обеспечивает стабильность получаемых результатов, однако приводит к низкой пропускной способности и дороговизне масштабирования (песочница обходится дороже процесса ОС). Параллельное исполнение, напротив, увеличивает пропускную способность системы и улучшает утилизацию ресурсов песочницы, но одновременно повышает вероятность нестабильных результатов. Более того, при параллельном исполнении появляется шанс перегрузить песочницу или вывести её из строя таким образом, что приведет к увеличению времени исполнения всех запущенных задач или потере результатов их работы.</p><p>На практике было замечено, что при параллельном исполнении, несмотря на увеличенную общую пропускную способность, время исполнения каждой отдельной задачи увеличивается. Если уровень параллелизма становится больше числа CPU-ядер, время исполнения начинает деградировать намного сильней.</p><h2>Управление песочницами</h2><p>Допустим, переиспользование песочниц возможно. В таком случае необходимо определить способ управления ими. Можно выделить два подхода, основанные на принципах микросервисной архитектуры, но адаптированные к специфике рассматриваемой проблемы.</p><h3>Оркестрация</h3><p>Оркестрация предполагает, что приложение совмещает две роли: оркестратор исполнения и оператор песочниц. Оркестратор координирует процесс исполнения кода: выбор подходящей песочницы, загрузка в неё входных данных, запуск удалённого процесса, получение результатов его работы и т.п. Оператор, в свою очередь, отслеживает доступные песочницы и их состояние.</p><figure><img src="https://media.tproger.ru/user-uploads/115455/2025-06-18/93758cab-2542-4a80-b47a-d65b04ef4f14.png" alt="Оркестрация песочниц." /><figcaption>Оркестрация песочниц.</figcaption></figure><p>Основное преимущество оркестрации в контексте решаемой проблемы — её простота и ясность. Код легко читается и сосредоточен в одном месте. Однако у этого решения есть и недостатки. Рассмотрим их в порядке от простого к сложному.</p><ul><li><i>Синхронное взаимодействие.</i> Так или иначе, для результата приложение вынуждено ожидать окончания исполнения задачи. Для продуктивного использования ресурсов приходится прибегать к техникам асинхронного программирования: пока задача исполняется, приложение будет занято полезной работой. Это малозаметный недостаток в языках со встроенной поддержкой концепции асинхронного программирования. Для упрощения работы с асинхронным кодом в Java я создал небольшую вспомогательную библиотеку <a href="https://github.com/AlexMAS/asynchronizer">asynchronizer</a>, снабдив её подробной <a href="https://github.com/AlexMAS/asynchronizer/blob/main/docs/README.ru.md">документацией</a>.</li></ul><ul><li><i>Отслеживание доступности песочниц.</i> Поскольку хотелось бы, чтобы количество песочниц менялось в зависимости от нагрузки на систему, придётся отслеживать их доступность. Это прямая обязанность оператора песочниц, которую можно выделить в отдельный discovery-сервис (например, на базе <a href="https://github.com/spring-cloud/spring-cloud-netflix">Netflix Eureka</a>), либо реализовать как часть приложения с использованием инфраструктурных механизмов (например, <a href="https://github.com/fabric8io/kubernetes-client">Kubernetes API</a>). Важно отметить, что оператор песочниц не имеет отношения к бизнес-логике приложения.</li></ul><ul><li><i>Отслеживание загруженности песочниц.</i> Оркестратор исполнения должен выбрать подходящую <a href="https://samwho.dev/load-balancing/">стратегию балансировки</a>, основанную на состоянии песочниц, предоставляемых оператором. На практике наилучшую эффективность демонстрирует алгоритм Least connections, с помощью которого можно выбирать наименее загруженные песочницы. Для этого достаточно вести учёт количества задач, исполняемых каждой песочницей. Конечно, это не серебряная пуля, а лишь частное наблюдение, поэтому в идеале нужно предусмотреть несколько стратегий балансировки и выбрать наилучшую по результатам нагрузочного тестирования.</li></ul><ul><li><i>Неопределённость результата, если нет ответа от песочницы.</i> Песочница может быть недоступна по различным причинам, включая не только проблемы с сетью, но и падения песочницы из-за ненадёжного кода. К сожалению, в общем случае эта проблема не имеет решения, так как делать повторные запуски (retries) может быть опасно. Всё, что остаётся, это использовать таймауты и откладывать неуспешную задачу на потом.</li></ul><p>Ещё один существенный минус, который стоит упомянуть, это возможный побочный эффект, возникающий при масштабировании системы и проявляющийся в виде перегрузки песочниц. Для наглядности рассмотрим конкретный пример.</p><p>Для отслеживания нагрузки на песочницы экземпляр приложения ориентируется на количество задач в каждой из доступных песочниц. Предположим, что было принято решение увеличить количество экземпляров приложения. Этот экземпляр исполняет 5 задач в двух песочницах (3 процесса в одной и 2 в другой). Известно, что каждая песочница может вынести максимум 4 параллельных задачи.</p><figure><img src="https://media.tproger.ru/user-uploads/115455/2025-06-18/623f7e7c-71d0-41da-8681-731ef43d3716.png" alt="Экземпляр исполняет 5 задач в двух песочницах (3 процесса в одной и 2 в другой)." /><figcaption>Экземпляр исполняет 5 задач в двух песочницах (3 процесса в одной и 2 в другой).</figcaption></figure><p>Добавив новый экземпляр приложения, неизвестно, сколько задач исполняет каждая песочница. Такая ситуация может произойти по разным причинам.</p><figure><img src="https://media.tproger.ru/user-uploads/115455/2025-06-18/7131d310-7c0d-44b8-b031-055436bd64d8.png" alt="Новый экземпляр приложения не знает, сколько задач исполняет каждая песочница." /><figcaption>Новый экземпляр приложения не знает, сколько задач исполняет каждая песочница.</figcaption></figure><p>Вполне очевидно, что новый экземпляр приложения направит очередную задачу в первую попавшуюся песочницу, чем может спровоцировать её перегрузку. В итоге результат исполнения будет испорчен или потерян из-за падения песочницы.</p><figure><img src="https://media.tproger.ru/user-uploads/115455/2025-06-18/c65090e5-020f-4eff-826b-566d3dc6da5c.png" alt="Очередная задача направляется в первую песочницу и провоцирует её перегрузку." /><figcaption>Очередная задача направляется в первую песочницу и провоцирует её перегрузку.</figcaption></figure><p>В качестве решения можно предложить два способа, каждый из которых уменьшает вероятность возникновения перегрузок, но не избавляет от них.</p><ul><li><i>Для контроля количества исполняемых задач в песочнице использовать распределённый счётчик</i> (например, на базе Redis). Проблема в том, что распределённый счётчик имеет латентность и на момент запуска задач может выдать устаревшее значение. Кроме того, в системе появляется еще один инфраструктурный компонент, который не несёт бизнес-пользы.</li></ul><ul><li><i>Выделить каждому экземпляру приложения эксклюзивное подмножество песочниц.</i> Подобное решение существенно усложнит deployment-скрипты и процесс масштабирования, а также снизит степень утилизации выделенных ресурсов, ведь нет никаких гарантий того, что экземпляр приложения сможет хорошо нагрузить все выделенные ему песочницы.</li></ul><p>Кстати, после доклада на TechLeadConf 2025 мне задали интересный вопрос: <i>Можно ли при балансировке нагрузки на песочницы учитывать не только количество исполняемых задач, но и процент загрузки CPU, памяти и прочих ресурсов? </i>Если у кого-то возник такой же вопрос, то отвечу, что это не имеет смысла, поскольку ситуация в песочнице может поменяться мгновенно. Полученный практический опыт и нагрузочное тестирование показали, что простой подсчёт задач работает эффективно.</p><h3>Самоорганизация</h3><p>В микросервисной архитектуре подобный подход принято называть хореографией, однако чтобы не возникало неправильных ассоциаций, предлагаю использовать термин <i>самоорганизация</i>.</p><p>Ключевой момент в архитектуре — это появление двух очередей: очередь задач на исполнение (Task Queue) и очередь результата их исполнения (Result Queue). Все поступающие задачи приложение направляет в первую очередь, а результаты — во вторую. Дополнительно появляется роль агента — микросервиса, который исполняется в рамках узла песочницы и координирует исполнение поступающих задач.</p><figure><img src="https://media.tproger.ru/user-uploads/115455/2025-06-18/0d449846-e767-49bd-bd50-d1c77c49cf10.png" alt="Самоорганизация песочниц." /><figcaption>Самоорганизация песочниц.</figcaption></figure><p>Основной недостаток самоорганизации — распределённый процесс обработки задач. Учитывая простоту алгоритма обработки, это не так существенно. Стоит отметить преимущества этой архитектуры.</p><ul><li><i>Максимальная изоляция ненадёжного кода.</i> Ненадёжный код, как и в случае с оркестрацией, по-прежнему работает в песочнице в рамках отдельного процесса ОС.</li></ul><ul><li><i>Скорость и стабильность взаимодействия.</i> Никаких проблем с сетью  из-за локальности взаимодействия между агентом и песочницей.</li></ul><ul><li><i>Контролируемая нагрузка на песочницы.</i> Агент, выступая в роли консюмера очереди задач, может точно контролировать степень параллелизма и выбирать новые задачи только тогда, когда он закончил обрабатывать предыдущие.</li></ul><ul><li><i>Минимум инфраструктурного кода.</i> Очереди избавляют от необходимости иметь оператор песочниц, отслеживать их состояние и осуществлять балансировку нагрузки.</li></ul><ul><li><i>Простота масштабирования.</i> Приложение и песочницы масштабируются независимо друг от друга без негативных побочных эффектов.</li></ul><h2>Запуск процесса ОС</h2><p>К запуску процесса ОС, в рамках которого будет исполняться ненадёжный код, нужно подойти с особой осторожностью. Здесь важно ответить как минимум на три вопроса.</p><ul><li><i>Как ограничить права доступа к ресурсам.</i> Самое простое решение — запуск процесса от имени пользователя с ограниченными правами (на доступ к ресурсам ОС).</li></ul><ul><li><i>Как ограничить объем используемых ресурсов.</i> Для запускаемого процесса нужно определить доступные ресурсы и возможные действия.</li></ul><ul><li><i>Как осуществлять анализ поведения и результатов исполнения.</i> Наличие и решение этой проблемы целиком и полностью зависит от специфики проекта. Здесь невозможно предложить универсального решения.</li></ul><p>Рассмотрим варианты ограничения ресурсов процесса ОС.</p><h3>Ограничение ресурсов процесса</h3><p>Ресурсы процесса могут быть ограничены на трех уровнях:</p><ul><li><i>Лимиты узла.</i> Физические ограничения машины, на которой исполняется процесс. В частном случае можно говорить об инфраструктурных лимитах, определённых для Docker/Kubernetes контейнера.</li></ul><ul><li><i>Лимиты контейнера.</i> Программные лимиты, задаваемые выбранным инструментом контейнеризации (cgroup, Docker, <a href="https://dzen.ru/a/Z8sdaQvf5w96SRes">Bubblewrap</a>, <a href="https://github.com/AlexMAS/ProcessSandbox">ProcessSandbox</a> и т.п.).</li></ul><ul><li><i>Лимиты процесса.</i> Программные лимиты, задаваемые средствами ОС. На этом уровне можно осуществлять гибкую настройку вариантов запуска и исполнения.</li></ul><figure><img src="https://media.tproger.ru/user-uploads/115455/2025-06-18/d11a1ee8-1780-4ca6-b826-a09d4d95ed0d.png" alt="Уровни лимитирования ресурсов процесса." /><figcaption>Уровни лимитирования ресурсов процесса.</figcaption></figure><p>Можно использовать все три уровня лимитирования, либо какой-то определенный.</p><p>Между тем, важно отметить некоторые трудности, которые могут возникнуть при использовании инструментов контейнеризации.</p><p>Например, для использования cgroup или Docker внутри Kubernetes-контейнера нужно эскалировать привилегии контейнера, что в общем случае небезопасно в контексте исполнения ненадёжного кода. Более того, практика показала, что легковесных rootless-средств, предоставляемых ОС, вполне достаточно, чтобы снять большую часть рисков. В частности, Linux API позволяет не только лимитировать CPU и память, но и блокировать доступ к некоторым возможностям самой ОС. Например, можно наложить фильтр, который запретит вызов определённых системных функций.</p><h3>Проблемы жёсткого лимитирования</h3><p>Рассмотренные выше способы лимитирования задают жёсткие границы (hard limit), нарушение которых замедляет исполнение процесса, либо приводит к его принудительному завершению. При этом поведение наблюдаемого процесса и системы сильно варьируется в зависимости от того, какой лимит был превышен. Например, превышение по использованию CPU может привести к троттлингу (throttling), приостановке работы или принудительному завершению; превышение по использованию памяти заканчивается принудительным завершением со стороны ОС (OOM Killer) либо самостоятельным падением процесса (с ошибкой Out Of Memory).</p><p>Подобная вариативность осложняет <i>анализ поведения и результатов исполнения.</i> В этом случае можно использовать подход с программной мягкой границей (watchdog limit). Суть заключается в запуске дополнительного следящего потока (или процесса) ОС, который контролирует поведение и расход ресурсов у наблюдаемого. Как только детектируется превышение одного из лимитов, производится принудительное завершение наблюдаемого процесса, но уже не со стороны ОС, а со стороны приложения.</p><figure><img src="https://media.tproger.ru/user-uploads/115455/2025-06-18/e38eb138-04f3-439f-89b5-9b810f112a69.png" alt="Программная мягкая граница (watchdog limit)." /><figcaption>Программная мягкая граница (watchdog limit).</figcaption></figure><p>Такой подход имеет несколько преимуществ.</p><ul><li><i>Точное определение причин принудительного завершения.</i> Жёсткие лимиты чуть выше мягких, благодаря чему для исполняемого кода создаётся иллюзия отсутствия каких-либо лимитов. Между тем, если лимиты всё-таки нарушаются, процесс всё равно будет завершен (либо со стороны приложения, либо гарантированно со стороны ОС). Но подобный дополнительный контроль со стороны приложения оставляет для него гораздо больше шансов понять причину принудительного завершения наблюдаемого процесса.</li></ul><ul><li><i>Возможность гибкого лимитирования ресурсов.</i> Приложение (или агент), ответственное за запуск наблюдаемого процесса, может обратиться к средствам ОС (в частности, к Linux API) и гибко настроить параметры запуска и исполнения. Как минимум, жёстко определить лимиты по CPU и памяти; наложить ограничения на объем I/O; создать запрет на вызов некоторых системных функций (например, запрет использования сетевых операций или файловой системы) и т.п.</li></ul><p>Такой подход я назвал watchdog и в целях иллюстрации реализовал его в виде .NET-библиотеки <a href="https://github.com/AlexMAS/ProcessSandbox">ProcessSandbox</a>. Помимо прочего, на странице проекта подробно рассмотрена проблематика контроля и анализа поведения процесса ОС со стороны прикладного кода.</p><p>Итоговая схема лимитирования может выглядеть так, как показано на рисунке ниже. Вместо тяжеловесных инструментов контейнеризации используется легковесный rootless-инструмент (watchdog) на базе средств ОС и только.</p><figure><img src="https://media.tproger.ru/user-uploads/115455/2025-06-18/2c5e74e4-125b-467d-8b27-30b005364523.png" alt="Лимитирование ресурсов процесса с помощью watchdog." /><figcaption>Лимитирование ресурсов процесса с помощью watchdog.</figcaption></figure><p>Для задач, где не нужен анализ поведения процесса и тонкая настройка лимитов, можно воспользоваться готовым инструментом — утилитой.</p><h2>Многоконтейнерные поды</h2><p>Зная, что контейнеры одного Kubernetes-пода работают на одном и том же узле, можно попытаться решить проблему нестабильности сетевого взаимодействия приложения и песочницы, разместив их контейнеры в одном поде.</p><figure><img src="https://media.tproger.ru/user-uploads/115455/2025-06-18/62400b6a-9c5b-4285-bff8-b0adb5ac8868.png" alt="Размещение контейнера приложения и песочницы в одном Kubernetes-поде." /><figcaption>Размещение контейнера приложения и песочницы в одном Kubernetes-поде.</figcaption></figure><p>Несмотря на всю заманчивость данной идеи, она несёт ряд недостатков.</p><ul><li><i>Плохая масштабируемость.</i> Соотношение приложение-песочница всегда один к одному. Однако не исключено, что в некоторых случаях это вполне приемлемо.</li></ul><ul><li><i>Плохая утилизация ресурсов.</i> Сможет ли приложение достаточно нагрузить песочницу, если количество песочниц будет в избытке; и наоборот, нужно ли столько же экземпляров приложения, сколько и песочниц.</li></ul><ul><li><i>Возможность перегрузки песочницы.</i> В распоряжении экземпляра приложения только одна песочница, которая может не справиться с потоком задач, обрабатываемых приложением.</li></ul><ul><li><i>Риск нарушить работоспособность приложения.</i> Выход песочницы из строя скорее всего приведет к перезапуску всего пода. Более того, если приложение и песочница обмениваются файлами через общий раздел (<a href="https://kubernetes.io/docs/tasks/access-application-cluster/communicate-containers-same-pod-shared-volume/">shared volume</a>), это может стать уязвимым местом.</li></ul><h2>Образ для песочницы</h2><p>Основные моменты, которые следует учесть при создании (Docker) образов песочниц:</p><ul><li><i>Заменить init-процесс</i> на <a href="https://github.com/krallin/tini">tini</a>, чтобы не превысить лимит по PIDs.</li></ul><ul><li><i>Создать непривилегированного пользователя,</i> ограничив ему права на доступ к ресурсам.</li></ul><ul><li><i>Регулярно сканировать версии образов</i> и пакетов на наличие уязвимостей.</li></ul><h2>Инфраструктура исполнения</h2><p>Основные моменты, которые следует учесть при настройке инфраструктуры исполнения:</p><ul><li><i>Обеспечить быстрый (пере)запуск песочниц.</i> Нужно быть готовым к тому, что песочницы будут падать. Если речь идет о Kubernetes, то улучшить время запуска может подходящая настройка <a href="https://kubernetes.io/docs/concepts/containers/images/">Image Pull Policy</a>. При этом лучше не использовать тег `latest`, а указывать конкретную версию или хэш-код образа, чтобы не тратить время на попытки определения последней версии при каждом запуске.</li></ul><ul><li><i>Установить приемлемый <a href="https://kubernetes.io/docs/concepts/policy/pid-limiting/">лимит на PIDs</a>.</i> Необходимо контролировать число активных процессов в системе. Особо вредоносный код может попытаться создать очень много дочерних процессов, поэтому при отсутствии лимита на PIDs узел быстро будет выведен из строя. Важно отметить, что лимит задаётся для пользователя, а не для запускаемого процесса. По этой причине он должен быть разумно большим.</li></ul><ul><li><i>Установить <a href="https://kubernetes.io/docs/concepts/policy/resource-quotas/">лимиты на ресурсы узла</a>.</i> В Kubernetes для каждого контейнера нужно указать, как минимум, лимиты по CPU и памяти. Значения лимитов лучше всего определить в ходе нагрузочного тестирования или путём сбора метрик приложения.</li></ul><h2>Заключение</h2><p>Как можно заметить, задача исполнения ненадёжного кода всегда решается в комплексе, начиная с анализа, продолжая разработкой и заканчивая вопросами уровня DevOps. Думаю, что многие техники и инструменты применимы и к коду самого приложения.</p><p>Я постарался показать последовательность шагов по направлению к целевой архитектуре, которая будет отвечать требованиям бизнеса и справляться с ненадёжным кодом. <i>Если вам интересна данная тематика, подписывайтесь на мой Telegram-канал Архитектоника в ИТ (@arch_and_dev). Буду рад поделиться опытом. </i></p>]]></content:encoded>
    </item>
    <item>
      <title>Микросервисная архитектура: от монолита к гибкой системе</title>
      <link>https://tproger.ru/articles/mikroservisnaya-arhitektura--ot-monolita-k-gibkoj-sisteme</link>
      <comments>https://tproger.ru/articles/mikroservisnaya-arhitektura--ot-monolita-k-gibkoj-sisteme?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Татьяна Жукова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/mikroservisnaya-arhitektura--ot-monolita-k-gibkoj-sisteme</guid>
      <description><![CDATA[<p>«Монолит или микросервисы» — вопрос, который до сих пор вызывает споры в IT. СТО Сервисной цифровой платформы в Газпромбанке делится личным опытом перехода к микросервисной архитектуре, разбирает реальные кейсы и объясняет, почему однозначного ответа не существует.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/mikroservisnaya-arhitektura--ot-monolita-k-gibkoj-sisteme">Микросервисная архитектура: от монолита к гибкой системе</a>»</p>]]></description>
      <category><![CDATA[Интернет]]></category>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[Ретро]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Опрос]]></category>
      <category><![CDATA[Микросервисы]]></category>
      <category><![CDATA[Практика]]></category>
      <category><![CDATA[Google]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[Навыки]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[QA]]></category>
      <category><![CDATA[Аналитика]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Kubernetes]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[аналитик]]></category>
      <category><![CDATA[микро]]></category>
      <category><![CDATA[Grafana]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Архитектура приложений]]></category>
      <category><![CDATA[CI/CD]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 27 Jun 2025 08:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Привет! Меня зовут Андрей Бирюков, я СTO Сервисной цифровой платформы в Газпромбанке. За свою карьеру поработал в нескольких компаниях — от стартапов до крупных корпораций — и видел разные архитектурные подходы.</p><p>И вот начала копиться усталость от обсуждения, что использовать — монолиты или микросервисы. Этот вопрос стал преследовать меня на конференциях, в офисе, в личных сообщениях. Я потратил столько времени на обсуждение этой темы, что иногда хочется просто распечатать какой-нибудь емкий ответ на футболке и ходить в ней на все митапы.</p><p>Шутки шутками, но тема действительно важная. Я прошел путь от классических монолитных приложений до сложных микросервисных, проектировал системы, которые работают под большой нагрузкой, и пришел к выводу, что однозначного ответа здесь не существует. И вообще, «монолит или микросервисы» — это неправильная постановка вопроса.</p><p>Недавно сходил с Витей на запись <a href="https://vkvideo.ru/video-145457488_456239831">подкаста</a> на эту тему и настолько преисполнился, что решил в текстовом виде формализировать свое отношение к теме (я гнался за вами три дня, чтобы сказать, как вы мне безразличны, ага), обобщить то, о чем говорили, и попытаться дать ответ на вопрос «когда микросервисы действительно помогают и как не сойти с ума, если вы с ними работаете». Порассуждаю о проектировании, поддержке, DevOps-культуре и попробую немного заглянуть в микросервисную архитектуру.</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-06-27/98a19000-c584-440e-bf7a-af36d4409a2a.png" alt="" /><figcaption>Подкаст «Техно.Логично»</figcaption></figure><h2>Микросервисы: зачем они нужны и в чем их плюсы</h2><h3>Архитектура приложений: немного базы</h3><p>Под капотом современных приложений обычно скрываются три основные части:</p><ul><li>множество библиотек и зависимостей;</li><li>единый store, в котором живут состояние и данные;</li><li>компоненты, которые нужно собрать, чтобы сделать из них приложение.</li></ul><p>Собрать это все можно по-разному. Можно сложить в монолит, а можно попробовать модульный подход.</p><p>Монолитное приложение — старое доброе приложение, которое, как правило, создают один или несколько разработчиков, потом его дорабатывает армия джунов, синьоров и всех, кто оказался рядом. Каждый «чуть-чуть поправил», и вот уже никто не понимает, почему оно работает, — но трогать страшно. Монолиты пишут и сейчас — все зависит от бизнеса. Если нужно приложение для небольшого проекта, микросервисы могут и не понадобиться.</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-06-27/02011912-2de9-4c86-9de2-44865eb93fab.png" alt="" /><figcaption>Как выглядит монолит</figcaption></figure><p>Однако наступает момент, когда бизнес расширяется, аудитория растет, нагрузка увеличивается — а масштабировать монолит становится все сложнее. Тогда и приходят на помощь микросервисы.</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-06-27/739de2ec-05c4-4f68-bf1a-356380611028.png" alt="" /><figcaption>А вот приложение с микросервисной архитектурой</figcaption></figure><p>Масштабировать можно и монолиты, но у них всегда остается какая-то единая точка отказа — например, база данных. Особенно если это реляционная СУБД, завязанная на Oracle или PostgreSQL. Когда база достигает сотен гигабайт или даже терабайт, масштабировать такую штуку становится дорого, больно и ненадежно.</p><h3>Микросервисы — панацея? Не совсем</h3><p>Тренд на микросервисный подход появился в начале 2010-х годов, вместе с проникновением интернета в широкие слои населения. Первый iPhone вышел в 2007 году, люди стали гораздо ближе к интернету, к данным, к информации. Бизнес захотел дотянуться до этой аудитории, и тогда началась диджитализация, сложность систем стала повышаться. Особенно остро это почувствовали крупные организации вроде банков: функциональность увеличивалась, и монолит начал «трещать» не только технически по инфраструктуре, но и по возможностям команд разработки, которые с ним работали.</p><p>Плюсы микросервисов очевидны: масштабируемость, независимая разработка, изоляция компонентов. Но вместе с этим пришли новые проблемы — усложнились мониторинг и поддержка, стали требоваться все новые инструменты, чтобы обеспечивать работу огромной инфраструктуры. Так появился DevOps.</p><h2>Распространение DevOps-культуры и инструменты оркестрации</h2><p>Раньше разработчик писал код, собирал артефакт и перекидывал его через забор в поддержку. Коллеги за забором его деплоили, запускали — и разработчику можно было больше не думать про плоды своей работы.</p><p>В новой реальности количество артефактов, которые нужно перекидывать через забор, кратно выросло. Вместе с этим появилась и стала распространяться DevOps-культура: понимание, что за качественную раскатку в проде отвечает не только команда поддержки, но и разработчики.</p><p>Важно учитывать еще и то, что сложность поддержки кратно увеличилась. Если монолит можно было отдебажить, просто заглянув в логи, то с сотней микросервисов так не получится. Поэтому появились такие инструменты, как централизованное логирование, распределенный трейсинг — и сотни, если не тысячи других, связанных в первую очередь с observability. В таких обстоятельствах DevOps-культура стала особенно важна.</p><h2>Проектируем микросервисы без боли: от стандартов до DDD</h2><h3>Стандартизация — наше все</h3><p>Если каждый микросервис пишет логи в своем формате и использует свои библиотеки, получается зоопарк. Нужно, чтобы были выровнены стек и CI/CD pipeline, существовали одинаковые библиотеки логирования и формат.Микросервисы дают свободу писать на разных языках, но с ней приходит и ответственность: под каждый язык придется придумывать и поддерживать разные инструменты. А это приведет к еще большему увеличению сложности. Так что с языком тоже лучше соблюдать стандартизацию: если пишете на Java, то и решать все проблемы стоит с помощью этого языка.</p><p>При этом иногда другой язык вполне оправдан. Например, просто потому, что Java не может работать с такой высокой скоростью, какая нужна. В некоторых случаях даже на Java приходится писать особым образом, либо можно использовать C++, Go или Rust. Но это скорее исключение из правила.</p><p>Инженеры — натуры увлекающиеся и любят паттерн CV driven development, когда хочется новую технологию потрогать и внедрить у себя. А потом похвастаться этим на каком-нибудь ивенте по принципу «just because I can» («просто потому что могу»). При этом может оказаться, что бизнесу технология особо и не была нужна. Чтобы избегать таких ситуаций, необходим технологический радар — список того, что можно использовать в компании, а что нет. И исключения из такого радара должны приниматься и допускаться очень взвешенно.</p><h2>DDD: как правильно нарезать сервисы</h2><p>Одна из опасностей при проектировании микросервисов — скатиться в очень мелкую гранулярность, когда логика нарезается чуть ли не по отдельной функции на микросервис (на отдельный deployment unit). Это может привести к такой сложности, которой потом будет очень трудно управлять. Такая проблема была, например, у Uber в начале их пути, и им пришлось пересматривать свою архитектуру. Избежать этого помогает Domain-driven design (DDD) — предметно-ориентированное проектирование.</p><p>Вместо того чтобы пилить отдельные сервисы для авторизации, логирования и уведомлений, команда может подумать вот над чем: все это части одного бизнес-контекста — пользовательского доступа. И целесообразно оставить их в одном сервисе. Это и есть DDD в действии.</p><p>Существует и еще одна проблема, с которой DDD помогает справиться, — неправильная нарезка сервисов с точки зрения бизнесовой функциональности. Если не понимать бизнес-контекста, можно получить «распределенный монолит»: будет много отдельно стоящих сервисов, но профита никакого, только все сложности микросервисов плюс проблемы монолита с масштабируемой базой данных. Особенно остро это проявляется, когда изменения в одной части бизнес-процесса (в одном сервисе) влекут за собой изменения еще в трех-четырех-пяти других сервисах.</p><p>DDD помогает выделить bounded context — согласованные по бизнесу участки. Они позволяют более или менее правильно нарезать большой бизнес-функционал на отдельные части.</p><p>Еще один важный принцип правильной архитектуры микросервисов — у каждого микросервиса должна быть своя независимая маленькая база данных (если она вообще нужна).</p><p><b>Два эмпирических правила, которые касаются размера сервисов и помогают понять, правильно ли они спроектированы:</b></p><ul><li>Если вы не можете переписать сервис за две недели, значит, возможно, он неправильно нарезан, и его нужно декомпозировать.</li><li>Если вам страшно браться за переписывание сервиса, значит, он точно кандидат на декомпозицию.</li></ul><p>Внедрение микросервисов: с чего начать?</p><p>С микросервисным подходом есть проблема — нет четкого ответа, куда идти и что делать, чтобы научиться его создавать. Это одна из главных сложностей микросервисной архитектуры, особенно когда только начинаешь с ней работать. Если хочется изучить Spring или Oracle, можно почитать официальную документацию. А к такой большой и необъятной теме, как микросервисы, даже и непонятно, с какой стороны подступиться. Туториала к ней нет, есть только куча статей, подходов и практик. Причем одни практики подойдут конкретной команде, а другие — нет.</p><p>И вот тут возникает реальная сложность, особенно когда вы только начинаете, — глаза разбегаются. Здесь Kubernetes, здесь ELK, здесь Grafana, здесь observability, здесь всякие паттерны отказоустойчивости, CAP-теорема и прочее. Непонятно, куда бежать. И каждый день появляются новые инструменты, которые так или иначе упрощают жизнь.</p><p>Совет: задавайте себе вопрос о каждом инструменте, который вы хотите внедрить (будь то Kubernetes, OpenTelemetry с Jaeger или любой другой) — какую проблему мы решаем, втаскивая его в свою инфраструктуру? Ответ на этот простой вопрос может дать много инсайтов и просветлений.</p><p>Чтобы в первом приближении ознакомиться с темой, можно почитать материалы <a href="https://sre.google/books/">SRE</a> от Google, также будут полезны статьи и книги в<a href="https://martinfowler.com/"> блоге</a> Мартина Фаулера, в том числе <a href="https://martinfowler.com/microservices/">Microservices Guide</a>. Если вам нужна практика, можно попробовать пойти на тот же Udemy, где есть множество курсов по микросервисной архитектуре с хорошими рейтингами и отзывами.</p><p>И вот что важно: при проектировании и внедрении микросервисов лучше избегать «велосипедостроения». Если индустрия уже решила проблему, нет смысла изобретать новое логирование или оркестрацию. Собственное решение вряд ли будет работать лучше, а сил, времени ресурсов на него можно потратить очень много.</p><h2>Поддержка микросервисной архитектуры</h2><p>Мы каждый день используем разные приложения — например, мобильный банк. Если в магазине длинная очередь, а на кассе у вас вдруг вылетает ошибка, — это раздражает. Поэтому у бизнеса нет права на ошибку: мониторинг должен срабатывать раньше, чем клиент успеет заметить, а инциденты необходимо устранять за минуты.</p><p>В крупных организациях микросервисов могут быть сотни: например, в некоторых системах насчитывается почти 700 микросервисов на продакшене. Каждый инстанс еще масштабирован — это тысячи подов, которые постоянно обрабатывают клиентский трафик. И при этом в современных условиях нужно стремиться к доступности системы на уровне четырех девяток (99,99%), то есть к простою всего в несколько минут в год.</p><p>Если вы хотите достичь того, чтобы простой вашего приложения был минимальным, приходится продумывать много разных подходов, приемов и инструментов.</p><h3>Паттерны отказоустойчивости</h3><p>Микросервисы — это не про «разбили монолит», это про то, что сбой одного сервиса не должен валить весь продукт. Поэтому если какой-то важный сервис упал, то максимум, который нужно сделать, — чтобы клиент не увидел упавший кусочек функционала приложения.</p><p>Еще один хороший вопрос: как мониторить аварии? Необходимо очень быстро находить точку отказа. Для этого, собственно, и нужен observability-подход, трейсинг. Нужно смотреть, где какой RPS (число запросов в секунду), не произошло ли резкого скачка трафика, важно следить за latency (задержками).</p><p>Бывали случаи, когда из-за бага в мобильном приложении трафик внезапно удваивался, и системы не выдерживали такой нагрузки. Любая малейшая задержка в самом незначительном компоненте может привести к тому, что по цепочке пойдет отказ, — будут копиться потоки, соединения, и рано или поздно упадет вообще все. Чтобы подготовиться к таким ситуациям, важно изучить хотя бы <a href="https://sre.google/sre-book/monitoring-distributed-systems/">четыре «золотых сигнала» мониторинга</a> из SRE от Google.</p><p>Совет: возьмите на вооружение парадигму проектирования на отказ. Исходите из того, что в любой момент что угодно может пойти не так. Сеть будет нестабильной, железо начнет падать, интеграции станут работать неправильно. Если изначально придерживаться этого принципа, вы здорово подстрахуете себя завтрашнего. Это всегда спасает, особенно когда получаешь по наследству что-то, что не было спроектировано с учетом этого принципа.</p><p>Сейчас часто используют паттерны, которые помогают поддерживать отказоустойчивость системы:</p><ul><li><b>Circuit Breaker</b> — если сервис спамит ошибками, лучше временно прекратить попытки до него достучаться. Для клиента ничего не изменится, он как получал ошибки, так и будет получать. Но, по крайней мере, можно дать системе возможность восстановиться. А еще лучше — позволить ей переключиться на какой-то резервный канал, например сходить в кэш с неактуальными данными.</li><li><b>Rate Limiter</b> — абсолютно банальная, но необходимая вещь. Нужно ограничивать входящий поток на примерно максимальном уровне от того, который ожидается. Чтобы все не развалилось, если произойдет резкий скачок трафика.</li><li><b>Blue-Green Deployment</b> — значительно снижают на продакшене количество аварий и проблем, связанных с кривыми релизами. Можно не раскатывать новую фичу сразу на все 100 подов, а выкатить ее только на 1% трафика и проверить.</li></ul><p>И это только малая часть паттернов.</p><p>Все это must have для абсолютно любой системы. Даже если у вас низкая нагрузка, она когда-нибудь увеличится. Лучше вовремя предусмотреть это, заранее потратив чуть больше времени и реализовав эти паттерны.</p><h3>Как эффективно работать с инцидентами</h3><p>Начало всех начал в траблшутинге — мониторинг. Здорово, когда разработчики понимают, как устроена их система, и уже вложились в мониторинг: есть дашборд, где можно посмотреть по уровням абстракций основные точки отказа.</p><p>Первый уровень — это application-слой, сами сервисы, которые в подах крутятся в Kubernetes. Нужно проверить, все ли у них хорошо по точкам интеграции — нет ли тайм-аутов. Все ли в порядке у них по железу — по CPU, по памяти, по дискам.</p><p>Если на первом уровне все нормально, нужно опуститься на уровень ниже — либо на виртуалки, на которых Kubernetes развернут, либо на железки, если он развернут на Bare-metal. Недавно мы столкнулись с интересным случаем: виртуалка показывала нормальную загрузку CPU, но физический гипервизор, на котором она крутилась, был загружен на 99%. Естественно, виртуалка страдала, но уровнем выше этого не было видно.</p><p>Совет: если вы вдруг нашли что-то, что еще не мониторится, — это повод поскорее добавить эту метрику, начать ее мониторить и ретроспективно отслеживать.</p><p>Еще одна важная вещь в работе с инцидентами — культура постмортемов. Ретроспективы по каждой аварии пишутся не просто так — их можно свести по категориям и понять, из-за чего чаще всего происходят аварии: например, из-за протухших сертификатов либо человеческого фактора в конфигурации. Категорий причин отказа обычно не так много. С постмортемами проще выработать стратегию технического инженерного развития.</p><p>Вообще, человеческий фактор — это отдельная боль. Все привыкли менять что-нибудь руками: заходить в виртуалки, поправлять конфиг. Чтобы такого было как можно меньше, важно вкладываться в infrastructure as a code и даже everything as a code. В идеале следует стремиться к zero access production — нулевому доступу к продакшену — и все раскатывать через Git, через конфигурации, включая политики безопасности.</p><h2>Культура ответственности и изменение ролей в команде</h2><p>Представим, что происходит инцидент — падают 15 микросервисов. Как должна быть устроена система, которая позволит оперативно справляться с авариями?</p><p>Организационно все достаточно просто — хотя не так просто на земле, при устранении инцидента. Все сервисы должны быть каталогизированы, сгруппированы по командам или продуктовым стримам. Необходима матрица эскалации, позволяющая найти по зоне ответственности человека, которому можно позвонить и попросить подключить необходимых инженеров.</p><p>Подобную конструкцию важно поддерживать в актуальном состоянии. Это часть процесса непрерывности, и в нее надо вкладываться. В крупных компаниях этим занимаются целые отделы, в небольших организациях — отдельный человек, но такая информация всегда должна быть в общем доступе. Иначе время «отскока» после инцидента увеличится кратно.</p><p>Желательно, чтобы в компании был специальный ситуационный центр, в котором сразу можно создать конференцию, если случилась авария, и поделиться информацией, чтобы все подключились к решению проблемы.</p><p>Однако эти организационные моменты еще не гарантируют быстрого решения проблемы. Ключевой фактор — культура компании. На людей часто нападает отстраненность — авария случилась, и все думают: «Кто-нибудь другой разрулит. Я разработчик, ну, что я там сделаю?»</p><p>Многие привыкли жить по старой парадигме: написали код, потестировали, отдали поддержке и забыли. Но культура в команде должна дорасти до такого уровня, когда каждый понимает: я не только разрабатываю или тестирую код, но еще и отвечаю за него на продакшене.</p><p>Из-за этого разрыва в осознании между командами поддержки и разработки возникают конфликты. У каждой разные цели, и зачастую одна команда не понимает, чего хочет другая. Чтобы лучше понять природу этих конфликтов, важно вспомнить про DevOps-культуру и SRE. В их парадигме разработчики не только пишут код, но и деплоят в продакшен.</p><p>Проще говоря, есть два варианта взаимодействия с поддержкой: классический, когда она административно отделена, и SRE-подобный, когда сотрудники «второй линии» прямо интегрированы в команду разработки. Могу сказать, что второй эффективнее.</p><p>При этом не обязательно сливать всех в одну плоскую структуру на уровне административного деления. Достаточно, чтобы люди, даже находясь в разных административных юнитах, работали как команда и коммуницировали постоянно, а не от случая к случаю. Важно, чтобы все были проактивными — если что-то случилось, сразу подрывались и по инструкции пытались устранить проблему.</p><p>Это то самое SRE, о котором пишет Google. Но людей нужно долго обучать такой культуре — это не дело одного месяца. Благодаря такому подходу инженеры, которые раньше были просто разработчиками или аналитиками, глубже осознают свою ответственность за стабильность продакшена. И это действительно правильное направление развития. Потому что и DevOps, и SRE — это в первую очередь культура, а уже во вторую — набор инструментов.</p><h3>Будущее микросервисов: тренд на AI Ops</h3><p>Разработчики уже используют AI как copilot — и это очень мощный инструмент в умелых руках. Он не заменяет инженера, но сильно экономит ему время. Эту помощь от нейросетей очень хочется растянуть и на инфраструктуру, и на эксплуатацию, чтобы получить крутой AI Ops.</p><p>Нейросеть будет находить протухшие сертификаты внутри инфраструктуры, работать инструментом для early warning, подсвечивать риски.Кажется, что все инструменты для этого есть уже сейчас. Надо только, чтобы кто-то сложил этот пазл в рабочее решение.</p><p>Есть прототипы — например, Big Panda или Moocsoft (который был недавно куплен Dell), но пока это точечные решения. Возможно, на горизонте 5–7 лет (скорее 5, чем 10) они станут серьезной частью индустрии и очень мощным прорывом, который упростит разработчикам жизнь.Кроме того, важно, чтобы развивались и более «приземленные» технологии: инструменты контейнеризации, оркестрации, observability, а также APM — Application Performance Monitoring.</p><h3>Инженер остается в центре всего</h3><p>Никакие микросервисы, Kubernetes и AI Ops не спасут, если за системой не стоит инженер, который думает головой, правильно работает руками и отвечает за результат. Важны его навыки, кругозор и культура работы. Именно такие люди превращают набор сервисов в работающий продукт. Все остальное — только инструменты.</p><p>P. S. Если интересно, как мы решаем эти задачи на практике, <a href="https://technologichno.mave.digital/">слушайте </a>(и <a href="https://api.vc.ru/v2.8/redirect?to=https%3A%2F%2Fvkvideo.ru%2Fvideo-145457488_456239831&amp;postId=1982175">смотрите</a>) наш подкаст «Техно.Логично» — там регулярно обсуждаем самое актуальное в IT-сфере.</p>]]></content:encoded>
    </item>
    <item>
      <title>Эволюция программиста 2005–2025: от CRT-мониторов до квантовых алгоритмов</title>
      <link>https://tproger.ru/articles/evolyuciya-programmista-2005-2025--ot-crt-monitorov-do-kvantovyh-algoritmov</link>
      <comments>https://tproger.ru/articles/evolyuciya-programmista-2005-2025--ot-crt-monitorov-do-kvantovyh-algoritmov?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Денис Кудерин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/evolyuciya-programmista-2005-2025--ot-crt-monitorov-do-kvantovyh-algoritmov</guid>
      <description><![CDATA[<p>Эпохи развития программирования в России и в мире. Какие стадии прошли разработчики и к чему пришли в настоящий момент. Прогнозы на будущее. </p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/evolyuciya-programmista-2005-2025--ot-crt-monitorov-do-kvantovyh-algoritmov">Эволюция программиста 2005–2025: от CRT-мониторов до квантовых алгоритмов</a>»</p>]]></description>
      <category><![CDATA[Интернет]]></category>
      <category><![CDATA[API]]></category>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[C++]]></category>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Обучение программированию]]></category>
      <category><![CDATA[Android]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Stack Overflow]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Apple]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[C#]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Ruby]]></category>
      <category><![CDATA[MySQL]]></category>
      <category><![CDATA[Google]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[jQuery]]></category>
      <category><![CDATA[Windows]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[iOS]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Ruby on Rails]]></category>
      <category><![CDATA[HTML]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[TypeScript]]></category>
      <category><![CDATA[Node.js]]></category>
      <category><![CDATA[Навыки]]></category>
      <category><![CDATA[Rust]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[React]]></category>
      <category><![CDATA[Docker]]></category>
      <category><![CDATA[Облачные технологии]]></category>
      <category><![CDATA[macOS]]></category>
      <category><![CDATA[Intel]]></category>
      <category><![CDATA[Mozilla]]></category>
      <category><![CDATA[WebAssembly]]></category>
      <category><![CDATA[Образование]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[OpenAI]]></category>
      <category><![CDATA[Soft Skills]]></category>
      <category><![CDATA[Бэкенд]]></category>
      <category><![CDATA[Обучающие курсы]]></category>
      <category><![CDATA[Дата-центр]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Kubernetes]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Машин]]></category>
      <category><![CDATA[Vue]]></category>
      <category><![CDATA[микро]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Fullstack]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 25 Jun 2025 10:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>За последние 20 лет программирование изменилось до неузнаваемости. Если в 2005 году разработчики писали код на PHP 4.0 под мерцание CRT-экранов, то в 2025-м нейросети помогают им генерировать целые модули, а квантовые компьютеры становятся частью исследовательских проектов.</p><p>Эта статья — подробная хроника эволюции программистов: какие языки и технологии они осваивали, как менялись их рабочие места, методы обучения и даже само восприятие профессии. Мы разберем ключевые этапы, от первых веб-гигантов до эпохи совместного программирования с ИИ, и попробуем представить, что ждет нас дальше.</p><h2>2005-2009: Эпоха авторских решений и первых веб-фреймворков</h2><p>В середине 2000-х типичный рабочий инструмент программиста — это громоздкий системный блок с процессором Intel Pentium 4 или новеньким Core 2 Duo. Мониторы с ЭЛТ-трубкой постепенно уступали место LCD-экранам с разрешением 1024×768 — именно на таких дисплеях создавались первые версии Wikipedia и набирающих популярность соцсетей. Оперативная память в 1-2 ГБ считалась нормой, а жесткие диски на 80-160 ГБ часто заполнялись до отказа — проекты редко весили меньше нескольких гигабайт.</p><p>Серьезная разработка велась преимущественно на стационарных компьютерах. Ноутбуки только начинали входить в обиход — их брали в офис, но для реальной работы предпочитали мощные десктопы. Операционная система Windows XP доминировала на рабочих станциях, в то время как серверы чаще всего крутили на Linux — Red Hat Enterprise или Debian.</p><figure><img src="https://media.tproger.ru/user-uploads/113565/2025-06-13/d5fca723-5450-4b72-8e8d-4cd57627fb99.jpg" alt="" /></figure><p>Среды разработки того времени сегодня кажутся архаичными. Eclipse и NetBeans потребляли гигабайты памяти, Visual Studio 2005 требовала серьезных ресурсов. Многие разработчики предпочитали простые текстовые редакторы вроде Notepad++, а для отладки использовали примитивные методы вроде вывода значений переменных через print. Контроль версий только начинал входить в практику — Git появился в 2005 году, но большинство команд продолжали использовать SVN или вообще заливали файлы по FTP напрямую на продакшен.</p><p>Языковая экосистема этого периода вращалась вокруг трех основных технологий. PHP версий 4 и 4.3 доминировал в веб-разработке — на нем работало около 80% всех сайтов в интернете. Однако его объектно-ориентированные возможности были крайне ограничены до выхода PHP 5 в 2004 году.</p><p>Java в лице J2EE оставалась стандартом для корпоративных решений — банковских систем, крупных порталов и ERP-комплексов. Spring Framework только начинал набирать популярность, а Hibernate упрощал работу с реляционными базами данных. C++ сохранял свои позиции в разработке игр (особенно с использованием Unreal Engine), драйверов и высоконагруженных сервисов.</p><p>Фронтенд-разработка в те годы была невероятно простой по современным меркам. Верстали преимущественно таблицами, а всю динамику реализовывали через jQuery, который появился в 2006 году и быстро вытеснил нативный JavaScript из повседневной практики. AJAX-запросы казались революционной технологией, позволяющей обновлять части страницы без ее полной перезагрузки.</p><p>Обучение программированию в этот период кардинально отличалось от современных подходов. Онлайн-курсы практически отсутствовали. Основными источниками знаний служили бумажные книги:</p><ul><li>«Философия Java» Брюса Эккеля;</li><li>«Совершенный код» Стива Макконнелла;</li><li>«PHP и MySQL. Разработка веб-приложений» Люка Веллинга.</li></ul><p>Русскоязычное сообщество активно обсуждало вопросы разработки на форумах RSDN.ru и CyberForum.ru. В 2008 году появился Stack Overflow, который постепенно стал главной площадкой для профессиональных обсуждений.</p><p>Университетское образование давало хорошую теоретическую базу — алгоритмы, структуры данных, принципы ООП. Однако практическим навыкам приходилось учиться самостоятельно, методом проб и ошибок. Документацию часто скачивали в формате CHM-файлов или читали непосредственно на сайтах вроде php.net и MSDN.</p><p>Типичный стек начинающего разработчика в 2009 году:</p><ul><li>HTML/CSS с jQuery для фронтенда;</li><li>PHP или Ruby on Rails для бэкенда;</li><li>MySQL в качестве базы данных.</li></ul><p>ORM-технологии еще не получили широкого распространения, поэтому SQL-запросы писали вручную. Многие проекты представляли собой монолитные приложения, где весь код хранился в единой кодовой базе без четкого разделения на модули.</p><p><b>Показательный кейс</b>:</p><p>В 2007 году разработчик PHP-приложений из МЭСИ (Москва) столкнулся с типичной для того времени проблемой — SQL-инъекциями. Вместо стандартных решений он создал DLAC (Data Logic Access Component) — обертку для работы с базой данных, которая автоматически экранировала параметры запросов. Это выглядело революционно на фоне типичного кода того периода, где строки запросов часто собирали через конкатенацию с пользовательским вводом.</p><p>Компонент использовал новую для 2005 года технологию Generics в C#. Он генерировал параметризованные запросы, что резко снижало риски взлома.</p><p><i>Разработчики в университетской среде тогда редко задумывались о безопасности — многие проекты содержали уязвимости вроде  </i>SELECT * FROM users WHERE name = ‘.$_POST[‘name’]<i>. </i></p><p><i>DLAC стал локальным спасением для внутренних систем МЭСИ, пока в 2009 году не появился NHibernate — порт популярного Java-фреймворка Hibernate.</i></p><p>Этот кейс хорошо иллюстрирует дух эпохи: отсутствие готовых безопасных решений заставляло программистов изобретать велосипеды. Многие подобные наработки позже легли в основу ORM-библиотек, но тогда они рождались в муках — через пробелы в безопасности и километры самописного кода.</p><h2>2010-2014: Мобильная революция и рассвет JavaScript</h2><p>Начало нового десятилетия ознаменовалось стремительным ростом мобильных технологий. Выход iPhone 4 в 2010 году и Android 2.3 Gingerbread задал новые стандарты мобильной разработки.</p><figure><img src="https://media.tproger.ru/user-uploads/113565/2025-06-13/7b640694-b2cd-4f03-a68f-51ed138557b2.jpg" alt="" /></figure><p>Программисты массово переходили на MacBook Pro — не столько из-за преимуществ macOS, сколько благодаря появлению Retina-дисплеев в 2012 году, которые кардинально улучшили качество отображения кода.</p><p>Железо продолжало стремительно эволюционировать. Твердотельные накопители (SSD) начали вытеснять традиционные жесткие диски в рабочих станциях. Облачные платформы вроде AWS и Heroku стали реальной альтернативой локальным серверам, которые раньше часто стояли прямо под рабочими столами в офисах. Оперативная память в 8 ГБ стала стандартом для комфортной разработки, а четырехъядерные процессоры ускорили сборку крупных проектов.</p><p>Языковая палитра этого периода значительно расширилась. Objective-C стал основным языком для iOS-разработки и оставался таковым до появления Swift в 2014 году. Python 3 начал набирать популярность благодаря веб-фреймворку Django и научным библиотекам NumPy и Pandas, которые открыли дорогу для анализа данных в массовом сегменте.</p><p>JavaScript пережил настоящий ренессанс — после выхода AngularJS в 2010 и Node.js в 2009 году он перестал быть просто «языком для анимаций на сайте», превратившись в полноценную платформу для fullstack-разработки.</p><p><b>Важный факт</b>. В 2011 году разработчик из Сан-Франциско Райан Даль представил Node.js — среду выполнения JavaScript на стороне сервера. За первые 24 часа после релиза проект собрал 10 000 звезд на GitHub, что для того времени стало рекордом. Многие скептически относились к идее использовать JavaScript вне браузера, но уже через год такие компании как LinkedIn и Walmart перевели части своего бэкенда на Node.js, получив прирост производительности в 2-3 раза по сравнению с традиционными решениями на Java и Ruby.</p><p>Образовательная сфера претерпела значительные изменения. В 2011 году запустилась Coursera с первым массовым курсом по программированию — Machine Learning от Эндрю Ына. В 2012 году в Кремниевой долине открылся Hack Reactor, ставший прототипом современных coding bootcamps (интенсивов по программированию). Эти форматы предложили альтернативу традиционному университетскому образованию, сделав акцент на практических навыках.</p><p>Параллельно в России:</p><ul><li>В 2012 году появился Hexlet — одна из первых русскоязычных платформ с практико-ориентированными курсами по программированию. Особенность: выполнение заданий в реальной среде разработки через браузер. Платформа до сих пор работает: на текущий момент 80% выпускников трудоустраиваются в IT, <a href="https://ru.hexlet.io/blog/posts/hse-research">согласно исследованию ВШЭ</a>. В 2012 этот показатель был еще выше.</li><li>«Нетология» (основана в 2011) к 2013 году запустила курсы по веб-разработке с акцентом на JavaScript и Python, сотрудничая с российскими tech-компаниями. Их модель включала менторство и проектные работы.</li><li>В 2013 году стартовал Stepik — платформа с открытыми курсами от ведущих вузов (ИТМО, МФТИ). Особенность: интерактивные задачи с автоматической проверкой кода, что было прорывом для местного рынка.</li></ul><p>Курс «Введение в Linux» от Stepik (2014) за полгода собрал 50 тыс. студентов — рекорд для Рунета. Задания включали настройку виртуальных серверов, что сразу применялось в работе.</p><p>Эти проекты заложили основу для бума EdTech в России после 2015 года, доказав, что онлайн-формат может давать актуальные навыки быстрее вузов.</p><p>Типичный разработчик среднего уровня в 2014 году:</p><ul><li>понимал принципы REST API;</li><li>начинал осваивать основы DevOps с появлением Docker в 2013;</li><li>экспериментировал с микроконтроллерами вроде Arduino или Raspberry Pi, создавая собственные IoT-устройства.</li></ul><p>В профессиональной среде начал формироваться консенсус о том, что PHP устаревает для сложных коммерческих проектов.</p><h2>2015-2019: Эра больших данных и облачных технологий</h2><p>Аппаратные возможности сделали очередной рывок вперед. Многоядерные процессоры Intel i7 и AMD Ryzen стали стандартом для рабочих станций. 16 ГБ оперативной памяти перестали быть роскошью, а мониторы с разрешением 4К стали доступны широкому кругу разработчиков. В 2015 году появился Visual Studio Code, который быстро обогнал по популярности Sublime Text и Atom благодаря удачному сочетанию функциональности и производительности.</p><figure><img src="https://media.tproger.ru/user-uploads/113565/2025-06-13/c92b70be-b3eb-4924-a40a-587ed3d43592.png" alt="" /></figure><p>Языковая экосистема продолжила развитие. TypeScript, представленный в 2014 году, предложил решение проблемы масштабируемости JavaScript-кода в крупных проектах. Go от Google, созданный еще в 2009, нашел свою нишу в разработке микросервисов и инструментов оркестрации вроде Kubernetes (2015). Rust от Mozilla начал завоевывать доверие системных программистов благодаря уникальной системе владения памятью.</p><p>JavaScript-сообщество столкнулось с первыми серьезными проблемами. В 2016 году инцидент с пакетом left-pad показал уязвимость экосистемы npm — удаление одного небольшого модуля привело к сбоям в работе тысяч проектов по всему миру. Это заставило разработчиков задуматься о зависимости от сторонних библиотек.</p><p>Типичный senior-разработчик в 2019:</p><ul><li>разбирался в микросервисной архитектуре и понимал, как избежать vendor lock-in (привязки к поставщику) при работе с облачными провайдерами;</li><li>имел опыт работы с React или <a href="http://vue.js">Vue.js</a>;</li><li>знал, что понимание принципов работы алгоритмов становится менее важным, чем развитие soft skills для работы в команде.</li></ul><p>Ключевые технологии этого периода включали Kubernetes, который стал стандартом де-факто для оркестрации контейнеров, а также TensorFlow (2015) и PyTorch (2016), открывшие эру машинного обучения для широкого круга разработчиков. Появились первые серьезные инструменты для работы с большими данными — Apache Spark, Hadoop.</p><p><i>Ключевой момент. В 2016 году Netflix раскрыл детали своего перехода на облачную инфраструктуру AWS. Компания полностью перенесла все сервисы — от рекомендательной системы до биллинга — в облако за семь лет. Главным триггером стала катастрофа 2008 года, когда три дня простоя дата-центра оставили 8,4 млн подписчиков без доступа к сервису. Миграция потребовала перепроектирования архитектуры: инженеры разбили монолит на 500 микросервисов и внедрили Chaos Monkey — инструмент для тестирования отказоустойчивости, который случайно отключал серверы в продакшене.</i></p><p>Этот кейс стал хрестоматийным примером cloud-native подхода. Облачные технологии стали активно использоваться в разработке, а обращение с ними — обязательным навыком для прогеров.</p><h2>2020-2024: AI-assisted разработка и новые парадигмы</h2><p>Пандемия COVID-19 ускорила переход на удаленную работу. Программисты по достоинству оценили макбуки на чипах M1 (2020) за их энергоэффективность и производительность. Домашние офисы оснащались 32-дюймовыми 4К-мониторами и механическими клавиатурами, ставшими своеобразным профессиональным стандартом.</p><figure><img src="https://media.tproger.ru/user-uploads/113565/2025-06-13/65ba41e0-844c-419f-8656-e78905e93540.jpg" alt="" /></figure><p>Языковая палитра продолжала обогащаться. Rust официально вошел в ядро Linux в 2022 году, подтвердив свой статус системного языка нового поколения. Zig появился как современная альтернатива «C» с акцентом на безопасность. WebAssembly (Wasm) позволил запускать ресурсоемкие приложения прямо в браузере, открыв новые возможности для веб-разработки.</p><p>Искусственный интеллект начал проникать в повседневную работу программистов. GitHub Copilot на базе GPT-3, представленный в 2021, изменил сам процесс написания кода, предлагая контекстные подсказки. Low-code платформы вроде Retool упростили создание внутренних инструментов для бизнеса.</p><p>Типичный lead-разработчик в 2024 году:</p><ul><li>умел эффективно работать в гибридных командах (офис + удаленка);</li><li>автоматизировал рутинные задачи через ChatGPT API;</li><li>следил за развитием квантовых вычислений, хотя практическое применение пока оставалось ограниченным.</li></ul><p><i>Ключевой момент. В 2023 году GitHub Copilot, разработанный совместно с OpenAI, стал катализатором перемен в индустрии. За первый год после релиза инструмент использовали более 1,3 млн разработчиков — каждый десятый подписчик GitHub. Система анализировала контекст кода и предлагала целые функции: например, при написании SQL-запроса она автоматически генерировала соответствующую модель данных на Python. Amazon внедрил аналогичный инструмент Amazon Q Developer для внутренних команд — по заявлению CEO Энди Джесси, это сэкономило компании 4,500 человеко-лет работы и $260 млн ежегодно.</i></p><p><i>Но были и курьезы. В 2024 году разработчик из Берлина случайно отправил в продакшен код, полностью сгенерированный Copilot. Система использовала фрагмент из GPL-лицензированной библиотеки, что нарушило политику компании по открытому ПО. Инцидент заставил пересмотреть процессы ревью: теперь 78% команд требуют ручной проверки AI-кода перед мержем (слиянием).</i></p><p><i>Параллельно выяснилось, что Copilot в 40% случаев предлагает уязвимый код при работе с СУБД — это привело к взлому API стартапа через SQL-инъекцию. Такие кейсы показали, что ИИ пока не заменяет программистов, а требует от них новых навыков — критического анализа машинных предложений и понимания юридических аспектов кода.</i></p><h2>2025: Современное состояние профессии</h2><p>Современные рабочие станции программистов оснащены ноутбуками с процессорами Apple M4 (3 нм) или Windows-машинами на Snapdragon X Elite. Мониторы с разрешением 8К используются для разработки AR-приложений, а OLED-экраны с HDR стали стандартом для работы с графикой. Появляются первые экспериментальные IDE с нейроинтерфейсами, способные предсказывать код на основе анализа мозговой активности.</p><p>Среди языков программирования выделяется Mojo (2023) — «Python для GPU», набирающий популярность в сфере машинного обучения. Carbon как потенциальный наследник C++ пока остается в тени Rust. Квантовые языки вроде Q# и Cirq интересуют в основном энтузиастов и исследователей.</p><p>Профессия претерпела значительные изменения. ИИ стал не конкурентом, а помощником — по некоторым оценкам, около 60% рутинного кода в 2025 году (тесты, документация) генерируется автоматически. Знание английского языка стало важнее знания сложных алгоритмов — без него невозможно эффективно работать с современными AI-инструментами. Понятие «fullstack-разработчик» трансформировалось — теперь оно подразумевает владение фронтендом, одним бэкенд-языком и основами машинного обучения.</p><p>За два десятилетия программисты прошли путь от одиночек за CRT-мониторами до участников глобальных распределенных команд. Если в 2005 ключевым навыком было умение написать работающий код, то в 2025 главное — способность эффективно взаимодействовать с ИИ-ассистентами. Однако основы профессии остались неизменными — логическое мышление, способность к абстракции и желание автоматизировать рутинные задачи.</p><p>Будущее обещает новые трансформации. К 2030 году нейроинтерфейсы смогут заменить традиционные устройства ввода, а квантовые компьютеры — перевернуть основы криптографии. Но пока актуальными остаются проверенные временем принципы: изучать перспективные технологии (вроде Rust и Mojo), осваивать работу с ИИ и, конечно, совершенствовать главный навык любого программиста — умение быстро и грамотно гуглить.</p><p>Ты уже программист, если читаешь это! Больше о кодинге <a href="https://t.me/+ezugB7gnIEsxNGMy">тут</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Каждый седьмой коммит российских Python-разработчиков авторства ИИ</title>
      <link>https://tproger.ru/news/kazhdyj-sedmoj-kommit-rossijskih-python-razrabotchikov-avtorstva-ii</link>
      <comments>https://tproger.ru/news/kazhdyj-sedmoj-kommit-rossijskih-python-razrabotchikov-avtorstva-ii?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/kazhdyj-sedmoj-kommit-rossijskih-python-razrabotchikov-avtorstva-ii</guid>
      <description><![CDATA[<p>Каждый седьмой коммит российских Python-разработчиков создаётся ИИ — исследование GitHub показало 15,4% сгенерированных функций в 2024 году</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/kazhdyj-sedmoj-kommit-rossijskih-python-razrabotchikov-avtorstva-ii">Каждый седьмой коммит российских Python-разработчиков авторства ИИ</a>»</p>]]></description>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 24 Jun 2025 10:54:31 GMT</pubDate>
      <content:encoded><![CDATA[<p>ИИ уже уверенно закрепился в рутине программистов. По данным масштабного исследования, к концу 2024 года около <b>15,4% всех функций в коммитах российских Python-разработчиков были сгенерированы нейросетями</b>. Это примерно каждый седьмой коммит.</p><p>Исследование охватило <b>80 млн коммитов</b> на GitHub, проанализированных с помощью обученного классификатора на основе GraphCodeBERT. Он распознает, сгенерирована ли функция ИИ. В выборку попали 200 000 разработчиков из шести стран.</p><p><b>Для сравнения</b>, в других странах картина выглядит так:</p><ul><li>США — 30,1%</li><li>Германия — 24,3%</li><li>Франция — 23,2%</li><li>Индия — 21,6%</li><li>Китай — 11,7%</li></ul><p>Разработчики с меньшим стажем используют ИИ чаще: новички в среднем генерируют с помощью ИИ <b>41% кода</b>, тогда как ветераны — около <b>28%</b>.</p><p>Интересно, что <b>разницы между мужчинами и женщинами не обнаружено</b> — обе группы используют ИИ с одинаковой активностью.</p><h2>Что это дает</h2><p>Авторы также выяснили, что интенсивное использование ИИ увеличивает продуктивность: <b>переход на 30% сгенерированного ИИ кода увеличивает число коммитов на 2,4%</b>.</p><p>Кроме того, возрастает и исследовательская активность: разработчики начинают чаще использовать новые библиотеки и их комбинации — как ранее не использовавшиеся лично, так и вообще новые для экосистемы.</p><h2>Что дальше</h2><p>По оценкам авторов, уже сейчас ИИ приносит <b>до $14,4 млрд</b> ежегодной добавленной стоимости только в американской индустрии разработки софта.</p><p>А если экстраполировать более оптимистичные результаты из контролируемых экспериментов, цифра может достигать и <b>$96 млрд</b> в год.</p><p>Полный отчет доступен<a href="https://arxiv.org/abs/2506.08945"> на arXiv</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как защитить pet-проект почти бесплатно, но эффективно</title>
      <link>https://tproger.ru/articles/kak-zashhitit-pet-proekt-pochti-besplatno--no-effektivno</link>
      <comments>https://tproger.ru/articles/kak-zashhitit-pet-proekt-pochti-besplatno--no-effektivno?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Светлана Гринь]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-zashhitit-pet-proekt-pochti-besplatno--no-effektivno</guid>
      <description><![CDATA[<p>Как эффективно защитить pet-проект: управление секретами, логирование, бэкапы, локальные туннели и другие базовые правила безопасности
</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-zashhitit-pet-proekt-pochti-besplatno--no-effektivno">Как защитить pet-проект почти бесплатно, но эффективно</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[Slack]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Навыки]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[ICO]]></category>
      <category><![CDATA[Pet-проекты]]></category>
      <category><![CDATA[Мессенджер]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Взлом]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[1C]]></category>
      <category><![CDATA[Grafana]]></category>
      <category><![CDATA[CI/CD]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 17 Jun 2025 10:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Pet-проекты помогают развивать профессиональные навыки и воплощать собственные идеи, но не стоит забывать об их информационной безопасности. Делать сервис и не думать об инфобезе — всё равно что строить дом без фундамента: выглядит добротно, но всё может рухнуть в самый неожиданный момент. Разберём, как недорого и эффективно защитить проект.</p><h2>Что такое pet-проект и зачем его защищать</h2><p><b>Pet-проект</b> (от английского pet — «домашний питомец») — тренировочный проект, который разработчик создаёт в свободное время по собственному желанию. Обычно их делают, чтобы освоить новую технологию, пополнить портфолио или поучаствовать в хакатонах.</p><p>Такие проекты часто воспринимают как что-то «несерьёзное», но пренебрежение информационной безопасностью может привести к неприятным последствиям. Злоумышленники используют уязвимости pet-проектов для получения доступа к ресурсам разработчика, кражи данных и будущих атак на более крупные цели.</p><p>Кроме того, защита pet-проекта — важный навык, который высоко ценится работодателями.</p><p>Рассмотрим основные правила кибербезопасности, которые нужно учитывать при работе над pet-проектом.</p><h2>Безопасное управление секретами</h2><p><b>Секреты</b> — это чувствительные данные, такие как пароли, токены доступа, ключи API, SSH-ключи, сертификаты и другие данные, которые обеспечивают аутентификацию и шифрование. Если добавить секреты в код, злоумышленники могут получить полный контроль над вашей инфраструктурой.</p><h3>Какие правила нужно соблюдать</h3><ul><li>Не храните секреты в коде. Храните секреты в отдельных файлах env. и добавьте эти файлы в .gitignore, чтобы они не попадали в репозиторий.</li><li>Придерживайтесь принципа минимальных привилегий. Каждый сервис должен иметь только те права, которые необходимы для выполнения своих задач.</li><li>Регулярно обновляйте секреты. Меняйте токены и пароли периодически, особенно после обнаружения утечек или изменений в проекте.</li><li>Используйте менеджеры секретов. Популярные сервисы: Doppler, HashiCorp Vault, AWS Secrets Manager, 1Password Developer Tools.</li><li>Мониторьте утечки. Можно использовать такие инструменты, как GitGuardian, TruffleHog, Gitleaks.</li><li>Шифруйте секреты. Используйте библиотеки типа cryptography в Python и подключайте шифрование на уровне операционной системы.</li></ul><h2>Безопасность CI/CD</h2><p><b>Пайплайн CI/CD</b> (Continuous Integration / Continuous Delivery) — автоматизированный процесс сборки, тестирования и развёртывания приложений. Он помогает автоматически интегрировать код и деплоить его на различные среды.</p><p>Если злоумышленник получит доступ к пайплайну, он может внедрить вредоносный код в ваше приложение, остановить весь процесс разработки или развёртывания, украсть данные пользователей и т.д.</p><h3>Способы защиты пайплайна</h3><ul><li>Моделируйте угрозы. Оцените, какие угрозы наиболее вероятны на каждом этапе пайплайна: от коммита кода до деплоя на сервер.</li><li>Проверяйте зафиксированный код. Используйте статический анализ кода для автоматического поиска уязвимостей.</li><li>Защитите Git-репозитории. Настройте двухфакторную аутентификацию (2FA), ограничьте доступ к репозиториям, используйте обязательную проверку пул-реквестов двумя разработчиками.</li><li>Изолируйте пайплайн. Не запускайте его на том же сервере, где крутится ваше продакшн-приложение.</li></ul><p>Дополнительно стоит шифровать секреты в пайплайне и минимизировать их передачу между этапами сборки.</p><h2>Сервисы мониторинга и логирования</h2><p><b>Логирование</b> — запись событий, ошибок и других данных о работе приложения в специальные файлы или базы данных. По сути, это дневник.</p><p><b>Мониторинг</b> — наблюдение за состоянием приложения, инфраструктуры или сервисов в реальном времени для своевременного выявления падения сервера, роста ошибок и других проблем.</p><p>Анализ логов помогает выявлять баги, попытки несанкционированного доступа, долгие запросы, ошибки базы данных. Мониторинг позволяет мгновенно реагировать на сбои, а также с его помощью вы узнаете, хватает ли приложению серверных мощностей.</p><h3>Примеры популярных сервисов</h3><p><a href="https://logtail.ru/">Logtail </a>— простой инструмент для сбора и анализа логов, есть бесплатный тариф.</p><p><a href="https://github.com/paper-trail-gem/paper_trail">Papertrail</a> — удобный сервис для быстрого поиска по логам, бесплатный план для небольших проектов (10 Мб в день).</p><p><a href="https://docs.sentry.io/">Sentry</a> —  хорош для отслеживания ошибок в приложениях на клиентской стороне и сервере.</p><p><a href="https://betterstack.com/">BetterStack</a> — мониторинг доступности сайтов и серверов с бесплатными уведомлениями об инцидентах по почте, через SMS и Slack.</p><p><a href="https://grafana.com/pricing/">Grafana Cloud Free</a> — мониторинг с красивыми дашбордами, бесплатный лимит ресурсов до 10 тыс. серий данных, 50 ГБ трафика.</p><p><a href="https://prometheus.io/">Prometheus</a> и <a href="https://grafana.com/">Grafana</a> — Prometheus собирает метрики, Grafana их визуализирует.</p><p><a href="https://uptimerobot.com/">UptimeRobot</a> — проверка доступности вашего проекта каждые 5 минут, бесплатный тариф на 50 мониторингов.</p><h2>Бэкап и восстановление данных</h2><p><b>Бэкап</b> — это создание резервной копии данных, которую можно использовать для восстановления в случае утраты или повреждения оригиналов. Может показаться, что для pet-проекта это излишне, однако от случайных удалений данных, взломов серверов, утечек данных никто не застрахован. А ещё можно откатиться к рабочей версии, если будут ошибки в коде и деплойменте.</p><h3>Как сделать бэкап пошагово</h3><ol><li>Определите данные, которые необходимо бэкапить: какие данные критически важны, какие можно восстановить вручную.</li><li>Выберите место хранения: облачные сервисы, собственные серверы, внешние носители, Git-репозиторий.</li><li>Выберите тип бэкапа: при полном копируются все данные целиком, при инкрементном — изменения с момента последнего копирования, при дифференциальном — изменения с момента последнего полного бэкапа.</li><li>Настройте автоматизацию, чтобы не забывать делать бэкапы вручную. Можно использовать скрипты, планировщики задач или бэкап-сервисы.</li><li>Проверьте бэкап. Проведите тестовое восстановление.</li><li>Определите частоту бэкапа. Например, можно проводить полный бэкап раз в неделю и инкрементные бэкапы каждый день.</li><li>Защитите чувствительные данные.</li></ol><h2>Локальные туннели</h2><p>При разработке pet-проекта может возникнуть необходимость показать результат внешнему миру. Кроме того, многие внешние сервисы, такие как платёжные системы и мессенджеры, тоже требуют «боевые» URL для отправки запросов. Однако открывать порты на своём устройстве напрямую небезопасно. Локальные туннели создают временный внешний URL-адрес без развертывания на реальном сервере.</p><p>Когда вы запускаете туннель через специальный инструмент, он:</p><ul><li>устанавливает зашифрованное соединение между вашим компьютером и своим публичным сервером;</li><li>создаёт внешний адрес;</li><li>пересылает все запросы, которые приходят на этот адрес, вашему локальному приложению.</li></ul><p>Трафик при этом шифруется и проходит через защищённый канал.</p><h3>Примеры инструментов</h3><p><a href="https://ngrok.com/?ref=gobigger">Ngrok </a>— самый известный инструмент для быстрого создания туннелей. Есть бесплатный тариф.</p><p>Порты от<b> VSCode</b> — отличное решение для пользователей Visual Studio Code, удобно для быстрой демонстрации.</p><p><a href="https://dev.vk.com/ru/libraries/tunnel">VK Tunnel</a> — российская альтернатива, подходит для работы через VK Cloud.</p><p><b>Tuna</b> и <a href="https://xtunnel.ru/">xTunnel </a>— простые в использовании решения, есть бесплатные тарифы.</p><h2>Чек-лист по инфобезу для тех, кто делает pet-проект</h2><ol><li>Регулярно обновляйте зависимости. Используйте автоматические инструменты, например, Dependabot или npm audit.</li><li>Настройте базовые HTTP-заголовки безопасности. Добавьте заголовки Content-Security-Policy, X-Frame-Options, Strict-Transport-Security, чтобы минимизировать риск XSS, Clickjacking и других атак.</li><li>Используйте бесплатные SSL-сертификаты. Подключите HTTPS через бесплатные сервисы, например, Let's Encrypt.</li><li>Очищайте и валидируйте ввод данных. Фильтрация и валидация данных защитит от SQL-инъекций и XSS.</li><li>Создайте отдельные учётные записи для разных сервисов. Не используйте одну и ту же учётную запись везде.</li><li>Минимизируйте доступы к базе данных. Если сервису нужно только читать, не давайте права на запись или удаление.</li><li>Используйте бесплатные инструменты для сканирования уязвимостей. Проверьте код через такие сканеры, как SonarQube Community Edition, Snyk, OWASP ZAP.</li><li>Делайте резервные копии. Настройте автоматические бэкапы базы данных и важных файлов.</li><li>Не храните секреты в коде. Используйте .env файлы и убедитесь, что они добавлены в .gitignore.</li><li>Включите двухфакторную аутентификацию (2FA). На всех сервисах, где это возможно, включите 2FA для дополнительной защиты.<br /></li></ol><p>А больше про разработку и все, что с ней связано, в нашем<a href="https://t.me/tproger_web"> тг-канале</a>!</p>]]></content:encoded>
    </item>
    <item>
      <title>Как встроить распознавание документов в Android: пошаговое руководство</title>
      <link>https://tproger.ru/articles/kak-vstroit-raspoznavanie-dokumentov-v-android--powagovoe-rukovodstvo</link>
      <comments>https://tproger.ru/articles/kak-vstroit-raspoznavanie-dokumentov-v-android--powagovoe-rukovodstvo?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Smart Engines]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-vstroit-raspoznavanie-dokumentov-v-android--powagovoe-rukovodstvo</guid>
      <description><![CDATA[<p>Разбираемся, как быстро добавить возможность распознавания документов в Android. Пошаговое руководство по встраиванию Smart Document Engine.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-vstroit-raspoznavanie-dokumentov-v-android--powagovoe-rukovodstvo">Как встроить распознавание документов в Android: пошаговое руководство</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[SEO]]></category>
      <category><![CDATA[Android]]></category>
      <category><![CDATA[Опрос]]></category>
      <category><![CDATA[JSON]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[Распознавание]]></category>
      <category><![CDATA[CSS]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Tor]]></category>
      <category><![CDATA[HTML]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[BASIC]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[Intel]]></category>
      <category><![CDATA[ICO]]></category>
      <category><![CDATA[Стартапы]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[XML]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 10 Jun 2025 14:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Привет, Tproger!</p><p>Мы в <a href="https://smartengines.ru/">Smart Engines</a> занимаемся разработкой софта для распознавания самых разных документов — начиная от паспорта РФ, свидетельства о рождении и заканчивая первичкой вроде УПД или ТОРГ-12, а также банковских карт, номеров телефона и баркодов. Наши библиотеки написаны полностью с нуля (на плюсах), мы уделяем огромное внимание скорости алгоритмов, нейросетям (новым архитектурам, размеру и правильному применению) и оптимизации, за счет чего наш софт портируется на любые архитектуры и может быть использован на любой платформе.</p><p>Сегодня продолжим знакомиться через рассказ о нашем софте, на очереди вторая библиотека — Smart Document Engine и ее возможности работы с жесткими и гибкими формами.</p><h2>Гибкие и жесткие формы</h2><p>Вначале про сами формы: они могут быть «жесткими» и «гибкими». Жёсткие формы подразумевают, что положение всех объектов на форме может быть задано прямо в виде координат на шаблоне. Самое простое определение для жестких форм — они совпадают «на просвет». Возьмите пару листов А4 с распечатанной жёсткой формой, наложите друг на друга, и места расположения полей точно совпадут. Гибкие формы устроены гораздо сложнее, но все равно имеют свою характерную структуру и топологию.</p><p>Распознавание жестких форм можно свести к детекции формы на изображении и распознавании определенных областей, где должны быть искомые поля. Гибкие формы требуют гораздо более сложных систем поиска (к тому же, завязанных на результате предыдущих действий, например, OCR, что только увеличивает возможность ошибки).</p><p>Кстати, иногда вместо распознавания текста целиком достаточно просто ответить на вопрос «есть ли текст в выбранной области, и, если есть, то где»</p><p>Но не надо думать, что жёсткие формы совсем просты — большие белые поля без каких-либо символов (или одинаковый узор по краям, как это бывает с бланками гособразца), малый объём статического текста и некоторая вариативность бланков тоже заставляют потрудиться над детекцией и классификацией шаблонов.</p><p>Также существуют общие для подобных форм проблемы. Правильно интерпретировать галочки в чекбоксах, найти штрихкоды, правильно разметить табличные данные — есть куча проблем, каждая из которых имеет своё state-of-the-art решение и набор алгоритмов, над которыми нужно ломать голову.</p><h2>Почему не LLM, хотя казалось бы</h2><p>Сейчас мы переживаем бум развития нейросетей — генеративные и классифицирующие сети появляются как грибы после дождя. Количество задач, которые они могут решить, тоже кажется неисчислимым: казалось бы — дайте обучающую выборку побольше, и всё получится! Тем более, что примеры использования нейросетей для автоматизации рутины уже можно встретить на каждом шагу: об этом пишут заметки и обзорные статьи на научно-популярных ресурсах, а интеграторы и стартапы предлагают решения по созданию чат-ботов и помощников на основе ИИ, обученного на внутренней документации больших компаний.</p><p>Однако чем сложнее нейросеть, чем глубже степень обучения — тем выше шанс, что она начнёт бредить. Мы все какое-то время назад <a href="https://shedevrum.ai/post/bc5bf060107711eeb9ea06d64eab8f23/">смеялись</a> над шести-семипалыми героями очередных сгенерированных изображений, сейчас посмеиваемся над сгенерированными сетями текстами с описанием несуществующих фильмов и книг, но смешно ли будет нам (а особенно бухгалтерии), если нейросеть начнет галлюцинировать при распознавании платёжных реквизитов или суммы НДС? И чем выше степень развития сетей — тем менее заметными будут становиться такие ошибки.</p><p>В прошлом году на одной из ключевых конференций в области анализа и распознавания документов — ICDAR — учёные традиционно задались вопросом о будущем OCR. И сошлись во мнении, что OCR нисколько не устарела, благополучно развивается и остается наиболее надежным инструментом распознавания. Обеспечить требования консистентности (и ещё всякого такого) информации, извлекаемой из изображения, все равно сможет только старый добрый OCR и прочие детерминированные алгоритмы. И именно их разработкой (и доведением до совершенства) мы и занимаемся.</p><p>Вернёмся к библиотеке <a href="https://smartengines.ru/intelligent-document-recognition/">Smart Document Engine</a>. Как уже говорилось выше, гибкие формы на то и гибкие, что исключительно геометрией на них не обойдёшься — вопрос местонахождения полей решается «на лету». На процесс взаимодействия с библиотекой это влияет в самом конце, на моменте работы с результатом. Перейдем к знакомству с интерфейсом на примере всё того же встраивания в андроид.</p><h2>Встраивание</h2><p>В целом, сценарий работы с библиотекой распознавания документов такой же, как и в <a href="https://tproger.ru/articles/kak-vstroit-raspoznavanie-pasporta-rf-v-android--powagovoe-rukovodstvo">прошлой статье</a> про распознавание паспорта: создаём движок, формируем настройки сессии, заводим саму сессию и кормим её картинками, после чего работаем с результатом распознавания. В отличие от документов, удостоверяющих личность, гибкие и жесткие формы могут быть многостраничными, с одинаковыми «по смыслу» полями на каждой странице. Помимо этого, часто документы загружают «пакетом», и в этом случае на одном изображении могут быть несколько разных документов. Поэтому результат распознавания устроен сложнее, чем в прошлом примере. Есть «результат распознавания», внутри него лежит набор найденных документов, каждый документ разбивается на «логический» и «физический» набор полей:</p><p>Логическая и физическая части документа разбираются отдельно, так как в некоторых случаях геометрия вообще не нужна (если результат распознавания документа дальше идёт в базу данных):</p><p>Как правило, результат распознавания представляют в виде json-объекта, но для наглядности лучше всего пользоваться html — особенно в случае, когда логические и физические поля имеют больше одного соответствия. Вот простенький генератор html на основе документа:</p><p>В результате получается удобная для взаимодействия html-страничка. Если добавить немного фантазии, то можно сразу сделать форму, в которой можно будет проверять и дополнять неуверенно распознанные поля — очень удобно в случае, если качество изображения плохое или документ плохо пропечатан.</p><p>Конечно, помимо андроида встроить распознавание и организовать удобные представление документа (при необходимости) можно и на любой другой платформе, однако с трендом на создание банковских офисов нового поколения и развития курьерской сети автоматизация ввода документов с помощью средненьких мобильных устройств на Андроиде становятся актуальной задачей.</p><p>На этом мы не заканчиваем, ждите новых статей!</p>]]></content:encoded>
    </item>
    <item>
      <title>Как встроить распознавание паспорта РФ в Android: пошаговое руководство</title>
      <link>https://tproger.ru/articles/kak-vstroit-raspoznavanie-pasporta-rf-v-android--powagovoe-rukovodstvo</link>
      <comments>https://tproger.ru/articles/kak-vstroit-raspoznavanie-pasporta-rf-v-android--powagovoe-rukovodstvo?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Smart Engines]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-vstroit-raspoznavanie-pasporta-rf-v-android--powagovoe-rukovodstvo</guid>
      <description><![CDATA[<p>Пошагово объясняем, как встроить быстрое и безопасное распознавание паспорта РФ в Android. Нативное приложение с возможностью распознавания ДУЛ на устройстве.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-vstroit-raspoznavanie-pasporta-rf-v-android--powagovoe-rukovodstvo">Как встроить распознавание паспорта РФ в Android: пошаговое руководство</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Android]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[Распознавание]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[Kotlin]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 30 May 2025 14:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Привет, Tproger!</p><p>Мы в <a href="https://smartengines.ru/">Smart Engines</a> занимаемся разработкой софта для распознавания самых разных документов – начиная от паспорта РФ, свидетельства о рождении и заканчивая первичкой вроде УПД или ТОРГ-12, а также банковских карт, номеров телефона и баркодов.</p><p>Наши библиотеки написаны полностью с нуля (на плюсах), мы уделяем огромное внимание скорости алгоритмов, нейросетям (новым архитектурам, размеру и правильному применению) и оптимизации, за счет чего наш софт портируется на любые архитектуры и может быть использован на любой платформе.</p><p>Объяснять (и хвастаться) проще всего на примере – покажем, как развернуть распознавание паспорта РФ прямо на устройстве на Android.</p><h2>Зачем это всё?</h2><p>Кстати, <b>распознавание паспорта РФ на мобильном телефоне</b> – ключевой элемент процесса удостоверения личности в цифровых каналах. Функциональность дает возможность удаленно открывать счета в банковских приложениях, регистрироваться в шеринговых сервисах, покупать билеты на самолеты и поезда и многое другое.</p><p>Кроме того, распознавание на мобильнике открывает возможность к ещё одной функциональности — <b>распознаванию в видеопотоке</b>. При таком сценарии пользователь наводит камеру на документ, а система анализирует входящие кадры до тех пор, пока не будет обеспечено достаточное для распознавания документа качества. Таким образом клиенту не нужно несколько раз переснимать документ, если вдруг кадр не удался — получился размазанным, засвеченным и так далее.</p><h2>Немного вводных</h2><p>SDK <a href="https://smartengines.ru/smart-idreader/">Smart ID Engine</a> – это библиотека, собранная под нативную платформу, конфигурационный бандл и обёртка для вызова функций библиотеки с помощью других языков программирования (в этой статье нам понадобится java).</p><p>Сперва коротко об <b>интерфейсе библиотеки</b>, без этого мы не сможем написать адекватное работающее приложение. Система распознавания включает:</p><ul><li><b>Движок распознавания.</b>  Он создаётся с указанием конфигурационного бандла и представляет собой что-то вроде “склада инструментов” для распознавания различных документов. Движок создаётся в самом начале, существует на всём протяжении жизни (приложения или хотя бы сценария, в котором используется распознавание). От него создаются следующие элементы интерфейса:</li></ul><ul><li><b>Сессия распознавания</b>. Это сам процесс распознавания конкретного физического объекта – паспорта, ВУ, СТС, загранпаспорта и других. Всего по состоянию на сегодняшний день мы поддерживаем более 3 тысяч типов документов.  В сессию можно передать всего одно изображение, а можно - серию изображений последовательно (видеопоток), при этом после каждого нового распознавания результат будет уточняться, а так же на основе уверенности в результате будет приниматься решение, нужно ли распознавать дальше или лучше уже не будет.</li></ul><p><i>Важная оговорка: Вообще сессии бывают разных типов - помимо распознавания документов также существуют сессия сравнения лиц (сравнить два изображения на степень “похожести” или провести проверку определения живости лица. Кстати, это происходит без выявления биометрических дескрипторов). А также сессия файловой форензики (поиск признаков вмешательства в исходное изображение) и другие.</i></p><ul><li><b>Настройки сессии.</b> Они хранят список доступных для распознавания типов документов (сам по себе этот список определяется конфигурационным бандлом), дополнительную информацию о каждом документе, а также позволяют настроить процесс распознавания: задать список ожидаемых типов документов для сессии распознавания (кстати, если поставить *, то система сама определит тип документа из всех преднастроенных шаблонов), включить\выключить проверки признаков подлинности, задать таймаут для сессии распознавания и так далее. Настройки создаются перед созданием самой сессии и не могут редактироваться в процессе распознавания.</li></ul><ul><li><b>Результат распознавания. </b>Это объект, в котором хранится множество различной информации: координаты шаблонов документов (допустим, вторая и третья страницы паспорта ищутся отдельно) и всех полей на этих шаблонах, текстовые поля (вплоть до разбиения на варианты каждого символа с их весами), поля с изображениями, поля с проверками признаков подлинности документа. Как этим всем богатством пользоваться, расскажем чуть ниже.</li></ul><p>Беглого взгляда на этот интерфейс достаточно, чтобы понять, как его правильно встроить в приложение. При старте приложения (или сценария) создаем экземпляр движка, перед непосредственно распознаванием создаем настройки сессии и заполняем их, после чего при переходе на экран с превью камеры создаем саму сессию распознавания и “кормим” её кадрами до тех пор, пока сессия не затерминалится (= не решит, что “ей хватит”). После чего можно переходить к разбору результата распознавания.</p><h2>Как это встраивается и работает</h2><p>А теперь немного кода - покажем, как делается распознавание документа с помощью камеры устройства на Android. Полный код можно найти, перейдя по <a href="https://github.com/SmartEngines/Smart-ID-Engine-SDK/tree/main/Smart-ID-Engine-2.5.0-Full-bundle_idengine-Android">ссылке</a> на GitHub, а ниже – наиболее интересные моменты.</p><p>Начнём с создания движка:</p><p>Объявим класс:</p><p>И приведём его имплементацию:</p><p>Теперь нам нужно создать и подготовить настройки сессии, чтобы библиотека знала, какие именно инструменты использовать при распознавании:</p><p>С имплементацией:</p><p>Дальше, наконец, само распознавание. Поскольку для распознавания нужно откуда-то брать кадры (мы всё же не волшебники), логично завести контроллер, который будет хранить сессию, иметь доступ к камере и кормить сессию кадрами, пока та не попросит остановиться. Реализуем свой ImageProcessor, который будет кормить кадры из превью сессии распознавания:</p><p>Когда в процессе распознавания достигается терминальность, можно переходить к разбору результата распознавания. Результат распознавания хранит в себе множество информации - помимо собственно текстовых полей и фото владельца, там лежит геометрия (координаты документа на изображении), данные проверок признаков подлинности и различные атрибуты.</p><p>Теперь вы знаете, что встроить распознавание паспорта РФ в приложение для Android — намного проще, чем может показаться на первый взгляд.</p><p>Это далеко не единственный вариант использования нашего софта. Как минимум, помимо распознавания документов также можно сверять лица, проверять лицо на “живость”, организовывать распознавание двусторонних документов и еще много чего.</p><p>Но схема работы останется той же: движок – настройки сессии – сессия – разбор результата. Такая схема позволяет как сделать сервер с распознаванием тысяч документов одновременно, так и встроить распознавание хоть в браузер.</p><p>Если заинтересовались – добро пожаловать на <a href="https://smartengines.ru">наш сайт</a>. И не расходимся, скоро расскажем еще много чего интересного!</p>]]></content:encoded>
    </item>
    <item>
      <title>Защита API-ключей: как избежать утечек</title>
      <link>https://tproger.ru/articles/zashhita-api-klyuchej--kak-izbezhat-utechek</link>
      <comments>https://tproger.ru/articles/zashhita-api-klyuchej--kak-izbezhat-utechek?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Денис Кудерин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/zashhita-api-klyuchej--kak-izbezhat-utechek</guid>
      <description><![CDATA[<p>Защита API-ключей. Показываем, как избежать утечек в API. Рассматриваем пошаговую инструкцию и инструменты ✔ Tproger</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/zashhita-api-klyuchej--kak-izbezhat-utechek">Защита API-ключей: как избежать утечек</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Лучшая практика]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Практика]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[Microsoft]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Яндекс]]></category>
      <category><![CDATA[Cloudflare]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[Уязвимость]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Vue]]></category>
      <category><![CDATA[CI/CD]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 27 May 2025 10:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>API-ключи стали цифровыми пропусками в современную веб-инфраструктуру. Они открывают доступ к данным, сервисам и функционалу, но их утечка превращает этот удобный механизм в угрозу безопасности.</p><p>Техническая уязвимость идентификаторов — не единственная проблема. Защита API-ключей требует комплексного подхода, сочетающего технические решения и организационные меры. Практика показывает, что большинство утечек происходит не из-за направленных атак, а по причине пренебрежения базовыми принципами безопасности.</p><p>Поэтому важно не просто правильно хранить ключи, но и контролировать их использование, своевременно обновлять и ограничивать область действия. Понимание этих рисков — первый шаг к созданию надежной защиты API для ваших интерфейсов и данных.</p><p>В этой статье разберем основные причины утечек, а также практические методы защиты API-ключей, которые помогут избежать распространенных ошибок и минимизировать риски.</p><h2>Основные причины утечек</h2><p>API-ключи обеспечивают доступ к критически важным системам — от платежных шлюзов до облачных хранилищ данных. Их компрометация может привести к катастрофическим последствиям — утечке конфиденциальных данных, финансовым потерям и даже к полному захвату контроля над системой.</p><p>Разберем основные причины утечек.</p><h3>Хардкодинг ключей в исходном коде</h3><p>Пожалуй, самая распространенная и опасная практика — прямое внедрение API-ключей в исходный код приложения. Разработчики часто делают это для удобства тестирования, забывая удалить секретные данные перед релизом.</p><p>Особенно критично, когда ключи остаются:</p><ul><li>в конфигурационных файлах (config.php, .env);</li><li>в закомментированных блоках кода;</li><li>в тестовых сборках, которые по ошибке попадают в продакшен;</li><li>в шаблонах и примерах кода.</li></ul><p>Яркий пример — <a href="https://xakep.ru/2023/09/07/microsoft-post-mortem/">инцидент с Microsoft в 2023</a> году, когда утечка ключа MSA (Microsoft Account) через устаревший код позволила хакерам получить доступ к почтовым ящикам правительственных организаций США, включая Министерство торговли. Как показало расследование Microsoft Security Response Center, проблема возникла из-за ключа подписи, который продолжал использоваться в legacy-системах и попал в руки злоумышленников.</p><p>Главная опасность хардкодинга в том, что даже после удаления ключа из актуальной версии кода он может сохраняться в истории версий или бинарных файлах. Современные сканеры секретов легко находят такие уязвимости, что делает подобную практику особенно рискованной.</p><h3>Случайные коммиты в публичные репозитории</h3><p>Системы контроля версий типа Git хранят полную историю изменений, что создает дополнительные риски. Даже если ключ удален из текущей версии кода, он может остаться в истории коммитов.</p><p>Типичные сценарии:</p><ul><li>временное добавление ключа для отладки с последующим «удалением»;</li><li>позднее добавление .env-файла в .gitignore;</li><li>слияние веток с чувствительными данными;</li><li>автоматические коммиты IDE и инструментов разработки.</li></ul><p>В публичные репозитории GitHub ежедневно попадают сотни активных ключей — некоторые из них даже предоставляют доступ к платежным системам и базам данных.</p><h3>Ошибки в настройке CI/CD</h3><p>Автоматизированные системы сборки и деплоя могут невольно способствовать утечкам:</p><ul><li>передача ключей через аргументы командной строки;</li><li>попадание секретов в логи сборки;</li><li>неправильная настройка переменных окружения;</li><li>хранение ключей в незащищенных артефактах;</li><li>избыточные права доступа для CI-сервисов</li></ul><p>Особенно опасны ситуации, когда CI-пайплайн настроен на публикацию артефактов сборки, включающих конфигурационные файлы с ключами.</p><h3>Логирование чувствительных данных</h3><p>Разработчики часто добавляют отладочный вывод, который затем забывают удалить:</p><ul><li>console.log (“API Key: “, secretKey);</li><li>погирование полных HTTP-запросов с заголовками авторизации;</li><li>дампы ошибок с конфиденциальными данными;</li><li>журналирование параметров запросов.</li></ul><p>Такие записи могут попасть в системные логи, инструменты мониторинга (Kibana, Grafana), браузерную консоль (для фронтенд-приложений) и облачные сервисы хранения логов.</p><p>Проблема усугубляется тем, что многие фреймворки по умолчанию включают подробное логирование, а разработчики не всегда задумываются о последствиях. В корпоративных системах это может привести к накоплению секретов в централизованных системах мониторинга, доступ к которым имеют десятки сотрудников.</p><h2>Неправильное управление доступами</h2><p>Часто проблема кроется не в технических решениях, а в процессах управления:</p><ul><li>отсутствие ротации ключей — некоторые из них используются годами;</li><li>использование одних ключей для разных сред (dev/stage/prod);</li><li>избыточные права доступа — принцип минимальных привилегий не соблюдается;</li><li>хранение ключей в общих хранилищах и чатах;</li><li>отсутствие аудита использования ключей.</li></ul><p>Часто утечки происходят из-за совокупности нескольких перечисленных факторов. Например, типичный сценарий: ключ сначала попадает в код, затем в репозиторий, обнаруживается в логах CI-системы, а потом оказывается в общем доступе из-за неправильных настроек прав.</p><p>Особую опасность представляет практика использования долгоживущих ключей с широкими правами доступа. В отличие от временных токенов, такие ключи редко проверяются и могут годами оставаться незамеченными в случае утечки. Поэтому современные подходы к безопасности рекомендуют использовать краткосрочные реквизиты для входа с минимально необходимыми правами.</p><h2>Безопасное хранение и использование API-ключей</h2><p>API-ключи — это критически важные элементы инфраструктуры, и их утечка недопустима. Чтобы минимизировать риски, важно соблюдать несколько принципов.</p><p>Переменные окружения — один из базовых, но эффективных способов изоляции ключей от кода. Хранение их прямо в скриптах или конфигурационных файлах, особенно в публичных репозиториях, — распространенная ошибка.</p><p>Сканер секретов GitHub ежедневно обнаруживает сотни случайно залитых ключей, несмотря на предупреждения. Переменные окружения позволяют отделить конфиденциальные данные от кода, но важно убедиться, что файлы .env не попадают в билды или логи.</p><p>Для более сложных сценариев стоит рассмотреть специализированные хранилища секретов, такие как HashiCorp Vault, AWS Secrets Manager или Doppler. Они не только обеспечивают безопасное хранение, но и добавляют функции ротации ключей, аудита доступа и интеграции с системами мониторинга.</p><ul><li><b>Vault</b> динамически генерирует временные ключи для отдельных сервисов, сводя к нулю риск их повторного использования. Однако такие решения требуют настройки и контроля — при некомпетентном подходе компании сталкиваются с ошибками конфигурации при внедрении.</li><li><b>AWS Secrets Manager</b> — инструмент, который позволяет централизованно хранить конфиденциальную информацию, извлекать ее, управлять доступом, ротировать и мониторить.</li><li><b>Doppler</b> — кроссплатформенное решение с удобным интерфейсом и историей изменений. Особенно популярно среди стартапов.</li></ul><p>Главное преимущество таких систем — централизованное управление. При увольнении сотрудника или компрометации ключа его можно отозвать мгновенно для всех сервисов.</p><p>Шифрование обязательно как при передаче, так и при хранении. Даже если злоумышленник получит доступ к базе данных или логам, зашифрованные ключи останутся бесполезными без расшифровки. Современные стандарты, такие как AES-256 или алгоритмы на основе PQC (постквантовой криптографии), уже встроены в большинство облачных провайдеров. Но важно не забывать про управление ключами шифрования (KMS): их утечка сведет на нет всю защиту.</p><p>Ограничение доступа — еще один уровень безопасности. Даже корректно хранимый ключ должен работать только с определенных IP-адресов, в заданные промежутки времени и для конкретных методов API. Например, ключ для чтения данных не должен разрешать запись. Cloudflare <a href="https://blog.cloudflare.com/">рекомендует</a> комбинировать геофильтрацию, ограничение частоты запросов и сигнатурный анализ запросов для блокировки аномальных действий.</p><p>Наконец, мониторинг помогает обнаружить утечку до того, как ею воспользуются. Инструменты вроде AWS GuardDuty или открытый вариант Falco отслеживают подозрительные операции: неожиданные запросы из новых регионов, аномальную частоту вызовов API или попытки доступа к заблокированным эндпоинтам.</p><p>Важно: ни один метод не дает 100% защиты API. Нужно комбинировать подходы и регулярно аудировать систему. Безопасность API-ключей — это не разовая настройка, а процесс, требующий регулярного пересмотра политики адаптации к новым угрозам.</p><h3>Лучшая практика работы с ключами</h3><p>Хранение API-ключей требует особого внимания, так как их компрометация может привести к серьезным последствиям. Около половины всех утечек ключей происходят из-за их хардкодирования в исходном коде. Это базовая ошибка, которую легко избежать, используя переменные окружения или специализированные хранилища секретов.</p><p>Вот самые эффективные практики:</p><ul><li>Первое правило — никогда не оставлять ключи в коде. Даже если репозиторий приватный, всегда существует риск случайной публикации или утечки через резервные копии. Инструменты вроде pre-commit хуков помогают предотвратить подобные инциденты, автоматически проверяя изменения перед отправкой. Например, скрипт может сканировать коммиты на наличие строк, похожих на ключи, и блокировать их сохранение.</li><li>Регулярная ротация снижает потенциальный ущерб от возможной компрометации. Ключи, которые не обновлялись годами, представляют особую опасность. Современные системы, такие как HashiCorp Vault или AWS Secrets Manager, позволяют автоматизировать этот процесс.</li><li>Принцип минимальных привилегий должен применяться ко всем ключам. Если токен нужен только для чтения данных, он не должен иметь прав на запись или удаление. Ограничение области действия каждого токена — простой, но эффективный способ снизить риски.</li><li>Мониторинг использования помогает выявлять аномалии в реальном времени. Неожиданные всплески активности, запросы из новых регионов или попытки доступа к неиспользуемым методам API — все это сигналы потенциальной компрометации. Инструменты типа AWS CloudTrail или Elastic SIEM позволяют отслеживать подобные события и оперативно реагировать на угрозы.</li><li>Обучение команды не менее важно, чем технические меры. Регулярные тренинги и чек-листы помогают поддерживать уровень осведомленности.</li></ul><p>Централизованное управление упрощает контроль за ключами. Когда все токены хранятся в одном защищенном месте, проще отслеживать их использование, вовремя обновлять и отзывать при необходимости. Это также облегчает аудит, который часто требуется для соответствия стандартам вроде PCI DSS или ГОСТ Р 56939-2024.</p><p>Процесс отзыва должен быть максимально оперативным. В случае компрометации ключа важно не только сгенерировать новый, но и убедиться, что старый уже недействителен. Некоторые сервисы, например Google Cloud, позволяют автоматически блокировать ключи при обнаружении подозрительной активности.</p><h3>Автоматическое выявление утечек</h3><p>Обнаружение утекших API-ключей должно быть неотъемлемой частью стратегии безопасности. Современные инструменты позволяют выявлять компрометацию секретов на ранних стадиях, минимизируя потенциальный ущерб.</p><p>Эффективный мониторинг начинается с проверки исходного кода. Такие инструменты, как <a href="https://www.gitguardian.com/">GitGuardian</a> и <a href="https://trufflesecurity.com/">TruffleHog</a>, сканируют git-репозитории, включая историю коммитов, на наличие случайно оставленных ключей. Они используют комбинацию шаблонов и энтропийного анализа, что помогает находить даже замаскированные секреты. Интеграция этих проверок в CI/CD-пайплайны позволяет перехватывать потенциальные утечки до их попадания в основную ветку.</p><p>Для обнаружения ключей за пределами репозиториев существуют специализированные сервисы, которые мониторят открытые площадки вроде Pastebin и технических форумов. Некоторые решения способны анализировать контекст, отличая реальные ключи от случайных последовательностей символов.</p><p>При выявлении компрометации критически важна оперативная реакция. Первый шаг — немедленный отзыв скомпрометированного ключа. Современные системы управления секретами позволяют делать это автоматически, одновременно инициируя процесс генерации замены. Задержки в этом процессе создают опасное окно уязвимости.</p><p>Проактивный мониторинг должен сопровождаться четким планом реагирования. Документированные процедуры позволяют сократить время реакции и минимизировать последствия инцидента. Важно регулярно тестировать эти процедуры на практике.</p><p>Автоматизированные системы обнаружения утечек работают наиболее эффективно в сочетании с обучением разработчиков. Технические средства бесполезны, если команда продолжает пренебрегать базовыми правилами безопасности. Регулярные тренировки помогают поддерживать высокий уровень готовности к реальным угрозам.</p><p>Важно понимать, что автоматическое обнаружение — это последний рубеж защиты. Оно не заменяет, а дополняет другие меры безопасности, такие как грамотное хранение ключей и контроль доступа. Комплексный подход значительно снижает риски, связанные с компрометацией API-ключей.</p><h2>Как реализовать безопасный доступ на фронтенде</h2><p>Основная проблема фронтенд-разработки в контексте работы с API — невозможность полностью защитить клиентский код. В отличие от серверной части, JavaScript остается открытым для анализа, а сетевые запросы легко перехватываются. Однако существуют проверенные подходы, позволяющие минимизировать риски утечки ключей.</p><p>Первое и главное правило — никогда не хранить приватные ключи в клиентском коде. Даже минифицированный JavaScript легко декомпилируется, а строковые константы извлекаются за несколько минут с помощью стандартных инструментов разработчика.</p><p>Вместо этого рекомендуется использовать архитектурный паттерн Backend-for-Frontend (BFF), когда фронтенд общается с промежуточным сервером, а тот уже взаимодействует с основными API. Так ключи остаются на защищенной стороне, а клиент получает только временные токены с ограниченным сроком действия.</p><p>Для аутентификации пользователей оптимально подходит OAuth 2.0 с расширением PKCE (Proof Key for Code Exchange). Этот механизм обеспечивает безопасный обмен токенами даже в публичных клиентах. В отличие от обычного потока авторизации, PKCE добавляет дополнительный уровень защиты через одноразовые ключи верификации, что предотвращает перехват кодов злоумышленниками.</p><p>В случаях, когда фронтенду необходим доступ к публичным API без аутентификации пользователя, стоит использовать ограниченные токены. Например, для картографического сервиса можно выпускать ключи, разрешающие только чтение данных с жестким лимитом запросов. Такой подход применяют многие крупные платформы, включая Яндекс.Карты. Даже если токен будет скомпрометирован, его полезность для злоумышленников окажется минимальной.</p><p>Дополнительную безопасность обеспечивает динамическое получение ключей. В этой схеме фронтенд сначала запрашивает у сервера одноразовый код, затем использует его для подписи запроса. После проверки подписи сервер выдает временный ключ, действительный только для текущей сессии. Этот метод значительно усложняет массовый перехват и повторное использование украденных данных.</p><p>Фронтенд должен получать ровно столько данных, сколько необходимо для отображения интерфейса, а все критические операции должны выполняться на сервере. Комбинация прокси-серверов, временных токенов и строгого контроля доступа позволяет создать надежную систему защиты даже для чувствительных API.</p><p>Последний рубеж безопасности — верификация среды выполнения. Современные библиотеки анализируют параметры браузера, выявляя признаки эмуляции или автоматизации. Это позволяет блокировать запросы от ботов и скриптов, пытающихся массово собирать данные через API. Такой подход особенно важен для финансовых сервисов и платформ с ценной информацией.</p><p>Главный вывод: фронтенд действительно представляет угрозу для безопасности API-ключей, но грамотная архитектура и продуманные механизмы авторизации позволяют снизить риски до приемлемого уровня. Ключевой принцип защиты API — минимализм в правах доступа и максимальное делегирование ответственности серверной части.</p><p>Хочешь писать код, который не стыдно показывать? Всё для фронтендеров и бэкендеров в <a href="https://t.me/+c6lPaQBXLvE4YmMy">одном месте</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Делаем безопасные приложения: зачем нужен DevSecOps</title>
      <link>https://tproger.ru/articles/delaem-bezopasnye-prilozheniya--zachem-nuzhen-devsecops</link>
      <comments>https://tproger.ru/articles/delaem-bezopasnye-prilozheniya--zachem-nuzhen-devsecops?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Анна Ельцова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/delaem-bezopasnye-prilozheniya--zachem-nuzhen-devsecops</guid>
      <description><![CDATA[<p>Василий Степаненко, генеральный директор облачного провайдера Nubes, рассказывает, как подход DevSecOps помогает строить безопасные приложения с самого начала.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/delaem-bezopasnye-prilozheniya--zachem-nuzhen-devsecops">Делаем безопасные приложения: зачем нужен DevSecOps</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Языки программирования]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Роскомнадзор]]></category>
      <category><![CDATA[GitLab]]></category>
      <category><![CDATA[Информационная безопасность]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Уязвимость]]></category>
      <category><![CDATA[Kubernetes]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[CI/CD]]></category>
      <category><![CDATA[DevSecOps]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 22 May 2025 14:00:04 GMT</pubDate>
      <content:encoded><![CDATA[<p>Сейчас информационная безопасность — это не просто тренд, а необходимость, учитывая огромный масштаб киберугроз. Программное обеспечение обязано становиться защищённым с самого момента его создания и на всех дальнейших этапах вплоть до непосредственной эксплуатации. О том, как сделать разработку ПО безопасной с самого старта с помощью методики DevSecOps, рассказывает генеральный директор облачного провайдера Nubes Василий Степаненко.</p><h2>Что такое DevSecOps</h2><p>DevSecOps образовано от слов development (разработка), security (безопасность) и operations (эксплуатация или операции). Это подход к разработке приложений, при котором безопасность учитывается на каждом этапе CI/CD, чтобы минимизировать стоимость и повысить скорость исправления ошибок. К нему относятся не только инструменты, по типу различных сканеров библиотек и кода, но и определённые договоренности между разработчиками, DevOpsами и безопасниками.</p><p>Разработка приложений сегодня похожа на приготовление салата: берутся овощи, мясо, масла и приправы, все смешивается — и получается блюдо. Если хоть один ингредиент окажется плохим, то весь салат будет испорчен. Разработчики не всё пишут сами: в DevOps из общедоступных репозиториев могут браться готовые библиотеки: их соединяют, и в результате получается приложение (тот самый салат).</p><p>Если хоть одна из библиотек окажется плохой или дописанный разработчиком код для объединения библиотек будет некачественным, то весь салат будет непригодным для употребления. Стоимость исправления ошибки велика, ведь нужно найти испорченный ингредиент и заменить его. Однако с ПО все еще сложнее: библиотеки постоянно обновляются, а потому не понятно, в какой момент весь салат может стать непригодным — нужно постоянно следить за всеми ингредиентами блюда.</p><h2>Лицо врага</h2><p>Не все библиотеки с открытым исходным кодом, выложенные в публичные репозитории, можно считать безопасными. Их авторы часто остаются неизвестными — это могут быть как энтузиасты, так и злоумышленники, включая хакеров или представителей недружественных государств. В итоге даже при использовании сложных систем защиты — межсетевых экранов, VPN, антивирусов, DLP и PAM — компания может оказаться уязвимой. Уязвимость может прийти изнутри — через стороннюю библиотеку, которая станет «троянским конём» и даст злоумышленникам доступ к данным, производственным процессам и критичной инфраструктуре.</p><p>Процент небезопасных приложений в исследованиях российских компаний, занимающихся защитой приложений, в разные годы отличается и зависит от отрасли. Так, про финансовую отрасль <a href="https://plusworld.ru/daily/bezopasnost/positive-technologies-kriticheski-opasnie-uyazvimosti-vstrechautsya-v-90-sistem-dbo/">Positive Technologies в 2015 говорили о 90%</a>, в 2016 г. — о 71%, а в 2017 – о 56%. Если замеченный Positive Technologies тренд защищенности приложений финансового сектора сохранился бы в тех же пропорциях, то сегодня процент был бы ещё меньше. Однако <a href="https://mobile-stingray.ru/research/security-analysis">исследование «Стингрей Технолоджис»</a> 2024 г. говорит о 56% опасных приложений в финтехе.</p><p><a href="https://www.cnews.ru/news/line/2025-01-31_67_finansovyh_kompanij_schitayut">Ассоциация ФинТех проводила исследование</a>, и в 2025 году 82% компаний назвали разработку на базе открытого исходного кода оптимальной с точки зрения сроков и удобства внедрения. При этом использование таких библиотек несёт в себе риски на протяжении всего жизненного цикла продукта, и риски для данных, которые используются в приложениях.</p><p>У крупных финтех-компаний DevSecOps уже в работе — они вкладываются в безопасную разработку и задают статистику. Но для большинства игроков из второй и третьей лиги всё только начинается: подход к безопасности — пока больше на уровне обсуждений, чем практики.</p><h2>Какие есть риски для данных</h2><p>Основные риски для данных обычно связаны с нарушением их конфиденциальности. В процессе разработки важно проводить тесты, а для этого нужны данные, причём не сильно отличающиеся от настоящих. Также важен их объём, иначе не получится провести нормальные нагрузочные тесты. Выгрузка реальных данных — самый заманчивый вариант. Но если для стендов Dev и Test используются облачные среды или в процессах разработки задействованы подрядчики, то некоторые организации могут на такое не решиться из-за требований к ИБ. И это логично, поскольку в Prod есть комплексный подход к защите, а на стендах Dev и Test меры защиты могут быть минимизированы.</p><p>Один из способов снизить риски — использовать системы маскирования: они помогают обезличить персональные и финансовые данные (например, номера карт и счетов). Сейчас действует приказ Роскомнадзора №996 от 2013 г., но, необходимо отметить,  уже опубликован <a href="https://regulation.gov.ru/Regulation/Npa/PublicView?npaID=155867#">проект приказа Роскомнадзора</a> «Об утверждении требований к обезличиванию персональных данных и методов обезличивания персональных данных», который его заменит.</p><p>Контейнеры стали стандартом для запуска приложений, но вместе с удобством они приносят и риски — особенно в защите данных. Да, контейнеризация улучшает доступность и масштабируемость, но не решает проблем с конфиденциальностью и целостностью «из коробки». На российском рынке уже существуют отечественные платформы контейнеризации, например, Штурвал, DeckHouse, в которых сразу учтены механизмы безопасности либо есть накладные средства для kubernetes от Luntry, PT, Kaspersky и т.д.</p><h2>Как внедрять DevSecOps</h2><p>DevSecOps — подход, при котором безопасность вшита в код на всех этапах. Уязвимости ищут не в самом конце, а прямо по ходу разработки: в pull request'ах, CI/CD и при работе с зависимостями. Такой подход требует, чтобы разработчики, DevOps и специалисты по безопасности работали как одна команда, а не передавали задачи «по цепочке» в последний момент.</p><p>При этом каждой компании может требоваться сугубо индивидуальный набор инструментов — всё зависит от зрелости команды и доступных ресурсов (особенно человеческих). Важно договориться о недопустимых событиях, об уровне риск-аппетита с бизнесом, разработать модель угроз. Некоторым клиентам нужно наличие собственного доверенного репозитория, а для других достаточно GitHub, GitLab и т.д.</p><p>После аудита начинается внедрение. На этом этапе команда определяет инструменты, выстраивает процесс проверки кода и решает, как именно безопасность будет встроена в разработку.</p><p>Cloud Native — это подход к разработке приложений, изначально ориентированных на работу в облачной среде и интеграцию с облачными сервисами. Сегодня большинство новых решений проектируются именно так. Для безопасной работы таких приложений важно не только адаптировать архитектуру под облако, но и выстраивать взаимодействие с провайдером: от заключения договора до работы с API. Облачные провайдеры часто предлагают инструменты, которые помогают встроить безопасность в процесс разработки. У многих есть готовые сервисы Kubernetes, в том числе с учётом требований информационной безопасности. Также доступны решения уровня WAF и инструменты анализа безопасности кода (например, SAST, DAST, SCA) — иногда по подписке, как в случае с некоторыми российскими платформами.</p><p>Начать можно с внедрения бесплатных решений — например, SAST, SCA и DAST, которые уже можно интегрировать в текущий DevOps-стек. Когда команда понимает ценность и пользу этих проверок, можно переходить к платным продуктам с расширенными возможностями.</p><p>Затем практики DevSecOps внедряются в небольших проектах — так можно оценить эффективность их работы, заметить возможные недостатки, скорректировать решения, чтобы на выходе получить отличный рабочий вариант для применения в крупных проектах с потенциальным увеличением масштабов в будущем.</p><p>Однако не стоит думать, что это финальная точка. DevSecOps — постоянный процесс: мониторинги, улучшения, обновления стандартов ИБ и поиски идеальных практик.</p><h2>Цена вопроса</h2><p>Вернемся к примеру с салатом. Все любят разное: кто-то — «цезарь», другой – «селёдку под шубой». Разные языки программирования, риск-аппетиты в командах в отношении принятия требований безопасности, цели внедрения DevSecOps (кому-то нужно в итоге получить сертификат, а кому-то страшно за конечный продукт и важно обеспечить реальную максимальную безопасность) — всё это не позволяет создать коробочный продукт с фиксированной ценой, хотя на рынке есть те, кто предлагает поставить 2-3 сканера и удовлетвориться этим, назвав DevSecOps.</p><p>При внедрении DevSecOps стоит учитывать затраты на разделение сред Dev, Test и Prod — это не входит в концепцию по западным лекалам. Однако от руководства компаний-клиентов нам часто поступают запросы на усиление безопасности разработки, поскольку разработчик перепутал стенд, после чего важнейшие системы компании пострадали. Вынести в облако Dev и Test и оставить у себя Prod кажется хорошей идеей (или наоборот). Для некоторых она способна полностью решить вышеупомянутую проблему.</p><p>Однако тем, кому важно углубиться именно в DevSecOps, следует внедрить процесс анализа библиотек с открытым исходным кодом. Мы не знаем разработчиков этих библиотек, в сообществах могут поменяться цели и их лидеры. Они, в свою очередь, вполне могут оказаться хакерами, желающими распространить через эти библиотеки свои инструменты.</p><h3>Сканеры библиотек могут быть бесплатными и платными</h3><p><b>Статический анализ кода (SAST)</b> — может быть реализован через бесплатные инструментов, таких как SonarQube, semgrep, gitleaks/trufflehog, но есть и платные – PVS-Studio, Svace, Solar appScreener и т.д.</p><p><b>Динамический анализ кода (DAST)</b> — можно осуществить с помощью бесплатных инструментов OWASP ZAP, Nuclei, NMAP, Burp Suite или платных, например, PT BlackBox.</p><p>И другие элементы DevSecOps (анализ мобильных приложений, API и т.д.) можно реализовать с использованием платных или бесплатных инструментов.</p><p>Таким образом, если не продавать какой-то сканер под видом DevSecOps, то сложно сказать цену для клиента, всё зависит от пожеланий. Если все же очень нужно грубо оценить DevSecOps, то его внедрение обходится примерно в одну треть от стоимости процессов DevOps, но это при использовании бесплатных инструментов. Платные автоматически увеличивают стоимость.</p><p>В процессы Ops можно также включить элемент безопасности WAF (Web Application Firewall). Доступны как бесплатные варианты (например, ModSecurity), так и платные (PTAF, Гарда WAF, Вебмониторэкс и т.д.).</p><p>Начинать стоит с бесплатных инструментов, поэтапно внедряя их в CI/СD, взаимодействуя с командой DevOps. По сути, DevSecOps – это консалтинг с возможностью применения платных инструментов, если к ним готова команда DevOps. И мы абсолютно уверены, что ради его внедрения точно не стоит жертвовать командой разработки. Кстати, для трактовки отчётов сканеров зачастую используются те же консалтеры, что внедряли DevSecOps.</p><p>Нельзя забывать и об обучении команды практикам безопасной разработки. Тут следует упомянуть, что сканеры типа CheckMarx наглядно демонстрируют эксплуатацию уязвимостей. Часто вендоры сводят DevSecOps к сканерам, консалтеры — к процессам, а про людей и их обучение — забывают.</p><p>Просто прочитать пару статей про DevSecOps — недостаточно. Команда должна <b>понимать реальные уязвимости</b>: как они появляются, чем опасны и как их избежать. Сейчас в России появляются обучающие платформы, которые показывают это на практике — с примерами уязвимого кода, проблемных библиотек и типовых ошибок. Но останавливать разработку ради курсов на две недели — нереально. Поэтому лучше встроить обучение в рабочий ритм: хотя бы один час в неделю на всю команду. Это немного, но в долгосрочной перспективе даёт устойчивую культуру безопасности. Стоимость зависит от числа участников и выбранных курсов — но в любом случае это обойдется дешевле, чем инцидент в проде.</p><h2>Требования к безопасной разработке ПО</h2><p>Уже сейчас требования по безопасной разработке (а если есть DevOps, то по сути это требования к внедрению DevSecOps) появились в:</p><ul><li>ГОСТ Р 57580.1-2017: СМЭ.6, СМЭ.7, ЖЦ.4, ЖЦ.5, ЖЦ.6, ЖЦ.7. ЖЦ.24;</li><li>PCI DSS 4.0.1: 6.2, 6.3, 6.5;</li><li>ГОСТ Р ИСО/МЭК 15408-3-2013: ALC_CMC, ALC_CMS, ALC_DEL, ALC_DVS, ALC_FLR, ALC_LCD, ALC_TAT.</li></ul><p>Если речь идет о <b>средствах защиты информации (СЗИ)</b>, которые нужно будет сертифицировать по требованиям ФСТЭК или ФСБ, важно помнить: <b>инструменты, которые вы используете для сканирования кода, тоже должны быть сертифицированы.</b> Иначе при испытаниях возникнут сложности — лаборатории не примут результаты без официальной документации.</p><p>Если же приложение не попадает под категорию СЗИ, жёстких требований к инструментам нет. Главное — понимать, от каких угроз вы защищаетесь, и подбирать инструменты под реальные задачи: будь то уязвимости в зависимостях, ошибки в логике или неправильные настройки.</p><h2>Куда будет развиваться DevSecOps</h2><p>Очевидно, что DevSecOps ждет намного более массовое внедрение и развитие — устранить проблемы на этапе разработки дешевле, чем позже латать пробоины в ИБ.</p><p>Скорость появления эксплоитов растёт — и это прямая угроза. Если раньше у команд была пара месяцев, чтобы закрыть уязвимость до начала атак, то теперь — всего несколько дней. <a href="https://www.opennet.ru/opennews/art.shtml?num=62065">Исследование Google</a> показало: в 2018–2019 годах эксплойты появлялись в среднем через 63 дня после патча, в 2020 — через 44, в 2021 и 2022 — уже через 32, а в 2023 году — всего через 5 дней. А с развитием ИИ этот срок может сократиться ещё сильнее.</p><p>В России сильные программисты, но собственные новации в сфере ИБ традиционно появляются позже, чем на Западе — чаще в виде адаптаций или копий существующих решений. Однако импортозамещение меняет ландшафт: появляются десятки отечественных продуктов, которых просто нет в зарубежных базах уязвимостей. А значит — и в популярных сканерах кода они тоже не учтены. Это открывает окно возможностей: российские команды смогут развивать собственные инструменты безопасности — от сканеров и доверенных репозиториев до платформ для DevSecOps. Плюс эти принципы начнут постепенно проникать в программы обучения в вузах.</p><p>Уже существуют реестр отечественного ПО (ведется под патронажем Минцифры), реестр сертифицированных средств защиты ФСТЭК России, реестр ФСБ России, реестр отечественных ПАК (ведётся Минпромторгом). Чтобы попасть туда в ближайшие годы, разработчики должны будут не просто заявлять о безопасности, а доказывать на практике — в процессах, документации и архитектуре. Это станет драйвером роста: инструменты для безопасной разработки будут развиваться, а вместе с ними — и культура DevSecOps.</p>]]></content:encoded>
    </item>
    <item>
      <title>CD, флоппи и кассеты: как мы хранили данные до флешек и облаков</title>
      <link>https://tproger.ru/articles/cd--floppi-i-kassety--kak-my-hranili-dannye-do-flewek-i-oblakov</link>
      <comments>https://tproger.ru/articles/cd--floppi-i-kassety--kak-my-hranili-dannye-do-flewek-i-oblakov?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Денис Кудерин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/cd--floppi-i-kassety--kak-my-hranili-dannye-do-flewek-i-oblakov</guid>
      <description><![CDATA[<p>Эволюция носителей данных от дискет и магнитных лент до облачных сервисов. Прошлое и будущее способов хранения и воспроизведения информации. </p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/cd--floppi-i-kassety--kak-my-hranili-dannye-do-flewek-i-oblakov">CD, флоппи и кассеты: как мы хранили данные до флешек и облаков</a>»</p>]]></description>
      <category><![CDATA[Интернет]]></category>
      <category><![CDATA[Ретро]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Apple]]></category>
      <category><![CDATA[Опрос]]></category>
      <category><![CDATA[Фильмы]]></category>
      <category><![CDATA[Windows]]></category>
      <category><![CDATA[Музыка]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Microsoft]]></category>
      <category><![CDATA[Tor]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Tesla]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[IBM]]></category>
      <category><![CDATA[Игра]]></category>
      <category><![CDATA[Илон Маск]]></category>
      <category><![CDATA[Sony]]></category>
      <category><![CDATA[Космос]]></category>
      <category><![CDATA[Дата-центр]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Машин]]></category>
      <category><![CDATA[микро]]></category>
      <category><![CDATA[1C]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Стриминговые сервисы]]></category>
      <category><![CDATA[Steam]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 16 May 2025 14:00:04 GMT</pubDate>
      <content:encoded><![CDATA[<p>Сегодня, когда терабайты информации умещаются в кармане, а облачные хранилища доступны в два клика, трудно представить, что всего 30 лет назад люди осторожно вставляли в компьютер хрупкие пластиковые квадратики с объемом в 1,4 Мб, надеясь, что дискета не «съест» важные файлы.</p><p>Для поколения Z и альфа дискеты, кассеты и CD — такая же архаика, как патефон для миллениалов. Но именно эти носители стали мостом между эпохой аналоговых технологий и цифровой революцией. Некоторые до сих пор помнят скрежет модема, загружающего игру с аудиокассеты, или волнение при записи первого CD — этот ритуал требовал идеального буфера в Nero и молитв, чтобы электричество не отключили в процессе.</p><p>Вспомним, какими были носители данных до эры флешек и облаков. Это не просто история технологий — это рассказ о том, как мы научились ценить каждый мегабайт и почему современные удобства сделали нас немного ностальгирующими гиками.</p><h2>Носители информации: эволюция</h2><p>Сегодня данные окружают нас, как воздух — невидимые, но жизненно важные. В наших смартфонах — навигаторы, приложения для заказа еды, интернет-банкинг, весь Лев Толстой в текстовом или аудиоформате. Фотографии автоматически загружаются в облако, рабочие документы синхронизируются между устройствами, а музыка и фильмы доступны по первому требованию без необходимости записывать что-либо на пленку или вставлять диск в дисковод.</p><p>Мы живем в эпоху, когда информация стала нематериальной, а ее хранение — виртуальной услугой, за которую ежемесячно платят подпиской. При этом цена за удовольствия, информацию и духовную пищу (музыка, кино, книги и т.д.) несоизмеримо ниже, чем несколько десятилетий назад.</p><p>Но так было не всегда. Было время, когда никто не доверял интернет-хранилищам — да их и не было в том виде, к которому мы сегодня привыкли. Важные файлы хранили на чем-то осязаемом — дискетах, дисках, пленках. Данные были привязаны к физическим объектам, которые можно было потерять, сломать или случайно очистить.</p><p>История носителей — это история компромиссов между объемом, скоростью и надежностью. Каждая эпоха выбирала свой формат, исходя из технологических возможностей и потребностей пользователей, будь то ученые, музыканты или просто те, кто очень хотел сохранить свою коллекцию пиксельных картинок.</p><p>Первые носители информации были аналоговыми и требовали физического контакта. Бумага, перфокарты, магнитная лента — все это работало по принципу «записал один раз и следи, чтобы не испортилось». Но с появлением продвинутой техники понадобилось что-то более гибкое, что позволило бы не только хранить, но и быстро перезаписывать данные. Так началась эра магнитных носителей.</p><p>Магнитные кассеты использовались не только для записи и воспроизведения музыки, но и стали первым массовым способом хранения цифровой информации для домашних компьютеров. Пользователи писали на пленку игры типа Pacman или Dizzy, а также  прикладные программы для компьютеров АТМ Турбо и Spectrum.</p><p>Кассеты были дешевы, доступны, но обладали низкой скоростью доступа. Загрузка программы с кассеты занимала несколько минут: один сбой — и данные отправлялись в небытие. Тем не менее для своего времени это был прорыв: в отличие от перфокарт, кассеты позволяли перезаписывать информацию, а их компактность делала этот способ удобным для домашнего использования.</p><p>Затем пришли дискеты, и мир узнал, что такое «портативность» в цифровом смысле. Если кассеты были еще слегка похожи на предыдущее поколение (массивные бобины), то флоппи-диски уже вполне выглядели как технология из будущего. Первые модели хранили жалкие 80 КБ, но к 1980-м емкость выросла до 1.44 МБ — достаточно для текстовых документов и простейших программ. Правда, надежность оставляла желать лучшего: магнитные диски боялись пыли, влаги и просто времени.</p><p>Оптические носители, такие как CD и DVD, стали следующим шагом. Они предлагали куда больший объем (от 700 МБ до 4.7 ГБ) и теоретически — вечное хранение данных. Правда, на практике царапины, солнечный свет и некачественные болванки приводили к быстрому обнулению файлов. Но главный минус — эти диски нельзя было просто так перезаписать. CD-RW и DVD-RW решили проблему, но их распространение было медленным: люди уже начали привыкать к тому, что данные можно копировать бесконечно.</p><p>Конец XX века принес еще несколько любопытных форматов вроде ZIP-дисков, которые пытались заменить флоппи, но проиграли войну, поскольку оказались слишком дорогими и неудобными.</p><figure><img src="https://media.tproger.ru/user-uploads/113565/2025-05-06/71eb328d-a19d-48f3-8864-b798c77cd662.jpg" alt="" /></figure><p>Эволюция носителей — это вопрос не только технологий, но и человеческих привычек. Мы перешли от кассет, которые нужно было перематывать, к дискам, которые нельзя было поцарапать, а затем — к флеш-памяти, где вообще не было движущихся частей. Каждый новый формат убивал предыдущий, поскольку делал хранение данных проще, надежнее, быстрее и дешевле. О том, как это происходило на практике, читайте далее.</p><h2>Как хранили и передавали информацию до флешек и облаков</h2><p>Ненадежные, но безальтернативные дискеты, вмещавшие меньше, чем сегодняшний снимок экрана; кассеты с уязвимой магнитной пленкой; CD с их обманчивым обещанием «вечного хранения». Все эти носители в свое время считались если не революционными, то прогрессивными и передовыми. Нынешнему поколению будет полезно узнать, где хранили музыку, видео, софт и другие данные их родители и почему эти волшебные изобретения больше не используются массово.</p><h3>Аудио и видеокассеты: не забудьте перемотать на начало</h3><p>До того как видеохостинги и стриминговые сервисы стали нормой, люди обменивались музыкой и фильмами при помощи хрупких пластиковых коробочек с магнитной лентой внутри. Аудио- и видеокассеты были не просто носителями — они стали культурным феноменом, символом эпохи, когда контент нельзя было получить мгновенно, зато можно было легко испортить — поместить рядом с магнитом или «зажевать» в некачественном проигрывателе.</p><p>Магнитная лента появилась задолго до кассет — первые бобинные магнитофоны использовались еще в 1940-х, но они были громоздкими и дорогими. Все изменилось в 1963 году, когда компания Philips представила компакт-кассету — небольшой, удобный и, что важно, дешевый формат. В отличие от винила, кассеты можно было записывать повторно, носить с собой и даже ронять без катастрофических последствий.</p><p>К 80-м годам кассеты стали основным способом слушать музыку. Их продажи в США достигли пика в 442 миллиона штук в 1990 году, но затем началось стремительное падение — CD-диски предлагали лучшее качество звука и отсутствие изматывающей перемотки. Однако кассеты не исчезли полностью: даже в 2012 году в Штатах продали 13 миллионов штук, в основном благодаря автолюбителям, чьи старые машины были оборудованы кассетными магнитолами. В России формат держался примерно до середины 2000-х, после чего кассеты почти исчезли из обихода.</p><figure><img src="https://media.tproger.ru/user-uploads/113565/2025-05-06/aff42e02-398c-4f5e-a1f0-ff8fc0074ca5.png" alt="" /></figure><p>Пока аудиокассеты правили балом в музыке, VHS делал то же самое с видео. Этот формат, появившийся в 1970-х, быстро вытеснил конкурентов (например, Betamax от Sony) благодаря простоте и доступности. Видеомагнитофон стал почти обязательным устройством в каждом доме, а прокат кассет — целой индустрией.</p><p>Но у VHS были свои причуды:</p><ul><li>Длинный фильм на двухчасовой кассете мог закончиться в самый напряженный момент, заставляя зрителя в недоумении хлопать глазами.</li><li>Качество изображения ухудшалось с каждой перезаписью, превращая картинку, над которой так трудилась съемочная группа, в движения размытых или крупнозернистых силуэтов.</li><li>Размагничивание, скручивание ленты и вечная борьба со «снегом» и полосами на экране — все было неотъемлемой частью пользовательского опыта.</li></ul><p>Несмотря на это, VHS формат продержался до начала 2000-х, пока его не вытеснили DVD, а затем и стриминговые сервисы.</p><figure><img src="https://media.tproger.ru/user-uploads/113565/2025-05-06/c0d5e69c-ad0d-46ac-8a66-9a759df9c1ef.png" alt="" /></figure><p>Магнитная лента использовалась не только для музыки и фильмов — в 1980-х она стала первым массовым носителем данных для домашних компьютеров. Владельцы ZX Spectrum и Commodore 64 загружали программы с аудиокассет, подключив магнитофон к компьютеру. Процесс напоминал шаманский ритуал: нужно было выставить правильный уровень громкости, надеяться, что маг не зажует ленту, и ждать несколько минут, пока игра загрузится (если, конечно, в середине не возникала ошибка, заставляющая начинать все сначала).</p><p>Перезапись данных на кассетах была рискованным делом — старую информацию можно было случайно стереть, а новая не всегда записывалась корректно. Тем не менее, это был прорыв: в отличие от дискет, кассеты были дешевы и доступны, что делало их идеальным вариантом для домашнего использования.</p><p>Казалось бы, эпоха магнитной ленты бесповоротно миновала, но это не совсем так. В дата-центрах до сих пор используют ленточные библиотеки (например, LTO), потому что они дешевы, энергоэффективны и отлично подходят для долгосрочного хранения больших объемов данных. Современные картриджи LTO-9 вмещают до 45 ТБ информации — это в тысячи раз больше, чем могла предложить кассета 1980-х.</p><figure><img src="https://media.tproger.ru/user-uploads/113565/2025-05-06/37a1c3a2-95fb-4168-a30d-ff61432a9618.png" alt="" /></figure><p>Кассеты утратили актуальность, но их наследие живет, как и ностальгия по аналоговой эре. Они напоминают нам о времени, когда контент нельзя было получить мгновенно, зато сам процесс — запись, перемотка, даже борьба с зажеванной лентой — был частью ритуала.</p><h3>Флоппи-диски (дискеты): 1,4 Мб славы</h3><p>В эпоху, когда облачные хранилища предлагают терабайты пространства за несколько сотен рублей в месяц, трудно представить, что всего 30 лет назад люди хранили данные на квадратных кусочках пластика, которые могли вместить меньше, чем сегодняшнее селфи в хорошем качестве.</p><p>Флоппи-диски, или просто дискеты, стали символом компьютерной революции 1980-1990-х: они были везде, их боялись потерять, ими обменивались, как сейчас ссылками, и их регулярно проклинали, когда на экране возникало сообщение «Диск не отформатирован».</p><p>Первая дискета, представленная IBM в 1971 году, была 8-дюймовой и вмещала смехотворные по современным меркам 80 КБ данных. Она создавалась как альтернатива перфокартам — более надежная и удобная, но по-прежнему громоздкая. К середине 1980-х индустрия перешла на 5,25-дюймовые гибкие диски, а затем и на 3,5-дюймовые, которые стали стандартом. Последние, кстати, были не такими уж «гибкими» — прочный пластиковый корпус защищал магнитный диск внутри, хотя слово «флоппи» (от английского floppy — «гибкий») так и осталось в названии.</p><p>Объем памяти рос медленно: если в 1984 году дискета на 3,5 дюйма хранила 720 КБ, то к 1987-му — уже 1,44 МБ. Этого хватало для текстовых документов, простых программ и даже некоторых игр. Microsoft Word 2.0, выпущенный в 1991 году, умещался на одной дискете, а его современный аналог требует около 4 ГБ — в 3000 раз больше.</p><p>Дискеты были удобны и одновременно ужасно ненадежны. Они боялись магнитов, пыли, влаги, перепадов температуры и даже слишком резкого извлечения из дисковода. Классическая ситуация: вы вставляете дискету в компьютер, слышите характерный скрежет, а через пару секунд получаете роковое сообщение о том, что носитель не читается. Иногда помогало «продувание» — буквально дыхание на магнитную поверхность в надежде, что влага временно восстановит контакт.</p><figure><img src="https://media.tproger.ru/user-uploads/113565/2025-05-06/13c5b2b5-7ec4-4706-bb05-aeb757d1d9e1.png" alt="" /></figure><p>Еще одна проблема — ограниченный срок жизни. Даже идеально хранимая дискета могла потерять данные через 5-10 лет из-за размагничивания. Архивы на флоппи требовали регулярного перезаписывания, что превращало хранение информации в постоянную головную боль.</p><p>В 1980-х развернулась настоящая битва форматов. Компания Apple сделала ставку на 3,5-дюймовые дискеты, в то время как IBM и другие производители первое время держались за 5,25 дюймов. Победил, как известно, меньший размер — отчасти благодаря тому, что новые носители были прочнее и компактнее.</p><p>Любопытно, что следы дискетной эпохи до сих пор встречаются в цифровом мире. Буква «A:\» в Windows, которая изначально обозначала дисковод, осталась в системе как дань традиции. Иконка «Сохранить» во многих программах до сих пор изображает флоппи-диск, хотя большинство современных пользователей и в руках-то его никогда не держали.</p><p>К началу 2000-х дискеты начали стремительно исчезать. В 2011 году компания Sony, последний крупный производитель, прекратила их выпуск. Но, как это часто бывает, технология не умерла полностью.</p><p>Оказалось, что множество промышленных станков, медицинского оборудования и даже некоторых банковских систем до сих пор используют флоппи-диски. В 2018 году выяснилось, что американские ядерные силы все еще управляются с помощью 8-дюймовых дискет (хотя позже систему все же модернизировали).</p><p>На вторичном рынке дискеты до сих пор в ходу. Предприниматель Том Перски в 2010 году скупил около миллиона 3,5-дюймовых флоппи и создал целый бизнес по их продаже. Основные клиенты — владельцы старого промышленного оборудования, для которого переход на современные носители оказался слишком дорогим.</p><p>Флоппи-диски — это не просто архаичный способ хранения данных. Они были важным этапом в эволюции персональных компьютеров, сделавшим информацию по-настоящему мобильной. Сегодня, когда мы можем переносить терабайты данных в кармане, стоит вспомнить, с чего все начиналось — с хрупких квадратиков, которые нужно было беречь от магнитов и всегда переворачивать правильной стороной.</p><h3>Сиди и Дивиди: эпоха лазерного ренессанса</h3><p>В конце 1990-х дискеты уже выглядели архаично, а облачных хранилищ еще не существовало. На сцену вышли оптические диски — сначала скромные CD на 700 МБ, после — DVD на 4,7 ГБ, а затем и Blu-ray с их 50 ГБ. В определенный период записать фильм на болванку считалось технологическим подвигом. Нужно было также красиво написать название на внешней стороне специальным маркером.</p><p>Изначально компакт-диски создавались для музыки — первый коммерческий CD выпустили в 1982 году с записью альбома ABBA «The Visitors». Объем в 650 МБ (74 минуты аудио) выбрали не случайно: разработчики из Sony и Philips хотели, чтобы на один диск целиком поместилась Девятая симфония Бетховена. К концу восьмидесятых большинство звукозаписывающих компаний перешли на CD-формат.</p><figure><img src="https://media.tproger.ru/user-uploads/113565/2025-05-06/66eb6312-1cc6-43f5-9cc2-3d039bd65987.png" alt="" /></figure><p>Когда технологию адаптировали для компьютеров (CD-ROM), эти же 700 МБ стали стандартом для софта, игр и даже операционных систем, например, Windows 95.</p><p>Запись CD представляла собой сложную процедуру . Программа Nero Burning ROM с ее интерфейсом, напоминающим кабину пилота, требовала идеально настроенного буфера записи. Ошибка «Buffer underrun» означала, что диск испорчен, а 30-50 рублей за болванку (по меркам 2000-х — немалая сумма) летели в мусорку.</p><p>Когда в 1996 году появились DVD, их емкость в 4,7 ГБ казалась фантастической. Почему не 5? Все просто: инженеры Sony и Philips изначально планировали 5 ГБ, но пришлось пожертвовать частью объема ради совместимости с форматом CD. Впрочем, даже 4,7 ГБ хватало для фильмов в приличном качестве — пиратские копии расходились быстрее, чем студии успевали считать убытки.</p><figure><img src="https://media.tproger.ru/user-uploads/113565/2025-05-06/d4563ec9-5237-4a75-8fc1-b23b54e53576.png" alt="" /></figure><p>Киноиндустрия быстро поняла угрозу и начала войну с пиратством. На диски добавляли защиту вроде SecuROM и StarForce, которая не только мешала копированию, но и могла вывести из строя дисковод. Пользователи в ответ придумывали хитрости: от скотча на краю диска до специальных программ, которые «прожигали» защитные сектора.</p><p>В середине 2000-х разгорелась война форматов высокой четкости: Blu-ray от Sony и HD DVD от Toshiba. Технически Blu-ray был лучше — большая емкость (50 ГБ против 30 ГБ у HD DVD), но исход противостояния решил не этот фактор. Sony, которая владела киностудией Columbia Pictures, обеспечила Blu-ray эксклюзивными релизами. А когда за синий формат неожиданно выступила индустрия фильмов для взрослых (на тот момент — один из главных драйверов продаж любых носителей), судьба HD DVD была предрешена.</p><p>К 2010-м оптические диски начали сдавать позиции. Скорость интернета росла, стриминговые сервисы набирали популярность, а производители ноутбуков массово отказывались от дисководов. Последний гвоздь в крышку гроба забила Apple, выпустив в 2012 году MacBook Pro без CD-привода — тогда это казалось смелым шагом, а сегодня воспринимается как норма.</p><p>Но диски не исчезли полностью. Blu-ray до сих пор используют для фильмов в 4К, а некоторые госструктуры предпочитают архивные DVD — они дешевы и, в отличие от флешек, не подвержены спонтанному размагничиванию. Да и любители ретро-техники продолжают охотиться за редкими релизами игр на CD — например, оригинальная Half-Life на диске сегодня стоит дороже, чем в Steam.</p><p>Оптические диски стали переходным звеном между эрой физических носителей и современным цифровым миром. Они научили нас терпению (установка игры была ответственным мероприятием), бережливости (царапина на диске означала существенные финансовые потери) и даже стратегическому мышлению (когда приходилось решать, что удалить с жесткого диска ради места под новый фильм). Сегодня, когда любой контент доступен по клику, эти ритуалы кажутся странными — но именно они сделали нас теми пользователями, которыми мы стали.</p><h2>Почему все это исчезло</h2><p>Кассеты, дискеты и оптические диски не просто ушли в прошлое — они проиграли войну за удобство. В мире, где гигабайты данных передаются за секунды, а облачные хранилища доступны с любого устройства, физические носители оказались слишком медленными, хрупкими и ограниченными. Но их исчезновение — это не просто история технологического прогресса. Это урок о том, как мы перестали ценить сам процесс хранения информации.</p><p>Три причины краха:</p><ul><li>Первая и главная — объем. В 1990-х 1,44 МБ дискеты хватало для текстовых документов, но уже к началу 2000-х этого было недостаточно даже для одной MP3-песни. CD на 700 МБ казались спасением, но и они быстро устарели, когда размеры софта перевалили за гигабайты. Современные игры и видеофайлы просто не поместились бы на десятках дисков, которые пришлось бы таскать с собой.</li><li>Вторая причина — скорость. Загрузка программы с кассеты занимала минуты, запись DVD — десятки минут, а копирование файлов с дискеты напоминало медитацию. Когда на смену пришли USB-накопители с их мгновенным доступом к данным, терпеть эти задержки стало невозможно.</li><li>Наконец, надежность. Магнитные ленты размагничивались, дискеты боялись кофе и магнитов, а царапины на CD превращали их в елочные украшения. Потерять данные было проще, чем сохранить — особенно если учесть, что резервные копии требовали такого же ненадежного носителя.</li></ul><p>Некоторые архаичные носители до сих пор используются там, где важнее стабильность, а не прогресс. В авиации, например, часть бортовых систем Boeing 747 до недавнего времени обновлялась через 3,5-дюймовые дискеты — потому что проверенная временем технология надежнее экспериментальных решений.</p><p>Промышленные станки, медицинское оборудование и даже банковские системы иногда работают на технологиях 1980-х просто потому, что их модернизация стоит дороже, чем покупка партии старых дискет на eBay. А энтузиасты ретро-компьютеров сознательно используют кассеты и флоппи-диски — для них это не просто носители, а часть культурного кода.</p><h2>Что мы потеряли и что приобрели</h2><p>Физические носители учили нас ценить данные. Когда файл нельзя было скопировать в два клика, а каждый мегабайт занимал место, люди тщательнее подходили к хранению информации. Переписка кассет требовала времени, коллекцию CD бережно держали на книжных полках, стирая пыль с футляров, а игры на 10 дискетах устанавливали с замиранием сердца — вдруг последняя окажется битой.</p><p>Сегодня данные стали абстрактными. Мы не держим их в руках, не боимся потерять из-за царапины и даже зачастую не знаем, на каком именно сервере они лежат. Это удобно, но лишает нас того самого «тактильного» отношения к информации.</p><p>История кассет, дискет и дисков показывает: технологии умирают, но информация остается. Мы сменили десятки форматов, но по-прежнему хотим того же — быстрого, надежного и простого доступа к своим файлам. Разница лишь в том, что теперь для этого не нужен магнитофон или дисковод — достаточно облака и быстрого интернета.</p><h2>Флешки, SD-карты и облака: вы находитесь здесь — что дальше</h2><p>Флешки, которые еще недавно казались чудом технологий, уже выглядят архаично на фоне облачных хранилищ. SD-карты, вмещающие терабайты информации, размером не больше ногтя на мизинце. Но что дальше?</p><p>Твердотельные накопители, основанные на кремниевых чипах, приближаются к физическим пределам. Производители научились упаковывать данные невероятно плотно — современные 3D NAND-чипы содержат до 200 слоев памяти. Однако закон Мура (формулирующий неизбежность технологического прогресса) хотя и универсален, имеет определенные физические ограничения: стоимость новых фабрик по производству микросхем измеряется десятками миллиардов долларов.</p><p>Параллельно растет спрос на хранение информации: только за 2023 год человечество создало больше данных, чем за всю предыдущую историю. Архивы научных исследований, нейросетевые модели, медицинские записи — все это требует новых решений.</p><p>Будущее, которое уже тестируют в лабораториях:</p><ul><li>ДНК-хранилища. В 2017 году гарвардские ученые записали на ДНК кишечной палочки GIF-анимацию и изображение. Технология CRISPR позволяет редактировать геном, превращая его в биологический жесткий диск. Пока процесс дорогой и медленный, но потенциал огромен: один грамм ДНК может хранить 215 петабайт данных — эквивалент 14 тысяч современных SSD.</li><li>Молекулярные диски. Исследователи из Университета Брауна (Провиденс, США) создали прототип накопителя, где информация кодируется органическими молекулами. Метод напоминает древние глиняные таблички, только вместо клинописи — бинарный код из присутствия или отсутствия конкретных молекул.</li><li>Кварцевые кристаллы. Технология «5D-памяти» использует фемтосекундные лазеры для записи данных в кварцевое стекло. Такие носители выдерживают температуру до 1000°C и могут хранить информацию миллиарды лет. В 2018 году Илон Маск отправил в космос Tesla с кварцевым диском, содержащим трилогию А. Азимова «Основание».</li><li>Арктические архивы. На Шпицбергене уже работает «Арктический мировой архив», где данные хранятся на специальной пленке в стальных контейнерах. Туда поместили исходники GitHub, цифровое искусство и даже конституции некоторых стран — на случай глобальной катастрофы.</li></ul><p>Парадоксально, но будущее может вернуть нас к чему-то очень древнему: подобно тому, как египтяне высекали иероглифы в камне, мы будем записывать информацию в молекулы и кристаллы — носители, которые переживут не только нас, но и предположительно саму человеческую цивилизацию.</p><p>Ты точно программист, если читаешь это! Больше мемов, инсайтов и боли кодеров <a href="https://t.me/+ajgz7pDecB4xZTI6">тут</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>OpenJDK добавит нативный JSON API для Java — первые подробности</title>
      <link>https://tproger.ru/news/openjdk-dobavit-nativnyj-json-api-dlya-java---pervye-podrobnosti</link>
      <comments>https://tproger.ru/news/openjdk-dobavit-nativnyj-json-api-dlya-java---pervye-podrobnosti?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/openjdk-dobavit-nativnyj-json-api-dlya-java---pervye-podrobnosti</guid>
      <description><![CDATA[<p>OpenJDK добавит нативный JSON API для Java — встроенная поддержка JSON упростит парсинг, обработку и создание данных без внешних библиотек</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/openjdk-dobavit-nativnyj-json-api-dlya-java---pervye-podrobnosti">OpenJDK добавит нативный JSON API для Java — первые подробности</a>»</p>]]></description>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[JSON]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 16 May 2025 09:25:45 GMT</pubDate>
      <content:encoded><![CDATA[<p>Разработчики OpenJDK <a href="https://mail.openjdk.org/pipermail/core-libs-dev/2025-May/145905.html">анонсировали</a> планы по созданию встроенного JSON API для Java. Этот шаг должен упростить работу с JSON-документами, не требуя установки сторонних библиотек.</p><p>Больше новостей — в нашем тг-канале «<a href="https://t.me/your_tech">Представляешь»</a></p><p>Новый API станет частью стандартной библиотеки Java и будет следовать принципу «батарейки в комплекте», который предполагает, что базовые функции должны быть доступны без внешних зависимостей.</p><h2>Основные особенности</h2><h2>Простой интерфейс</h2><p>Новый API будет включать минимальный набор классов для работы с JSON, включая:</p><ul><li><b>JsonValue</b> — базовый интерфейс для всех JSON-значений;</li><li><b>JsonObject</b> — коллекция ключ-значение;</li><li><b>JsonArray</b> — упорядоченный список значений;</li><li><b>JsonString</b> — строковое значение;</li><li><b>JsonNumber</b> — числовое значение;</li><li><b>JsonBoolean</b> — логическое значение;</li><li><b>JsonNull</b> — пустое значение.</li></ul><p>Вот как это будет выглядеть:</p><h2>Пример использования</h2><p>API будет поддерживать базовые операции, такие как разбор строк JSON и преобразование значений:</p><p>Со временем, по мере добавления новых возможностей для сопоставления паттернов (pattern matching) в Java, этот код станет еще более лаконичным.</p><h2>Работа с числами</h2><p>Поскольку JSON не различает целые и десятичные числа, новый API будет предлагать несколько способов работы с числами:</p><ol><li>Получение строкового представления числа.</li><li>Преобразование строки в BigDecimal для точной работы с десятичными числами.</li><li>Преобразование в стандартные числовые типы Java (Long, Double, BigInteger) с автоматическим выбором подходящего типа.</li></ol><h2>Совместимость и производительность</h2><p>Первая версия прототипа уже доступна в sandbox-репозитории OpenJDK.</p><p>Несмотря на раннюю стадию разработки, она успешно прошла большинство тестов из JSONTestSuite, за исключением случаев с дублирующимися ключами, которые намеренно запрещены для упрощения обработки JSON-объектов.</p><h2>Дальнейшие шаги</h2><p>Разработчики планируют оформить предложение по улучшению языка (JEP) для включения нового API в будущие версии JDK.</p><p>Это может быть обновление существующего JEP 198 (Light-Weight JSON API) или полностью новый документ.</p>]]></content:encoded>
    </item>
  </channel>
</rss>