<?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>Golang</title>
    <description>Go (он же Golang) — компилируемый многопоточный язык программирования, материалы по которому вы найдёте в этом разделе.</description>
    <link>https://tproger.ru/tag/golang</link>
    <atom:link href="https://tproger.ru/tag/golang/feed" rel="self" type="application/rss+xml"/>
    <lastBuildDate>Sat, 03 Oct 2026 15:36:17 GMT</lastBuildDate>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>12</sy:updateFrequency>
    <image>
      <title>Golang</title>
      <link>https://tproger.ru</link>
      <url>https://tproger.ru/apple-touch-icon.png</url>
    </image>
    <item>
      <title>Наблюдаемость: где на самом деле теряются миллисекунды</title>
      <link>https://tproger.ru/articles/nablyudaemost-gde-na-samom-dele-teryayutsya-millisekundy</link>
      <comments>https://tproger.ru/articles/nablyudaemost-gde-na-samom-dele-teryayutsya-millisekundy?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/nablyudaemost-gde-na-samom-dele-teryayutsya-millisekundy</guid>
      <description><![CDATA[<p>Как собрать трассы без правки кода через eBPF, превратить их в метрики по медленным запросам и не принять смену методики за регрессию. Разбираем три слоя с цифрами.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/nablyudaemost-gde-na-samom-dele-teryayutsya-millisekundy">Наблюдаемость: где на самом деле теряются миллисекунды</a>»</p>]]></description>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Микросервисы]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[OpenTelemetry]]></category>
      <category><![CDATA[Grafana]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 09 Sep 2026 13:00:26 GMT</pubDate>
      <content:encoded><![CDATA[<p>Дашборд краснеет, а причина не находится. У наблюдаемости, которая так себя ведёт, обычно три независимые беды: телеметрия собрана не везде, собранное не переведено в решения, а полученные числа прочитаны неверно.</p><p>Разбираем все три слоя: как получить трассировку, не переписывая сервисы, как превратить трассы в метрики, по которым можно действовать, и как не принять смену методики измерения за изменение продукта.</p><p>Трассировка через eBPF снимает налог на ручное инструментирование, но требует ядра не ниже 5.8, несрезанной таблицы символов и знания устройства планировщика Go.</p><p>При 50 000 запросах в секунду и четырёх точках съёма на запрос получается 200 000 входов в ядро ежесекундно и потолок расхода в 200–600 мс процессорного времени на ядро.</p><p>Медленный запрос это не одна проблема, а пять разных: лишняя работа, борьба за ресурсы, давление среды, деградация плана и патологические шаблоны вроде N+1.</p><p>Инструменты базы говорят, что дорого внутри неё, но не говорят, какой сервис это вызвал и был ли запрос пользовательским. Этот контекст приносят трассы.</p><p>Версия браузера, тип навигации, библиотека сбора данных и версия инструментирования входят в определение метрики: смешав их в одном графике, вы увидите изменение измерения вместо изменения продукта.</p><h2>Слой первый наблюдаемости: собрать данные, не трогая код</h2><p>Ручное инструментирование обходится дороже, чем кажется на старте. Каждая точка вызова библиотеки, каждая ветка передачи контекста и каждое извлечение сопутствующих данных — это код, который расходится с реальностью, забывается в горячем пути и стоит процессорного времени на высокой частоте запросов.</p><p>Альтернатива, ставшая эксплуатационно пригодной за последние пару лет, — <a href="https://dev.to/neeraj_singhi_golang/ebpf-powered-request-tracing-in-go-microservices-without-instrumentation-tax-34kf">подключение зондов eBPF напрямую к символам рантайма</a> и точкам входа библиотек HTTP и gRPC. Трассы восстанавливаются из событий ядра и пользовательского пространства, а файл бинарника на диске не меняется вовсе: правки идут только в памяти работающего процесса, точечно и обратимо.</p><h3>Почему с Go это сложнее, чем с C</h3><p>Зонд работает так: в заданное смещение работающего бинарника ставится инструкция прерывания, при попадании в неё ядро останавливает поток, выполняет свою программу и возобновляет исполнение. Для C и Rust это ложится на прологи функций почти без остатка. Go добавляет три осложнения.</p><p><b>Планирование горутин.</b> Планировщик Go раскладывает множество горутин на меньшее число системных потоков. Один HTTP-запрос может обрабатываться горутиной на одном потоке в момент срабатывания зонда и переехать на другой поток до записи ответа. Наивный зонд, читающий идентификатор потока или процесса, теряет непрерывность на этом переезде. Правильный якорь — идентификатор горутины, а достать его можно либо через карту, построенную по отладочной информации, либо вычислением фиксированного смещения от указателя, лежащего в регистре локального хранилища потока.</p><p><b>Соглашение о вызовах.</b> В Go 1.17 аргументы функций переехали со стека в регистры, причём сначала только на amd64; на arm64 и ppc64 это произошло версией позже. Программа зонда, написанная под прежнее соглашение и читающая контекст со смещения от указателя стека, на новых бинарниках прочитает мусор. Значит, трассировщику нужна либо логика зондов под каждую минорную версию языка, либо вычисление места по отладочной информации самого бинарника.</p><p><b>Встраивание функций.</b> Компилятор Go агрессивно встраивает мелкие функции, и нужный символ может просто отсутствовать по ожидаемому адресу. Зонд, поставленный не туда, даёт пропущенные отрезки трассы или испорченные аргументы, причём молча.</p><p><b>Отдельная ловушка при разборе событий:</b><br />Структура на стороне потребителя должна побайтово совпадать со структурой в программе зонда, включая выравнивание. Расхождение в один байт приводит к тому, что все поля после первого декодируются неправильно, а внешне это выглядит как случайный мусор в трассах.</p><h3>Главная нерешённая проблема: передача контекста между сервисами</h3><p>Если нельзя вписать заголовок в коде приложения, как передать идентификатор трассы дальше по цепочке вызовов? Есть три подхода, и практически применим один.</p><ul><li>Писать заголовок прямо в пакет на уровне сетевого интерфейса. Требует расширенных привилегий и работает только для нешифрованного HTTP/1.1: шифрование выполняется выше уровня сокета, и программа видит уже зашифрованные байты.</li><li>Пропускать исходящие вызовы через локальный вспомогательный прокси, который держит соответствие идентификатора горутины и контекста трассы и вставляет заголовки перед пересылкой. Добавляется сетевой переход, зато шифрование не ломается.</li><li>Править карту заголовков прямо в памяти процесса. Соответствующая функция ядра помечена как опасная и действительно способна повредить память: каждая её загрузка пишет предупреждение в журнал ядра, работа требует широкой привилегии CAP_SYS_ADMIN, а в режиме блокировки ядра она запрещена совсем.</li></ul><p>Единственный вариант, который одновременно совместим с шифрованием, безопасен и разворачивается где угодно, — второй. Его цена в задержке составляет обычно меньше 100 мкс на переход через локальную петлю, что приемлемо, когда сами измеряемые операции занимают миллисекунды.</p><h3>Что ломается в продакшене</h3><ul><li>Идентификаторы горутин переиспользуются. При высокой конкурентности номер может уйти на новую горутину раньше, чем потребитель разобрал события старой.</li><li>Обновление бинарника сдвигает смещения символов. Зонды старого отображения ядро снимает само, и новый бинарник какое-то время работает без трассировки. Слежение за изменением файла сокращает разрыв до секунд, но не убирает его.</li><li>Требования к ядру. Кольцевые буферы нужны ядру от 5.8, а переносимая компиляция зондов требует 5.4 с включённой отладочной информацией о типах. Матрицу ядер стоит проверить до внедрения, а не после.</li><li>Срезанные бинарники. Сборка без таблицы символов и отладочной информации лишает трассировщик возможности сопоставить имена функций со смещениями. Компромисс: оставить хотя бы таблицу символов, заплатив примерно 10–15% размера бинарника.</li></ul><h3>Сколько это стоит в процессорном времени</h3><p>Зонды не бесплатны: каждое срабатывание это программное прерывание с входом в ядро. При 50 000 запросах в секунду и четырёх точках съёма на запрос получается 200 000 входов ежесекундно. Опубликованные замеры дают порядка 1–3 мкс на срабатывание на современном оборудовании, то есть верхняя оценка расхода составляет 200–600 мс процессорного времени в секунду на одно ядро.</p><p>Цифра ощутимая, но сравнивать её стоит с альтернативой, а не с нулём. Автор разбора оценивает эту альтернативу в десятую часть рабочего времени разработчиков, уходящую на сопровождение кода инструментирования. Потребителя событий при этом лучше держать на отдельной горутине, привязанной к ядру, которое не обслуживает запросы, чтобы выделение памяти под отрезки трасс не мешало обработке.</p><p>Правильный вывод не «заменить инструментирование зондами», а «использовать оба». Зонды дают сплошное покрытие и базовое распределение задержек без усилий разработчиков, включая сторонние бинарники, которые вы не можете изменить. Ручное инструментирование даёт смысловое наполнение: идентификатор пользователя, арендатора, флаг функциональности — то, чего из сырых байтов HTTP не синтезировать. Наиболее точные схемы наблюдаемости держат оба слоя, причём слой зондов работает проверкой на непротиворечивость для отрезков, которые приложение теряет под нагрузкой.</p><h2>Слой второй: превратить трассы в решения</h2><p>Собранная телеметрия сама по себе ничего не улучшает. Больше телеметрии означает больше объектов для разглядывания, а не больше понимания. Полезной она становится, когда из неё извлечены закономерности, на которые можно действовать.</p><h3>«Медленный запрос» это пять разных диагнозов</h3><p>Прежде чем что-то чинить, стоит понять, чем именно болен запрос. <a href="https://www.cncf.io/blog/2026/08/21/how-to-turn-slow-queries-into-actionable-reliability-metrics-with-opentelemetry/">Разбор CNCF</a> раскладывает медленные запросы к базе на пять непохожих причин:</p><ul><li>Лишняя работа. Обычно это полный перебор таблицы из-за отсутствующего или неприменимого индекса. Выборка по идентификатору клиента без индекса растёт с 20 мс на десяти тысячах строк до минут на десяти миллионах. Запрос не менялся, изменился объём данных.</li><li>Борьба за ресурсы. Идеально оптимизированный запрос стоит в ожидании блокировок или свободного соединения. Запрос, проводящий 95% времени в ожидании блокировки, оптимизацией текста не лечится: ему нужна перекройка транзакций.</li><li>Давление среды. Насыщение процессора, узкое место ввода-вывода и нехватка памяти замедляют любой запрос с любым планом: тот же текст запроса и тот же план на нагруженной машине отработает в разы дольше, чем на свободной, и оптимизировать тут нечего.</li><li>Деградация плана. Данные и текст запроса те же, а план исполнения изменился. Устаревшая статистика после массовой загрузки заставляет планировщик выбрать заведомо плохую стратегию.</li><li>Патологические шаблоны. Проблема N+1 выполняет сотню быстрых запросов по две миллисекунды последовательно, добавляя двести миллисекунд задержки на одно только выполнение, не считая сетевых издержек на каждый обмен с базой. Ни один запрос не является медленным, а шаблон катастрофичен и в журнал медленных запросов не попадает вовсе.</li></ul><h3>Чего не хватает встроенным инструментам базы</h3><p>Журналы медленных запросов, хранилища запросов и разбор планов прекрасно отвечают на вопрос, что дорого внутри базы. Они не отвечают на вопросы, которые задаёт дежурный инженер: какой сервис это вызвал, пользовательская это работа или фоновая, связано ли это со всплеском задержки, который сейчас расследуется.</p><p>Этот контекст приносит распределённая трассировка: каждый отрезок обращения к базе вложен в контекст запроса и знает сервис, конечную точку и инициатора. Вместо того чтобы вручную сшивать журналы базы с трассами постфактум, медленные запросы анализируются прямо из трасс со всем прикладным контекстом внутри.</p><p>Дальше из отрезков трасс выводятся метрики, и делается это в три приёма: сперва простое обнаружение медленных запросов, затем взвешивание по трафику, чтобы понять, что даст наибольший выигрыш при ускорении, и наконец поиск аномалий для дежурства. Первые два отвечают на вопрос оптимизации, третий — на вопрос реагирования на инцидент, и путать их не стоит: это разные задачи с разными приоритетами.</p><h2>Слой третий: не принять смену измерения за изменение продукта</h2><p>Третья ошибка самая обидная, потому что данные при этом верны. Метрика может быть абсолютно точной, а рассказанная по ней история — совершенно неверной.</p><p>Дальше примеры пойдут из веб-производительности, потому что там эта ошибка задокументирована лучше всего. Механика же общая: любой дашборд, где смешаны серии с разных популяций или с разных версий сбора, ведёт себя одинаково, будь то задержки бэкенда или отрисовка страницы.</p><h3>Общий тренд не объясняет вашу просадку</h3><p>В июньском наборе данных о реальных пользователях Chrome, опубликованном в середине июля, доля источников с хорошей отрисовкой основного содержимого упала до 67,7%, с хорошей задержкой отклика на взаимодействие до 85,9%, а доля проходящих все три ключевых показателя до 55,3%. Исключением оказалась стабильность вёрстки, поднявшаяся до 81,4%.</p><p>Google объяснил движение сезонностью, сравнив его с прошлым годом. Контекст полезный, но он не является доказательством того, что у вас локально ничего не сломалось. Релиз, рекламная кампания, изменение формы согласия, сдвиг в составе устройств или новый сторонний скрипт способны совпасть с общеотраслевым движением.</p><p>Гарри Робертс формулирует критерий проверки прямо: <a href="https://csswizardry.com/2026/07/web-perf-wednesday-002-the-metrics-dont-tell-the-whole-story/">если общая доля прошедших упала на 1,2 процентного пункта, а конкретный сайт просел на четыре, широкий тренд разницу не объяснил</a>. Верно и обратное: если сайт почти идеально повторяет рынок по браузерам и устройствам, срочное расследование в коде потратит время всей команды впустую.</p><p>Правильное сравнение поэтому не «этот месяц против прошлого». Сравнивайте движение сайта с общей дельтой, разделяйте мобильные и настольные устройства, смотрите на показатели отрисовки и отклика по отдельности и разбирайте важные шаблоны страниц, а не источник целиком.</p><h3>Изменение методики выглядит как изменение продукта</h3><p>Дальше будет сложнее. По мере того как браузеры начинают показывать переходы внутри одностраничных приложений, которые метрики первоначальной загрузки пропускали, на одном дашборде окажутся жёсткие навигации, мягкие навигации браузера и собственные виртуальные страницы приложения, причём каждая серия собрана с разной популяции пользователей.</p><p>Смешав их без оговорок, вы получите скачок графика, вызванный сменой методики, и потратите неделю на поиск несуществующей регрессии. Отсюда практическое требование: версия браузера, тип навигации, библиотека сбора данных и версия инструментирования перестают быть служебными деталями и становятся частью определения метрики. Дашборд должен нести отметки релизов, состав трафика и устройств и внятное указание, какую популяцию представляет каждый график.</p><h3>Компенсация это не исправление</h3><p>Ещё одна ловушка того же рода: браузеры учатся скрывать последствия проблем. Привязка прокрутки к содержимому подправляет позицию, когда над областью просмотра что-то вставилось или исчезло, и читателя перестаёт выбрасывать с того места, которое он разглядывал.</p><p>Улучшение реальное, но документ по-прежнему перевёрстывается, если у картинки не заданы размеры или объявление меняет высоту. Браузер убирает одно видимое следствие, а причина остаётся на месте. Проверять после такого изменения стоит липкие шапки, ленты, интерфейс согласия и встроенные блоки, а чинить всё равно вёрстку, а не полагаться на маскировку.</p><p>Тот же разрыв виден и в метрике отклика. Большинство команд сегодня способны сказать, плохой у них отклик или нет. Заметно меньше способны сказать, какое именно взаимодействие в этом виновато, на каком шаге пользовательского пути оно случилось и что его задержало. Весь разбор Гарри Робертса именно про этот разрыв между наличием числа и наличием понимания.</p><h2>Что забрать с собой</h2><p>Три слоя решают три разные задачи, и провал на любом из них выглядит одинаково: дашборд есть, ответа нет. Без покрытия вы не видите части системы. Без перевода трасс в метрики видите всё и не понимаете ничего. Без дисциплины в чтении принимаете смену методики за регрессию.</p><p>Начинать проще всего с третьего слоя: он не требует ни новой инфраструктуры, ни единой строчки кода, только дисциплины чтения. Сверьте движение своих метрик с движением рынка и убедитесь, что расследуете настоящую регрессию, а не смену методики. Дальше уже видно, чего не хватает: покрытия или перевода трасс в решения.</p><p>Материалы разбора: <a href="https://dev.to/neeraj_singhi_golang/ebpf-powered-request-tracing-in-go-microservices-without-instrumentation-tax-34kf">устройство трассировки Go-сервисов через eBPF</a>, <a href="https://www.cncf.io/blog/2026/08/21/how-to-turn-slow-queries-into-actionable-reliability-metrics-with-opentelemetry/">перевод медленных запросов в метрики надёжности</a> и <a href="https://csswizardry.com/2026/07/web-perf-wednesday-002-the-metrics-dont-tell-the-whole-story/">разбор того, как метрики вводят в заблуждение</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Producer-Consumer на Java, Go и Rust: одна задача и три уровня решения</title>
      <link>https://tproger.ru/articles/producer-consumer-na-java-go-i-rust-odna-zadacha-i-tri-urovnya-r</link>
      <comments>https://tproger.ru/articles/producer-consumer-na-java-go-i-rust-odna-zadacha-i-tri-urovnya-r?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/producer-consumer-na-java-go-i-rust-odna-zadacha-i-tri-urovnya-r</guid>
      <description><![CDATA[<p>Три уровня решения задачи производителя и потребителя: BlockingQueue в Java, каналы в Go и очередь без блокировок на Rust. Разбираемся, какой уровень нужен вам.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/producer-consumer-na-java-go-i-rust-odna-zadacha-i-tri-urovnya-r">Producer-Consumer на Java, Go и Rust: одна задача и три уровня решения</a>»</p>]]></description>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Многопоточность]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Rust]]></category>
      <category><![CDATA[Паттерны проектирования]]></category>
      <category><![CDATA[Потоки и блокировки]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 08 Sep 2026 09:00:57 GMT</pubDate>
      <content:encoded><![CDATA[<p>Задача Producer-Consumer звучит обманчиво просто: одни потоки производят элементы, другие их разбирают, а между ними стоит буфер. На собеседовании её просят решить почти всегда, и почти всегда кандидат берётся писать координацию потоков руками.</p><p>Между тем у этой задачи есть три принципиально разных уровня решения, и выбор уровня определяется не языком, а требованиями к задержке. Разбираем все три: блокирующую очередь на Java, каналы и горутины в Go и очередь без блокировок на Rust.</p><p>Producer-Consumer — это схема, в которой производители и потребители работают независимо, обмениваясь данными через общий буфер конечной ёмкости. Ёмкость здесь работает главным механизмом защиты: именно она не даёт быстрым производителям завалить медленных потребителей.</p><p>Ручная координация через wait() и notifyAll() в блоках синхронизации даёт гонки и ложные пробуждения, а активное ожидание в цикле впустую жжёт процессор.</p><p>Готовая блокирующая очередь решает задачу целиком: при переполнении она сама останавливает производителя, обеспечивая обратное давление вместо переполнения памяти.</p><p>Горутины — это не потоки операционной системы, а лёгкие единицы, которые планировщик рантайма раскладывает по потокам, поэтому создавать их можно в количествах, немыслимых для системных потоков.</p><p>Три гарантии прогресса различаются строго: obstruction-free требует отсутствия помех, lock-free гарантирует прогресс системы в целом, wait-free — завершение каждой операции за ограниченное число шагов.</p><p>Отсутствие блокировок и использование атомарных операций сами по себе не дают wait-free: цикл повторных попыток без верхней границы — это lock-free, как бы его ни называли в описании библиотеки.</p><h2>Уровень первый: блокирующая очередь Producer-Consumer</h2><p>С этого уровня начинают почти все, и здесь же <a href="https://dev.to/machinecodingmaster/mastering-the-producer-consumer-pattern-in-java-lld-the-restaurant-kitchen-khn">делают три типовые ошибки</a>:</p><ul><li>Писать собственную логику блокировок через wait() и notifyAll() внутри синхронизированных блоков. Это приносит тонкие гонки и баги ложного пробуждения, когда поток просыпается без всякого уведомления.</li><li>Крутить активное ожидание в бесконечном цикле поверх коллекции, не рассчитанной на многопоточность. Процессор загружен постоянной проверкой размера очереди, а корректности всё равно нет.</li><li>Не предусмотреть обратного давления. Когда производители быстрее потребителей, буфер растёт, пока приложение не упрётся в нехватку памяти.</li></ul><p>Правильная ментальная модель здесь кухонная: повара выкладывают блюда на раздачу фиксированной вместимости, официанты забирают их по готовности. Раздача заполнена — повар ждёт, и это нормальная работа системы, а не сбой.</p><p>В Java всё это уже реализовано в стандартной библиотеке:</p><p>Вся координация потоков спрятана внутри реализации очереди, и явных блокировок в коде не остаётся вовсе. Метод put останавливает производителя при переполнении, и это и есть обратное давление, ради которого затевалась ограниченная ёмкость.</p><h2>Уровень второй: передача сообщений вместо общей памяти</h2><p>Go подходит к задаче с другой стороны. Вместо того чтобы защищать общий буфер, язык предлагает передавать данные между независимыми исполнителями. Запускается такой исполнитель одним словом:</p><p>Ключевое слово go перед вызовом запускает функцию конкурентно. Правда, у примера выше есть подвох: когда main завершается, программа выходит целиком, и горутина может не успеть отработать. Дожидаться её нужно явно:</p><h3>Где здесь, собственно, очередь</h3><p>Горутины сами по себе задачу производителя и потребителя не решают: WaitGroup лишь дожидается завершения, буфера и обратного давления в нём нет. Роль ограниченной очереди в Go играет буферизированный канал, и это прямой аналог кухонной раздачи из предыдущего раздела:</p><p>Поведение совпадает с блокирующей очередью один в один: отправка встаёт при переполнении, приём встаёт на пустом канале. Разница в акценте. В Java вы защищаете общий буфер, в Go передаёте значение из одной горутины в другую, и владение данными переходит вместе с ним.</p><h3>Почему это не просто потоки с коротким именем</h3><p>Горутина не является потоком операционной системы. Это лёгкая единица конкурентного исполнения, которой управляет рантайм языка: он раскладывает горутины по небольшому набору системных потоков сам. Отсюда и практическое следствие — можно оперировать очень большим числом конкурентных задач, не создавая и не сопровождая отдельный системный поток под каждую.</p><p>Здесь же полезно развести два понятия, которые постоянно путают. Конкурентность — это способ структурировать программу так, чтобы несколько задач продвигались независимо. Параллелизм означает фактическое одновременное исполнение на нескольких вычислительных ресурсах. Программа может быть конкурентной, и при этом ни одна пара её задач не выполняется буквально в один момент.</p><h2>Уровень третий: очередь без блокировок</h2><p>Третий уровень нужен, когда неприемлема сама возможность того, что поток уснёт на блокировке. Это низкая задержка в торговых системах, обработка звука, ядра планировщиков. И здесь начинается терминология, в которой путаются чаще всего.</p><h3>Три гарантии прогресса</h3><p><b>Obstruction-free.</b> Операция завершится, если в какой-то момент ей дадут поработать без помех со стороны других потоков. При непрерывных помехах прогресс не гарантирован вообще. Самая слабая из трёх гарантий.</p><p><b>Lock-free.</b> Гарантирует прогресс системы в целом: даже если один поток застрял, какой-то другой обязательно завершит свою операцию. Отдельный поток при этом может голодать сколь угодно долго, но система не встаёт целиком.</p><p><b>Wait-free.</b> Каждая операция завершается за ограниченное число шагов независимо от того, что делают остальные потоки. Ключевая формулировка здесь именно «ограниченное число шагов», а не «обычно быстро», «не использует блокировок» или «работает на атомарных операциях». Это формальное свойство, а не характеристика скорости.</p><p><b>Два неравенства, которые стоит запомнить:</b><br />Отсутствие блокировок не равно wait-free. Использование атомарных операций тоже не равно wait-free.</p><h3>Почему мьютекса недостаточно</h3><p>Очередь, обёрнутая в мьютекс, — это совершенно корректный многопоточный код на Rust. Но wait-free она не является: поток, захвативший блокировку, может быть снят с процессора планировщиком, и все остальные будут ждать его возвращения неограниченно долго. Для большинства задач это приемлемо, для систем с жёсткими требованиями по задержке уже нет.</p><h3>Атомарность и упорядочивание — разные вещи</h3><p>Процессор гарантирует, что атомарная операция неделима. Этого мало: нужно ещё, чтобы потребитель увидел записи, сделанные производителем <b>до</b> публикации флага. За это отвечает модель упорядочивания памяти.</p><p>Пара «освобождение и захват» создаёт отношение синхронизации: если потребитель увидел освобождающую запись, он гарантированно видит и все предшествовавшие ей записи. Это одна из центральных идей программирования без блокировок, и именно её упускают, заменяя мьютекс на атомарную операцию без всего остального.</p><h3>Кольцевой буфер и номера последовательности</h3><p>Практическая конструкция ограниченной очереди для нескольких производителей и нескольких потребителей строится на кольцевом буфере с двумя атомарными счётчиками логических позиций. Физический слот вычисляется как остаток от деления позиции на ёмкость, а при ёмкости, равной степени двойки, деление заменяется маской по битам.</p><p>Каждый слот хранит не только значение, но и номер последовательности, по которому определяется, какому логическому поколению этот слот сейчас принадлежит:</p><p>Тип UnsafeCell здесь означает ровно то, что написано на упаковке: обращаться к значению можно только из блока unsafe, компилятор проверку прекращает, и инвариант «в конкретный момент со слотом работает один поток» держится на номере последовательности, а не на системе типов.</p><p>Тип MaybeUninit здесь не для красоты: при ёмкости в 1024 элемента нужны 1024 места под значения, а не 1024 сконструированных объекта. Производитель получает уникальную позицию одним атомарным инкрементом, и никакого соревнования за неё не возникает:</p><p>Последние три строки стоит запомнить, потому что через абзац они окажутся важны. Позиция достаётся производителю без соревнования, а вот дальше он крутится в ожидании, пока слот не перейдёт к его поколению. Верхней границы у этого ожидания нет.</p><h3>Где заканчивается честность в названиях</h3><p>Неприятная правда, которую стоит знать до выбора библиотеки: многое из того, что продаётся как wait-free очередь, на деле является lock-free. Причина в устройстве ядра алгоритма:</p><p>Операция обычно завершается быстро, но верхней границы на число неудачных попыток здесь нет, а именно она и определяет wait-free. И да, ровно такой цикл вы только что видели в нашей собственной очереди: строго говоря, на этом шаге она тоже lock-free, а не wait-free, и автор исходного разбора это прямо оговаривает. Строгая реализация требует ограниченной стратегии резервирования или механизма помощи: когда поток B встречает незавершённую операцию потока A, он не ждёт возвращения A, а доводит его операцию до конца сам. Так прогресс перестаёт зависеть от того, что планировщик сделал с конкретным потоком.</p><h2>Какой уровень выбрать</h2><p>Правило простое и почти всегда работает от обратного.</p><ul><li>Блокирующая очередь из стандартной библиотеки закрывает подавляющее большинство задач. Начинайте с неё и не пишите координацию потоков вручную.</li><li>Модель с передачей сообщений выигрывает, когда конкурентных задач много, а связи между ними хочется описать явно, а не через набор общих структур под блокировками.</li><li>Алгоритмы без блокировок берутся, когда есть измеренное требование к задержке, которое блокировка нарушает: не «хочется быстрее», а конкретная цифра в бюджете. И в продакшене их берут готовыми из библиотек вроде crossbeam, а разбирают по косточкам ради понимания механики.</li></ul><p>Ошибка почти всегда идёт в одну сторону: за атомарные операции берутся раньше, чем появилась причина, и получают код, который сложнее отлаживать, а гарантий даёт не больше.</p><h2>Что забрать с собой</h2><p>Задача Producer-Consumer решается на трёх уровнях, и уровень выбирается требованиями, а не вкусом. Ограниченный буфер с обратным давлением закрывает большинство случаев. Передача сообщений упрощает структуру, когда конкурентных задач становится много. Алгоритмы без блокировок нужны там, где блокировка нарушает измеренный бюджет задержки, и тогда важно понимать, какую именно гарантию вы покупаете.</p><p>Материалы разбора: <a href="https://dev.to/machinecodingmaster/mastering-the-producer-consumer-pattern-in-java-lld-the-restaurant-kitchen-khn">задача о ресторанной кухне на Java</a>, <a href="https://dev.to/ashitoshh01/why-does-go-have-goroutines-understanding-gos-lightweight-concurrency-341p">введение в горутины и модель конкурентности Go</a> и <a href="https://dev.to/derekmwale/building-a-wait-free-queue-in-rust-2329">построение wait-free очереди на Rust</a>.</p><p>Если в вашем коде есть класс, где потоки координируются через ручные ожидания и уведомления, у вас уже есть кандидат на замену стандартной очередью. Начните с него.</p>]]></content:encoded>
    </item>
    <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>Go 1.27 находит утечки горутин в работающем сервисе через pprof</title>
      <link>https://tproger.ru/news/go-1-27-nahodit-utechki-gorutin-v-rabotayushhem-servise-cherez-pprof</link>
      <comments>https://tproger.ru/news/go-1-27-nahodit-utechki-gorutin-v-rabotayushhem-servise-cherez-pprof?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/go-1-27-nahodit-utechki-gorutin-v-rabotayushhem-servise-cherez-pprof</guid>
      <description><![CDATA[<p>Профиль goroutineleak в Go 1.27 находит горутины, навсегда заблокированные на каналах, Mutex, WaitGroup и Cond, в продакшене: как включить и что он не ловит.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/go-1-27-nahodit-utechki-gorutin-v-rabotayushhem-servise-cherez-pprof">Go 1.27 находит утечки горутин в работающем сервисе через pprof</a>»</p>]]></description>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 03 Sep 2026 01:46:41 GMT</pubDate>
      <content:encoded><![CDATA[<p>Команда Go 2 сентября <a href="https://go.dev/blog/goroutine-leak-profiles">рассказала</a> в официальном блоге о новом типе профиля goroutineleak, который вошёл в Go 1.27. Он находит горутины, навсегда заблокированные на каналах и примитивах пакета sync, и делает это на работающем продакшен-сервисе, без тестов и без остановки процесса. Профиль доступен через runtime/pprof и через стандартный HTTP-обработчик net/http/pprof по адресу /debug/pprof/goroutineleak.</p><p>Для тех, кто держит Go-сервисы в проде, это закрывает старую дыру в инструментах. Обычный goroutine-профиль показывает, сколько горутин сейчас заблокировано, но не отличает штатное ожидание от горутины, которая уже никогда не проснётся. Раньше такие утечки искали руками по стекам или ловили в тестах пакетом goleak; сам релиз Go 1.27 <a href="https://go.dev/blog/go1.27">вышел</a> 19 августа, а разбор механизма команда опубликовала только сейчас.</p><ul><li>Профиль goroutineleak входит в Go 1.27 и доступен через runtime/pprof и net/http/pprof (/debug/pprof/goroutineleak).</li><li>Ловит блокировки на отправке и приёме в канал, блокирующем select, Mutex, RWMutex, WaitGroup и Cond.</li><li>Не считает утечкой ожидание файлового и сетевого ввода-вывода, системных вызовов и самодельных спинлоков.</li><li>По словам команды Go, метод точный и почти не даёт ложных срабатываний; накладные расходы на память названы пренебрежимо малыми, худший случай для одного цикла GC оценён как O(n²).</li><li>В примере из блога профиль нашёл 116 зависших горутин на одной строке с отправкой в небуферизованный канал.</li></ul><h2>Что такое утечка горутины и почему её было трудно найти</h2><p>Утечка горутины по определению из блога Go: горутина заблокирована на операции, условие для продолжения которой больше никогда не наступит. Классический пример: воркеры пишут результаты в небуферизованный канал, а читатель вышел из функции по первой ошибке. Каждый следующий воркер зависает на ch &lt;- result навсегда, и чем дольше живёт процесс, тем больше таких горутин копится, растёт потребление памяти и нагрузка на сборщик мусора.</p><p>До Go 1.27 инструментов было три, и ни один не решал задачу для продакшена. goleak проверяет, не остались ли горутины после конкретного теста. Пакет synctest, появившийся в стандартной библиотеке Go 1.25, помогает тестировать конкурентный код с виртуальным временем. Обычный goroutine-профиль показывает заблокированные горутины, но не доказывает, что они не проснутся: всплеск нагрузки выглядит в нём так же, как утечка.</p><h2>Как профиль отличает утечку от штатной блокировки</h2><p>Идея, которую описывает автор поста Влад Сайок из команды Go, опирается на работу, которую сборщик мусора и так делает. GC вычисляет достижимость памяти от корней. Команда добавила к этому анализу горутины: горутина считается живой, если она не заблокирована на примитиве конкурентности или если примитив, на котором она ждёт, достижим из какой-нибудь живой горутины. Анализ стартует с незаблокированных горутин и распространяется по доступным им каналам и мьютексам. Всё, что осталось недостижимым после этого обхода, никто уже не разблокирует, значит, это утечка.</p><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-09-03/c958bdbf-595c-4ab4-894d-ff81b1255c95.webp" alt="Схема изменённого алгоритма маркировки сборщика мусора Go с учётом заблокированных горутин" /><figcaption>Схема изменённого алгоритма маркировки: горутины помечаются живыми вместе с достижимыми примитивами синхронизации. Источник: Go Blog</figcaption></figure><p>Команда Go утверждает, что механизм точный и «почти не даёт ложных срабатываний» (перевод редакции). Есть патологический случай: цепочка горутин, где каждая ждёт примитив, доступный только следующей. Для такой «гирлянды» проверка в худшем случае занимает O(n²) шагов за один цикл GC, поэтому в блоге советуют не включать сбор профиля постоянно, а снимать его периодически, например раз в четыре часа. Память на учёт горутин авторы называют пренебрежимо малой, а GC при этом продолжает работать параллельно с пользовательским кодом.</p><p>Разработка выросла из совместного исследования Орхусского университета, Университета Вашингтона в Сент-Луисе и Uber; академическую версию представили на конференции ASPLOS 2025.</p><h2>Что видно в профиле на живом примере</h2><p>В блоге разобран сервис, который раз в секунду запускает обработку десяти элементов и на пятом получает ошибку. Функция делает ранний return, оставшиеся воркеры зависают на отправке в канал. Программа подключает net/http/pprof и слушает localhost:6060; профиль снимают обычным способом:</p><p>Через несколько минут работы pprof показывает Total: 116 заблокированных горутин, и все они стоят на одной операции: отправке в канал ch. Исправление для примера тривиальное: сделать канал буферизованным на число воркеров, make(chan result, len(ws)), тогда воркеры допишут результаты и завершатся, даже если читатель ушёл.</p><h2>Что профиль не ловит</h2><ul><li>Ожидание файлового и сетевого ввода-вывода и системных вызовов утечкой не считается: горутина, зависшая на чтении из сокета, в профиль не попадёт.</li><li>Самодельные спинлоки и другие пользовательские механизмы блокировки не входят в гарантированный набор.</li><li>Горутина, которая по замыслу ждёт вечно на достижимом канале (например, фоновый слушатель), утечкой не считается, потому что канал достижим из живого кода.</li></ul><p>Кому новый профиль ничего не даст: сервисам, где горутины блокируются в основном на сети, а не на каналах, и проектам, которые ещё не перешли на Go 1.27. Профиль работает только в рантайме этой версии; для старых сборок остаются goleak и ручной разбор стеков.</p><h2>Как включить у себя</h2><ol><li>Обновить тулчейн до Go 1.27 (релиз от 19 августа 2026 года, <a href="https://go.dev/doc/go1.27">заметки к выпуску</a>) и пересобрать сервис.</li><li>Если net/http/pprof уже подключён, новый обработчик появится автоматически по пути /debug/pprof/goroutineleak; отдельной настройки не нужно.</li><li>Снимать профиль периодически, а не постоянно: команда Go предлагает интервал вроде четырёх часов из-за квадратичного худшего случая.</li><li>Смотреть в первую очередь на места с ранним return при ошибках, таймауты без select с контекстом и воркер-циклы, у которых читатель может уйти раньше писателей.</li></ol><p>Схемы GC и полный пример кода лежат в <a href="https://go.dev/blog/goroutine-leak-profiles">посте команды Go</a>. Из соседних новостей по инфраструктуре Go-сервисов на сайте есть разбор <a href="https://tproger.ru/news/kubernetes-1-37-chitaet-bolwie-kollekcii-iz-etcd-potokom-i-ekono">Kubernetes 1.37</a> и заметка о <a href="https://tproger.ru/news/tailscale-vypustila-tailcat-soedinit-dve-mawiny-cherez-nat-bez">tailcat от Tailscale</a>, написанном на Go.</p><p>Источники: <a href="https://go.dev/blog/goroutine-leak-profiles">Go Blog: Goroutine leak profiles</a>, <a href="https://go.dev/doc/go1.27">Go 1.27 Release Notes</a>, <a href="https://go.dev/blog/go1.27">Go Blog: Go 1.27 is released</a></p><p>Изображение на обложке: Go Authors, логотип Go</p>]]></content:encoded>
    </item>
    <item>
      <title>Tailscale выпустила tailcat: соединить две машины через NAT без аккаунта</title>
      <link>https://tproger.ru/news/tailscale-vypustila-tailcat-soedinit-dve-mawiny-cherez-nat-bez</link>
      <comments>https://tproger.ru/news/tailscale-vypustila-tailcat-soedinit-dve-mawiny-cherez-nat-bez?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Tproger]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/tailscale-vypustila-tailcat-soedinit-dve-mawiny-cherez-nat-bez</guid>
      <description><![CDATA[<p>Tailscale открыла tailcat, CLI и Go-пакет, который соединяет две машины за NAT через WireGuard и DERP без аккаунтов и tailnet. Как это работает, для чего годится, чем отличается от ngrok, SSH-туннелей и обычного Tailscale, как установить.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/tailscale-vypustila-tailcat-soedinit-dve-mawiny-cherez-nat-bez">Tailscale выпустила tailcat: соединить две машины через NAT без аккаунта</a>»</p>]]></description>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Сетевые протоколы]]></category>
      <category><![CDATA[Инструменты командной строки]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 01 Sep 2026 17:28:01 GMT</pubDate>
      <content:encoded><![CDATA[<p>Tailscale 31 августа <a href="https://tailscale.com/blog/tailcat">опубликовала</a> <b>tailcat</b>, открытый инструмент, который соединяет две машины, где бы они ни стояли, без регистрации в сервисе и без сети tailnet. Автор — Брэд Фицпатрик, создатель memcached и один из основателей Tailscale. Идея проста: взять из Tailscale только сетевую часть (WireGuard, обход NAT и релеи DERP) и выбросить всё, что требует аккаунта. Компания называет это «Tailscale без Tailscale, от Tailscale» (перевод редакции).</p><p>На практике это netcat для интернета: на одной машине запускаете tailcat в режиме ожидания и получаете одноразовый адрес-токен, на другой вызываете tailcat с этим адресом, и между ними появляется шифрованный двунаправленный канал. Сверху можно пустить SSH, передачу файлов или проброс порта. Для разового доступа к машине за NAT это заменяет и промежуточный сервер, и регистрацию в чужом сервисе.</p><ul><li>tailcat — CLI и Go-пакет github.com/tailscale/tailcat под лицензией BSD-3-Clause.</li><li>Использует WireGuard, NAT traversal и DERP-релеи Tailscale, но не control plane: аккаунты, вход и tailnet не нужны; IP-адреса внутри туннеля есть, но пользователю их знать не требуется.</li><li>Адрес машины — её публичный ключ с информацией о DERP-сервере для первого контакта, закодированный в строку с префиксом tc.</li><li>Сценарии: SSH на машину за NAT, передача файлов, временный доступ; есть экспериментальная браузерная демонстрация на WebAssembly.</li><li>Прототип под названием derpcat написан в сентябре 2023 года; обещаний стабильности API и CLI у проекта нет.</li></ul><h2>Как соединение работает без сервера-посредника</h2><p>В обычном Tailscale центральный сервер (control plane) раздаёт машинам ключи друг друга и координаты, по которым их искать. В tailcat этого посредника нет: всё, что нужно для соединения, упаковано в сам адрес. По описанию в блоге, это публичный ключ WireGuard плюс сведения о том, через какой DERP-релей к машине можно достучаться, если прямой путь через NAT не найдётся; строка начинается с tc и кодирует эти данные в base64. Получатель адреса знает и кому доверять, и где искать.</p><blockquote>No accounts, login flow, tailnets, or IP addresses.</blockquote><p>Дальше работает тот же механизм, что и в Tailscale: машины пытаются пробить NAT и соединиться напрямую, а если не выходит, трафик идёт через DERP-релей, зашифрованный концами так, что релей содержимого не видит. Релеи Tailscale публичные, и их можно заменить своим. Ни root, ни TUN-интерфейс, ни права администратора не нужны: tailcat работает в пространстве пользователя как обычная программа.</p><h2>Чем это отличается от ngrok, SSH-туннелей и самого Tailscale</h2><p>От <b>ngrok</b> и подобных сервисов tailcat отличается тем, что не выставляет ничего в публичный интернет: соединение получит только тот, у кого есть адрес, а адрес — это ключ. От <b>SSH-прыжков</b> через промежуточный сервер — тем, что промежуточный сервер не нужен вообще: DERP лишь помогает найти друг друга и при необходимости ретранслирует уже зашифрованные байты. От <b>Tailscale</b> — отсутствием всей управляющей части: нет списка устройств, ACL, MagicDNS, нет и постоянной сети, каждое соединение живёт само по себе.</p><p>Отсюда и границы применимости. tailcat хорош для разового доступа: подключиться к ноутбуку коллеги, забрать большой файл с домашней машины из офиса, дать подрядчику временный вход на стенд. Для постоянной сети между десятками серверов с правами доступа он не замена Tailscale или WireGuard-конфигу, и авторы этого не обещают: README прямо предупреждает, что инструмент бесплатный, но стабильность API и CLI не гарантируется.</p><h2>Как попробовать</h2><ul><li>Установка при наличии Go: go install github.com/tailscale/tailcat/cmd/tailcat@latest; готовые бинарники смотрите в релизах репозитория.</li><li>На принимающей стороне запустите tailcat в режиме прослушивания и скопируйте выданный адрес; на второй машине передайте этот адрес как аргумент.</li><li>Поверх канала поднимайте SSH или пробрасывайте порт; для передачи файлов подойдёт обычное перенаправление stdin и stdout, как с netcat.</li><li>Для закрытого контура поднимите собственный DERP-сервер: код релея открыт в репозитории Tailscale.</li><li>Браузерная демонстрация на WebAssembly лежит на GitHub Pages проекта и показывает, что канал можно открыть даже из вкладки.</li><li>Публичные DERP-релеи даны без SLA, с ограничением частоты запросов и лишь в нескольких регионах; для рабочих сценариев поднимите свой релей.</li></ul><h2>Контекст</h2><p>Первый прототип под именем derpcat Фицпатрик написал в сентябре 2023 года, публично проект показали после конференции TailscaleUp в августе 2026-го. Мотив компании понятен: чем больше людей знакомы с её сетевым стеком, тем проще им потом прийти за полноценным продуктом. Для разработчика это честная сделка: рабочий инструмент под BSD-лицензией без обязательств, но и без гарантий, что завтра его интерфейс не изменится.</p><p>Источники: <a href="https://tailscale.com/blog/tailcat">tailcat: Tailscale without Tailscale (блог Tailscale)</a>, <a href="https://github.com/tailscale/tailcat">Репозиторий tailscale/tailcat</a></p><p>Изображение на обложке: Tailscale</p>]]></content:encoded>
    </item>
    <item>
      <title>Rust, Go или Zig: как выбрать язык для высоконагруженного бэкенда в 2026 году</title>
      <link>https://tproger.ru/articles/rust-go-ili-zig-kak-vybrat-yazyk-dlya-vysokonagruzhennogo-bekend</link>
      <comments>https://tproger.ru/articles/rust-go-ili-zig-kak-vybrat-yazyk-dlya-vysokonagruzhennogo-bekend?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/rust-go-ili-zig-kak-vybrat-yazyk-dlya-vysokonagruzhennogo-bekend</guid>
      <description><![CDATA[<p>Сравниваем Rust, Go и Zig для высоконагруженных сервисов: производительность, сложность, экосистема и реальные кейсы миграции.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/rust-go-ili-zig-kak-vybrat-yazyk-dlya-vysokonagruzhennogo-bekend">Rust, Go или Zig: как выбрать язык для высоконагруженного бэкенда в 2026 году</a>»</p>]]></description>
      <category><![CDATA[Языки программирования]]></category>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Rust]]></category>
      <category><![CDATA[Высокие нагрузки]]></category>
      <category><![CDATA[Бэкенд]]></category>
      <category><![CDATA[Архитектура приложений]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 09 Jul 2026 06:41:01 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если вы строите высоконагруженный бэкенд, выбор языка сегодня сводится к тройке: Rust, Go и Zig. У каждого — своя цена, своя скорость разработки и свои сценарии, в которых он выигрывает. Разбираем, как не ошибиться и когда смешивать их в одном проекте.</p><p>Речь пойдёт не о сравнении синтаксиса в вакууме, а о бэкенд-сервисах: API, шлюзах, обработке событий, парсинге данных и всём, что работает под нагрузкой. В статье — авторский взгляд на материал блога инженера Pooya Golchian, дополненный российским контекстом и поправками на реальное состояние экосистем.</p><p><b>Go</b> остаётся стандартным выбором для большинства микросервисов: быстрая компиляция, простота найма, огромная экосистема.</p><p><b>Rust</b> выигрывает там, где важны предельная задержка и контроль над памятью, но требует опытной команды и времени на обучение.</p><p><b>Zig</b> подходит для узких, критичных к производительности участков и для интеграции с существующим C-кодом, но экосистема пока незрелая.</p><p>В больших системах работает гибридный подход: Go для скорости разработки, Rust/Zig для горячих путей.</p><p>Мигрировать стоит только после профилирования: оптимизация без замеров обычно дороже, чем выгода.</p><h2>Почему именно эти три языка</h2><p>В 2026 году для нового backend-проекта по-прежнему можно взять Java, C#, Python или Node.js. Но если речь заходит о высоких нагрузках, низкой задержке и контроле над ресурсами, внимание смещается к трём игрокам.</p><ul><li><b>Rust</b> — язык с владением и заимствованием, дающий безопасность памяти без сборщика мусора.</li><li><b>Go</b> — язык с простой моделью конкурентности, статической линковкой и минималистичной философией.</li><li><b>Zig</b> — язык в духе C, но с современной системой сборки, comptime и явным управлением памятью.</li></ul><p>Все трое компилируются в нативный код, дают один бинарник на выходе и не требуют виртуальной машины. Именно это отличает их от Java, C# и Python на старте.</p><h2>Rust: максимум производительности, максимум сложности</h2><h3>Сильные стороны</h3><ul><li>Безопасность памяти на этапе компиляции — нет use-after-free, data races и большинства утечек.</li><li>Нулевая стоимость абстракций: высокоуровневый код часто компилируется так же эффективно, как ручной C.</li><li>Мощная модель конкурентности поверх tokio или async-std.</li><li>Зрелая экосистема: axum, actix-web, serde, sqlx.</li></ul><h3>Слабые стороны</h3><ul><li>Крутая кривая обучения: borrow checker требует перестройки мышления.</li><li>Долгая компиляция: полная пересборка крупного проекта занимает десятки секунд и минуты.</li><li>Меньше кадров на рынке, чем у Go или Java.</li><li>Итерации медленнее: каждая ошибка компилятора — это время на переделку.</li></ul><h3>Когда выбирать Rust</h3><p>Rust логичен, если вы строите инфраструктуру — прокси, базы данных, очереди, edge-сервисы — или если профилирование показывает, что горячий путь съедает CPU и память. Примеры из продакшена: Cloudflare использует Rust на edge, Discord переписал на Rust часть read-path сервисов.</p><h2>Go: скорость разработки в масштабе</h2><h3>Сильные стороны</h3><ul><li>Компиляция за секунды и один статический бинарник для деплоя.</li><li>Встроенные горутины и каналы — простая, но мощная конкурентность.</li><li>Отличная стандартная библиотека и быстрое тестирование через go test.</li><li>Большая база инженеров и проверенные практики в крупных компаниях.</li></ul><h3>Слабые стороны</h3><ul><li>Сборщик мусора может давать всплески задержек, хотя в последних версиях паузы сокращаются.</li><li>Меньше контроля над расположением памяти и размером структур.</li><li>Пиковая пропускная способность ниже, чем у Rust и Zig, на CPU-bound задачах.</li><li>Система типов и обработка ошибок минималистичны — кому-то этого достаточно, кому-то не хватает.</li></ul><h3>Когда выбирать Go</h3><p>Go — выбор по умолчанию для команд из 5–50 человек, которым нужно быстро запускать CRUD-сервисы, API-шлюзы и data pipeline. Uber, Google и Яндекс активно используют Go в микросервисах. Если главная метрика — time to market, а не последний процент производительности, Go обычно выигрывает.</p><h2>Zig: новый игрок с C-душой</h2><h3>Сильные стороны</h3><ul><li>Производительность уровня C с более современным синтаксисом и системой сборки.</li><li>comptime — выполнение кода на этапе компиляции для генерации оптимизированных структур.</li><li>Прямое взаимодействие с C без FFI-слоёв.</li><li>Маленькие быстрые бинарники и явное управление памятью.</li></ul><h3>Слабые стороны</h3><ul><li>Экосистема backend-фреймворков и библиотек пока существенно меньше, чем у Rust и Go.</li><li>Сообщество и количество инженеров на рынке ограничены.</li><li>Ручное управление памятью перекладывает ответственность на разработчика.</li><li>Некоторые части языка и стандартной библиотеки всё ещё эволюционируют.</li></ul><h3>Когда выбирать Zig</h3><p>Zig хорош, когда нужна C-производительность, но с более удобным инструментарием, или когда приходится интегрироваться с существующим C-кодом. Пример из продакшена: финансовая база данных TigerBeetle написана на Zig. Для универсального backend в 2026 году Zig ещё рано называть mainstream-выбором.</p><h2>Сравнение в цифрах</h2><p>Ниже — иллюстративные цифры из оригинального материала, полученные на AWS c7g.2xlarge (Graviton3). Относитесь к ним как к точке отсчёта, а не как к гарантии для вашего сервиса: в реальности большее значение имеют I/O, запросы к базе данных и сетевая задержка.</p><p><b>Бенчмарки:</b><br />HTTP throughput — Rust 892K req/s, Go 734K req/s, Zig 812K req/s.<br />JSON-сериализация — Rust 1,2M/s, Go 890K/s, Zig 1,1M/s.<br />Память на 10K соединений — Rust 45MB, Go 78MB, Zig 38MB.<br />Размер бинарника — Rust 8,2MB, Go 12,4MB, Zig 6,1MB.<br />Время компиляции с нуля — Rust 42s, Go 3,2s, Zig 18s.<br />P99 latency — Rust 2,1ms, Go 3,8ms, Zig 2,4ms.</p><h2>Реальные истории миграции</h2><h3>Discord: Go → Rust</h3><p>Discord переводил read-path сервисы с Go на Rust из-за пауз сборщика мусора, которые проявлялись в хвостовых задержках. По данным компании, throughput вырос в несколько раз, а tail latency снизилась. Ключевой вывод: мигрировать стоит только горячие пути, а не весь сервис целиком.</p><h3>Uber: Python → Go</h3><p>Uber мигрировал часть микросервисов с Python на Go, чтобы обойти ограничения GIL и упростить масштабирование. Переход занял годы, но зато проходил постепенно: Go-совместимость и простота языка позволяли быстро обучать команду.</p><h3>TigerBeetle: C++ → Zig</h3><p>TigerBeetle — финансовая база данных, ориентированная на корректность и производительность. Команда выбрала Zig, отказавшись от сложности C++ и сборщика мусора. comptime позволил генерировать специализированные структуры данных под задачу.</p><h2>Гибридная архитектура</h2><p>На практике редко выбирают один язык на весь проект. Гораздо чаще используют гибрид:</p><ul><li><b>API Gateway и CRUD</b> — Go: быстро писать, просто деплоить, легко искать людей.</li><li><b>Горячие пути</b> — Rust: низкая задержка и контроль над памятью.</li><li><b>Специализированные компоненты</b> — Zig: парсинг бинарных форматов, криптография, интеграция с C.</li></ul><p>Такая схема позволяет получить скорость разработки в большинстве сервисов и производительность там, где она действительно нужна. Главное — разделять систему по чётким границам и не превращать проект в зоопарк ради самого зоопарка.</p><h2>Что выбрать в 2026 году</h2><p>Выбор зависит от приоритетов команды и задачи:</p><ul><li><b>Нужна скорость разработки и лёгкий найм</b> — Go.</li><li><b>Нужна максимальная производительность и безопасность памяти</b> — Rust.</li><li><b>Нужна C-производительность с современной сборкой и интеграцией с legacy на C</b> — Zig.</li><li><b>Команда маленькая и сроки горят</b> — начинайте с Go, профилируйте, мигрируйте горячие пути при необходимости.</li><li><b>Строите базу данных, прокси или edge</b> — Rust становится очень сильным кандидатом.</li></ul><h2>FAQ</h2><h2>Выводы</h2><p>Rust, Go и Zig — не конкуренты в прямом смысле, а инструменты для разных условий. Go задаёт темп разработки, Rust отвечает за надёжность и производительность, Zig покрывает специализированные ниши. Лучшая стратегия для 2026 года — начать с Go, измерять, а затем точечно внедрять Rust или Zig там, где данные это оправдывают.</p><blockquote>Нет универсального лучшего языка — есть лучший язык для конкретной команды, задачи и бюджета на обучение.</blockquote><p><b>Источник:</b> <a href="https://pooya.blog/blog/rust-go-zig-high-performance-backend-2026/">Pooya Golchian — Rust vs Go vs Zig: High-Performance Backend Services in 2026</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как написать Kubernetes-оператор с нуля на Go: полный гайд</title>
      <link>https://tproger.ru/articles/kak-napisat-kubernetes-operator-s-nulya-na-go-polnyj-gajd</link>
      <comments>https://tproger.ru/articles/kak-napisat-kubernetes-operator-s-nulya-na-go-polnyj-gajd?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-napisat-kubernetes-operator-s-nulya-na-go-polnyj-gajd</guid>
      <description><![CDATA[<p>Разбираем паттерн Operator, создаём контроллер на Go с operator-sdk и учимся отслеживать дрейф конфигурации. Практический туториал — изучите пошагово.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-napisat-kubernetes-operator-s-nulya-na-go-polnyj-gajd">Как написать Kubernetes-оператор с нуля на Go: полный гайд</a>»</p>]]></description>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Docker]]></category>
      <category><![CDATA[Kubernetes]]></category>
      <category><![CDATA[Инфраструктура]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 08 Jun 2026 14:15:19 GMT</pubDate>
      <content:encoded><![CDATA[<p>Deployment умеет держать поды живыми, но не умеет мигрировать базу данных, управлять жизненным циклом приложений с данными (stateful-сервисов) и не защитит от случайного kubectl scale, который разрушит состояние. Для таких задач в экосистеме K8s существуют <b>операторы</b> — специальные контроллеры, которые кодируют человеческий опыт эксплуатации прямо в программный код.</p><p>Написать оператор можно на Go с помощью operator-sdk: сгенерировать скелет проекта, определить CRD, реализовать Reconcile и задеплоить в кластер. В этой статье разберём паттерн Operator и соберём рабочий оператор, который создаёт Deployment и Service по декларативной спецификации, отслеживает дрейф конфигурации и мгновенно откатывает несанкционированные изменения.</p><p>Оператор Kubernetes — это пользовательский контроллер, который расширяет API кластера собственными ресурсами (CRD) и непрерывно приводит фактическое состояние к желаемому.</p><p>Шаблон Reconcile — Observe → Create → Correct → Report — лежит в основе любого оператора: контроллер наблюдает, создаёт недостающее, исправляет отклонения и сообщает статус.</p><p>С помощью operator-sdk и kubebuilder-меток можно сгенерировать скелет проекта, CRD и RBAC-манифесты, не писать boilerplate вручную.</p><p>Owner Reference связывает дочерние ресурсы с родительским кастомным ресурсом (CR): при удалении WebApp Kubernetes автоматически уберёт связанные Deployment и Service.</p><p>Обновление статуса через Status().Update() изолировано от основного ресурса и предотвращает бесконечные циклы реконсиляции.</p><h2>Почему стандартных примитивов Kubernetes не хватает</h2><p>Kubernetes предоставляет мощный набор базовых абстракций: Pod, Deployment, StatefulSet, Service, Ingress. Они отлично справляются с запуском контейнеров, балансировкой трафика и базовым масштабированием. Однако эти примитивы агностичны к бизнес-логике приложения.</p><p>Представьте, что вам нужно развернуть production-grade кластер PostgreSQL. Помимо самих подов с базой, потребуются: инициализация репликации, управление резервными копиями, обновление версий без простоя, автоматическое переключение при отказе мастера. Всё это — операционная экспертиза, которую DevOps-инженеры накапливают годами. Оператор превращает эту экспертизу в автоматизированный контроллер, который круглосуточно следит за ресурсом и принимает решения.</p><p>Сегодня операторы де-факто стали стандартом для управления сложными stateful-приложениями в Kubernetes: от баз данных и брокеров сообщений до сервисных mesh и CI/CD-систем. Концепция была сформулирована инженерами CoreOS ещё в 2016 году, а сейчас поддерживается Cloud Native Computing Foundation (CNCF) как ключевой паттерн платформенной инженерии.</p><h2>Архитектура оператора: CRD, Reconciler и control loop</h2><p>Любой оператор состоит из двух ключевых компонентов:</p><ul><li><b>Custom Resource Definition (CRD)</b> — расширение API Kubernetes, которое определяет новый тип ресурса со своей схемой Spec (желаемое состояние) и Status (фактическое состояние).</li><li><b>Контроллер (Reconciler)</b> — программный цикл, который постоянно сравнивает Spec и Status, а затем выполняет действия для их сближения.</li></ul><p>Контроллер не работает по принципу «выполнил шаги и вышел». Вместо этого он реализует <b>control loop</b>: каждую итерацию можно запускать снова и снова — результат не сломается, потому что код сравнивает «что есть» с «что нужно» и корректирует только расхождения. Это критически важно, потому что события в распределённой системе приходят асинхронно, а состояние объекта могло измениться за время обработки предыдущего события.</p><h2>Создаём проект с operator-sdk</h2><p>Вручную писать весь boilerplate контроллера — неэффективно. Инструмент operator-sdk (основанный на Kubebuilder) генерирует стандартную структуру проекта Go, включая точку входа main.go, Makefile с целями для сборки и тестирования, а также инфраструктуру для управления CRD.</p><p>Инициализируем проект и создаём API с контроллером:</p><p>Флаг --resource сгенерирует Go-структуры, описывающие схему пользовательского ресурса. Флаг --controller создаст шаблон reconciler'а — файла, в котором мы будем писать логику управления.</p><h3>Определяем схему CRD</h3><p>Откроем api/v1/webapp_types.go. Здесь мы описываем два структурных блока: WebAppSpec — то, что задаёт пользователь в YAML-манифесте, и WebAppStatus — то, что оператор сообщает о текущем состоянии.</p><p>Важнейшая часть — kubebuilder-маркеры над основной структурой:</p><p>Маркер +kubebuilder:subresource:status сообщает Kubernetes, что для этого ресурса нужен отдельный endpoint /status. Без него любое обновление статуса будет восприниматься API-сервером как изменение всего объекта, что вызовет каскадную реконсиляцию и может привести к бесконечному циклу.</p><p>Маркеры +kubebuilder:printcolumn настраивают вывод команды kubectl get webapps: вместо голого имени ресурса пользователь увидит фазу, желаемое и доступное количество реплик.</p><h2>Reconciler: сердце оператора</h2><p>Файл internal/controller/webapp_controller.go содержит функцию Reconcile — точку входа в control loop. Перед ней размещаются RBAC-маркеры, которые генерируют манифесты прав доступа при выполнении make manifests:</p><p>Без этих маркеров оператор не получит прав на чтение и запись стандартных ресурсов Deployment и Service, и при запуске в кластере упадёт с ошибкой доступа. Разберём функцию Reconcile по шагам.</p><h3>Шаг 1. Получение актуального состояния</h3><p>Reconciler получает не сам объект, а лишь его имя и пространство имён. Это архитектурное решение Kubernetes: между постановкой события в очередь и его обработкой объект мог измениться. Поэтому первое действие — всегда запросить свежую версию ресурса из API.</p><p>Здесь apierrors импортируется из пакета k8s.io/apimachinery/pkg/api/errors, а ctrl — из sigs.k8s.io/controller-runtime.</p><h3>Шаг 2. Реконсиляция Deployment</h3><p>Сначала проверяем, существует ли связанный Deployment. Если нет — создаём его через вспомогательную функцию deploymentForWebApp.</p><p>Вызов return ctrl.Result{Requeue: true}, nil ставит событие обратно в очередь: контроллер немедленно перезапустит Reconcile для того же объекта, чтобы продолжить с следующего шага. Это удобнее, чем ждать следующего внешнего события.</p><p>Вот как выглядит функция deploymentForWebApp:</p><p>Owner Reference — это механизм garbage collection в Kubernetes. Когда пользователь удаляет ресурс WebApp, кластер автоматически удалит все дочерние объекты, на которые ссылается поле ownerReferences. Без этой связи после удаления кастомного ресурса в кластере останутся «зомби»-поды и сервисы.</p><h3>Шаг 3. Обнаружение дрейфа конфигурации</h3><p>Если Deployment уже существует, мы не просто идём дальше — сравниваем желаемое и фактическое состояние. Это и есть то, что отличает оператор от одноразового скрипта.</p><p>Представьте, что кто-то из команды в обход оператора выполнил следующую команду или подменил образ на уязвимую версию. Оператор мгновенно фиксирует расхождение и принудительно возвращает ресурс к значениям, заданным в WebApp.Spec.</p><h3>Шаг 4. Реконсиляция Service</h3><p>С вычислительным слоем разобрались — теперь нужен сетевой доступ. Логика полностью идентична: проверяем наличие Service, создаём при отсутствии, устанавливаем Owner Reference. Для локального тестирования в Minikube используем тип NodePort.</p><p>Вспомогательная функция serviceForWebApp строит объект Service с нужными селекторами и портами:</p><h3>Шаг 5. Обновление статуса</h3><p>Последний шаг — сообщить пользователю текущее состояние приложения через status subresource. Здесь критически важно использовать именно r.Status().Update(), а не r.Update().</p><p>Разделение основного endpoint ресурса и subresource /status — фундаментальное свойство Kubernetes. Оно гарантирует, что обновление статуса не триггерит новое событие изменения ресурса и, соответственно, не запускает бесконечную реконсиляцию.</p><h2>Тестирование: как проверить, что оператор работает</h2><p>Для локального тестирования подойдёт Minikube. Запускаем оператор в одном терминале, а в другом — создаём кастомный ресурс.</p><p>Проверяем, что оператор создал инфраструктуру и отчитался о статусе:</p><h2>Демонстрация: откат несанкционированных изменений</h2><p>Главная ценность оператора — самовосстановление. Сымитируем вмешательство: масштабируем Deployment в обход кастомного ресурса.</p><p>Мгновенно в логах контроллера появляется сообщение:</p><p><b>Лог оператора:</b><br />INFO  Drift detected! Updating Deployment  {"DesiredReplicas": 3, "ActualReplicas": 10}</p><p>А через несколько секунд избыточные поды начинают завершаться:</p><p>В это время статус WebApp отражает промежуточное состояние Scaling, а после полного схождения — автоматически переключается обратно на Running.</p><h2>Когда операторы необходимы, а когда избыточны</h2><p>Не каждому приложению нужен собственный оператор. Для stateless-сервисов, которые достаточно описать парой манифестов Deployment + Service, оператор будет накладным расходом. Однако есть категории систем, где без оператора не обойтись:</p><ul><li><b>Базы данных</b> — PostgreSQL, MySQL, MongoDB, etcd: репликация, бэкапы, обновления, failover.</li><li><b>Брокеры сообщений</b> — Kafka, RabbitMQ, NATS: управление партициями, топиками, кластерной топологией.</li><li><b>Сетевые компоненты</b> — Ingress-контроллеры, service mesh: динамическая маршрутизация и политики безопасности.</li><li><b>CI/CD и GitOps</b> — Tekton, Argo CD: оркестрация пайплайнов и синхронизация состояния кластера с репозиторием.</li></ul><p>В российской инфраструктурной практике операторы активно используются в Managed Kubernetes от крупных облачных провайдеров. Например, в Яндекс Облаке операторы лежат в основе managed-сервисов баз данных, обеспечивая автоматизацию резервного копирования, мониторинга и масштабирования.</p><h2>Выводы</h2><p>Паттерн Operator — это не просто модное слово в экосистеме Kubernetes, а проверенный подход к автоматизации эксплуатации сложных приложений. Вместо того чтобы полагаться на runbook'и и ручные действия инженеров, оператор кодирует операционную экспертизу в программу, которая работает круглосуточно, не устаёт и не забывает проверить важный шаг.</p><p>В этой статье мы прошли полный путь: от генерации скелета проекта через operator-sdk до работающего контроллера, который создаёт инфраструктуру, отслеживает дрейф конфигурации и автоматически восстанавливает желаемое состояние. Ключевые навыки — понимание асинхронной природы control loop, правильное использование Owner Reference и изолированное обновление статуса — применимы далеко за рамками Kubernetes.</p><blockquote>Оператор — это не магия, а дисциплина. Каждая итерация Reconcile — это честный вопрос: «Что должно быть?» против «Что есть сейчас?». Ответить на него правильно — значит построить надёжную систему.</blockquote><p>Полный код проекта доступен в репозитории автора оригинального туториала: <a href="https://github.com/SandeshOjha06/k8-operator">SandeshOjha06/k8-operator</a>. Если вы планируете развиваться в направлении platform engineering или SRE, умение писать и отлаживать собственные контроллеры станет серьёзным конкурентным преимуществом.</p><p><b>Источники:</b></p><ul><li><a href="https://dev.to/sandeshojha/building-a-kubernetes-operator-from-scratch-with-operator-sdk-576k">Building a Kubernetes Operator from Scratch with Operator SDK</a> — оригинальный туториал Сандеша Оджха.</li><li><a href="https://kubernetes.io/docs/concepts/extend-kubernetes/operator/">Kubernetes Operators</a> — официальная документация Kubernetes.</li><li><a href="https://sdk.operatorframework.io/">Operator SDK</a> — фреймворк для разработки операторов.</li><li><a href="https://book.kubebuilder.io/">The Kubebuilder Book</a> — руководство по построению Kubernetes API и контроллеров.</li></ul>]]></content:encoded>
    </item>
    <item>
      <title>IPv6-зоны в URL: почему Go падает на fe80::%eth0 и как это чинить</title>
      <link>https://tproger.ru/articles/ipv6-zony-v-url-pochemu-go-padaet-na-fe80-eth0-i-kak-eto-chinit</link>
      <comments>https://tproger.ru/articles/ipv6-zony-v-url-pochemu-go-padaet-na-fe80-eth0-i-kak-eto-chinit?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/ipv6-zony-v-url-pochemu-go-padaet-na-fe80-eth0-i-kak-eto-chinit</guid>
      <description><![CDATA[<p>Разбираем, как IPv6 link-local адреса с зонами ломают парсинг URL в Go, nginx и Python. Почему % нужно кодировать как %25 по RFC 6874 с 2013 года. Узнайте, как правильно собирать URL и не сломать продакшен.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/ipv6-zony-v-url-pochemu-go-padaet-na-fe80-eth0-i-kak-eto-chinit">IPv6-зоны в URL: почему Go падает на fe80::%eth0 и как это чинить</a>»</p>]]></description>
      <category><![CDATA[Интернет]]></category>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Языки программирования]]></category>
      <category><![CDATA[Сетевые протоколы]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 05 Jun 2026 12:56:04 GMT</pubDate>
      <content:encoded><![CDATA[<p>В URL с IPv6 link-local адресами символ % зоны интерфейса нужно кодировать как %25 — иначе парсер Go выбросит ошибку. Если вы пишете сервис, который ходит по локальной сети через IPv6, и ловите странную ошибку парсинга URL, скорее всего, вы столкнулись с одним из самых неочевидных граничных случаев современной работы с сетями.</p><p>В IPv6 каждый сетевой интерфейс получает <b>link-local адрес</b> из диапазона fe80::/10 (первые 10 бит фиксированы, остальное — адрес интерфейса). Если у машины два интерфейса — например, Ethernet и Wi-Fi — оба будут в одном и том же префиксе. Вопрос: как операционная система понимает, к какому именно интерфейсу адресовать пакет? Ответ — <b>зоны (scopes)</b>.</p><p>В IPv6 зона интерфейса записывается через %: fe80::4%eth0. Это нужно, чтобы различать link-local адреса на разных сетевых интерфейсах.</p><p>В URL зона попадает внутрь квадратных скобок: [fe80::4%eth0]:80. Но символ % в URL — это начало percent-encoding, поэтому парсер ломается.</p><p>Решение — экранировать % как %25: [fe80::4%25eth0]:80. Это поведение зафиксировано в RFC 6874.</p><p>Проблема затрагивает не только Go, но и nginx, Python requests и браузеры. Поддержка зон в HTTP-клиентах остаётся фрагментарной.</p><h2>Как зоны работают в IPv6</h2><p>Зона (или scope ID) — это механизм, позволяющий ядру отличать адреса из пересекающихся диапазонов. Для link-local адресов fe80::/10 он критичен: без него роутинговая таблица не поймёт, через какой интерфейс отправлять трафик.</p><p>Формат зоны зависит от ОС. В Linux это имя интерфейса — eth0, wlan0, ens192. В Windows — числовой идентификатор интерфейса. Полный адрес выглядит так:</p><p>Квадратные скобки отделяют хост от порта — иначе двоеточия IPv6-адреса спутаются с разделителем порта.</p><h2>Конфликт зон и URL</h2><p>Теперь вставим этот адрес в URL. На первый взгляд всё просто:</p><p>Но попробуем распарсить его в Go:</p><p>Получаем ошибку:</p><p>Что произошло? В URL любой символ, не входящий в разрешённый набор, должен быть <b>percent-encoded</b>. Пробел превращается в %20, кириллица — в последовательности вроде %D0%90. Парсер видит %e и пытается декодировать его как hex-последовательность. et — не валидный байт, поэтому URL отклоняется.</p><h2>Почему Go падает и как это чинить</h2><p>С точки зрения стандарта Go ведёт себя корректно. RFC 3986 определяет URL-грамматику, а RFC 6874 специально дополняет её для IPv6-зон: символ % перед zone ID должен быть сам закодирован как %25.</p><p>Правильный URL выглядит так:</p><p>Проверяем в Go:</p><p>Вывод:</p><p>Go корректно декодирует %25 обратно в % при извлечении хоста. То есть библиотека поддерживает RFC 6874, но <b>требует от вызывающего кода заранее закодировать зону</b>.</p><h2>RFC 6874: это не баг, а фича</h2><p>В RFC 6874 формально описан синтаксис IPv6-адресов с зонами в литералах URL. Ключевой фрагмент:</p><p>То есть зона записывается не как %eth0, а как %25eth0. Это выглядит ужасно с точки зрения пользовательского опыта, но таково решение стандартизации: совместимость с существующей URL-грамматикой важнее эргономики.</p><blockquote>Наша индустрия меня удивляет. Стандарт говорит: чтобы записать обычный символ процента в адресе, нужно его самого закодировать процентами. Это ужасно, но, похоже, это граничный случай, который касается не только Go.</blockquote><p>И действительно, та же проблема есть и в других инструментах:</p><ul><li><b>nginx</b> — <a href="https://trac.nginx.org/nginx/ticket/623">тикет #623</a>, созданный более десяти лет назад; проблема отсутствия поддержки link-local адресов с зонами до сих пор актуальна.</li><li><b>Python requests</b> — <a href="https://github.com/psf/requests/issues/6808">issue #6808</a>: даже при ручном кодировании % как %25 библиотека некорректно обрабатывает IPv6-зоны в URL, потому что urllib3 декодирует %25 обратно в %.</li><li><b>Браузеры</b> — draft Schinazi объясняет, почему зоны ломают концепцию origin, и рекомендует использовать mDNS вместо прямого указания link-local адресов в URI.</li></ul><h2>Что делать разработчику</h2><p>Если ваше Go-приложение работает с локальными IPv6-адресами — например, подключается к сервисам в Docker-сети, IoT-устройствам или внутренним API через link-local — учитывайте следующее:</p><ol><li>Перед передачей IPv6-адреса с зоной в url.Parse всегда экранируйте % как %25.</li><li>Используйте net.JoinHostPort для сборки host:port — он корректно оборачивает IPv6 в скобки, но не кодирует зону. Дополнительное кодирование остаётся на вас.</li><li>Если адрес приходит от пользователя, валидируйте его до парсинга: зона должна содержать только допустимые символы (имя интерфейса в Linux, числовой ID в Windows).</li><li>Тестируйте на реальных интерфейсах с разными зонами, чтобы убедиться, что кодирование работает корректно в вашей среде.</li></ol><p><b>На заметку:</b><br />Если вы пишете HTTP-клиент для embedded-устройств или промышленных контроллеров, которые общаются через link-local IPv6, ручное кодирование зоны — не костыль, а необходимость. Большинство библиотек не делают этого автоматически.</p><h2>FAQ</h2><h2>Выводы</h2><p>IPv6-зоны — редкий, но живучий граничный случай. Если вы пишете сетевой код на Go, который должен работать в гетерогенных средах — Docker, Kubernetes, embedded-системы, промышленные сети — знайте, что fe80::1%eth0 в URL превращается в fe80::1%25eth0. Это не баг парсера, а требование стандарта RFC 6874.</p><p>Инкапсулируйте кодирование зоны во вспомогательную функцию и всегда прогоняйте IPv6-адреса через неё перед сборкой URL. Экономия пяти минут сейчас обернётся часом отладки в продакшене, когда сервис внезапно не сможет достучаться до соседнего контейнера по link-local.</p><p><b>Источники:</b><br />• <a href="https://xeiaso.net/notes/2026/ipv6-zones-go-url/">Xe Iaso — IPv6 zones in Go URLs</a><br />• <a href="https://datatracker.ietf.org/doc/html/rfc6874">RFC 6874 — Representing IPv6 Zone Identifiers in Address Literals and Uniform Resource Identifiers</a><br />• <a href="https://datatracker.ietf.org/doc/html/draft-schinazi-httpbis-link-local-uri-bcp-03">draft-schinazi-httpbis-link-local-uri-bcp-03 — IPv6 Link-Local URIs</a></p>]]></content:encoded>
    </item>
    <item>
      <title>GitHub Dungeons: рогалик из вашего репозитория с Copilot CLI</title>
      <link>https://tproger.ru/articles/github-dungeons-vaw-repozitorij-stanovitsya-rogalikom-s-pomoshhyu</link>
      <comments>https://tproger.ru/articles/github-dungeons-vaw-repozitorij-stanovitsya-rogalikom-s-pomoshhyu?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/github-dungeons-vaw-repozitorij-stanovitsya-rogalikom-s-pomoshhyu</guid>
      <description><![CDATA[<p>Разработчик GitHub написал рогалик на Go с помощью Copilot CLI: BSP из хеша коммита, команды /delegate и /yolo, pre-commit хук со ставками. Попробуйте.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/github-dungeons-vaw-repozitorij-stanovitsya-rogalikom-s-pomoshhyu">GitHub Dungeons: рогалик из вашего репозитория с Copilot CLI</a>»</p>]]></description>
      <category><![CDATA[Open Source]]></category>
      <category><![CDATA[Разработка игр]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 14 May 2026 11:55:06 GMT</pubDate>
      <content:encoded><![CDATA[<p>Ваш последний коммит теперь определяет планировку подземелья. Сотрудник GitHub Ли Рейли (Lee Reilly) принял участие в GitHub Copilot CLI Challenge и написал <b>GitHub Dungeons</b> — расширение для GitHub CLI, которое превращает любой репозиторий в рогалик прямо в терминале. Уровни генерируются на основе хеша коммита, враги случайно заполняют коридоры, а выход спрятан за пятью уровнями процедурно созданных комнат.</p><p>Проект написан на Go — языке, с которым автор раньше почти не работал. Весь процесс разработки прошёл через GitHub Copilot CLI: вместо того чтобы разбираться в деталях синтаксиса незнакомого языка, можно было описать нужное поведение и получить работающий код.</p><p><b>GitHub Dungeons</b> — расширение gh extension, которое генерирует рогалик из вашего репозитория прямо в терминале.</p><p><b>Процедурная генерация</b> работает через Binary Space Partitioning (BSP), засеянный SHA последнего коммита — один и тот же код всегда даёт одно и то же подземелье.</p><p><b>Команда /delegate</b> в Copilot CLI передаёт задачу облачному агенту, который работает асинхронно и открывает готовый PR.</p><p><b>«Опасный режим»</b>: можно настроить pre-commit хук, который удалит все несохранённые изменения, если проиграть.</p><p>Установка одной командой: gh extension install leereilly/gh-dungeons.</p><h2>Что такое GitHub Dungeons</h2><p>GitHub Dungeons — это терминальная игра в жанре рогалик, где каждый уровень генерируется на основе вашей кодовой базы. Комнаты, коридоры и враги строятся из структуры репозитория и отрисовываются прямо в консоли. Навигация — стрелками, WASD или Vim-клавишами. Цель — найти скрытый выход, преодолев пять уровней с нарастающей сложностью.</p><p>Рогалики (roguelikes) ведут историю с игры Rogue 1980-х — терминальных приключений, где каждое прохождение генерировало новые подземелья, а смерть означала начало сначала (permadeath). GitHub Dungeons обращается к этой традиции, добавляя инженерный твист: ваш последний коммит задаёт seed генерации — один и тот же код всегда даёт одно и то же подземелье, но каждое изменение перестраивает его.</p><h2>Как репозиторий превращается в подземелье</h2><p>Генерация уровней построена на алгоритме Binary Space Partitioning (BSP) — классическом методе процедурной генерации карт в играх. В качестве seed используется SHA последнего коммита репозитория, что обеспечивает детерминированность: один коммит — одно подземелье. Изменился код — изменилась карта.</p><p>Процедурная генерация (или procgen) — это создание контента алгоритмически, а не вручную. Вместо того чтобы проектировать одно подземелье, вы проектируете систему, которая генерирует их бесконечно. Именно это даёт рогаликам высокую реиграбельность: каждое прохождение структурно отличается от предыдущего.</p><h3>Как работает Binary Space Partitioning</h3><p>BSP — это рекурсивное разбиение пространства на прямоугольные регионы. Алгоритм прост в объяснении, но даёт именно тот баланс между структурой и хаосом, который нужен рогаликам:</p><ol><li>Начало. Весь уровень — один большой прямоугольник.</li><li>Разбиение. Пространство делится на два региона (горизонтально или вертикально). Каждый регион снова делится. И снова.</li><li>Остановка. Разбиение прекращается, когда регион становится слишком маленьким для комнаты.</li><li>Комнаты. Каждый конечный регион становится комнатой. Позиция и размер слегка рандомизируются — чтобы карта не выглядела как сетка.</li><li>Коридоры. Алгоритм обходит дерево разбиений в обратном порядке и соединяет соседние комнаты L-образными коридорами.</li><li>Результат. Карта выглядит спроектированной, хотя создана алгоритмически. Все комнаты достижимы, нет тупиков.</li></ol><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-05-14/37595259-b651-48fb-90df-8723e5b05370.webp" alt="" /><figcaption>Шаг 1. Старт: всё подземелье — один прямоугольник.</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-05-14/6f46dad9-30d5-42bd-b38e-6be09284526f.webp" alt="" /><figcaption>Шаг 2. Первое разбиение — на две зоны.</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-05-14/e7c426de-384e-4f5b-841d-a2c93d5a90b4.webp" alt="" /><figcaption>Шаг 3. Рекурсивно: одна из зон разбита ещё раз.</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-05-14/e9914d85-103a-4801-9463-77ba9cf593d0.webp" alt="" /><figcaption>Шаг 4. После нескольких проходов — шесть листовых регионов.</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-05-14/b8f23b77-bdcf-48c8-99d4-877ca4f787db.webp" alt="" /><figcaption>Шаг 5. Каждый регион превращается в комнату — с небольшим рандомом по размеру.</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-05-14/4c632fc4-3b1c-4219-97f0-ad37b629998f.webp" alt="" /><figcaption>Шаг 6. Соседние комнаты пока не соединены.</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-05-14/250f28d8-6a7e-4bb2-bf65-cdf13d2848fe.webp" alt="" /><figcaption>Шаг 7. Сиблинги по дереву связываются L-образными коридорами.</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-05-14/0b89dd5b-a23e-417d-8df4-78f1ebd5c606.webp" alt="" /><figcaption>Шаг 8. Финальный layout: структурно, но каждый раз разный.</figcaption></figure><p>BSP решает две главные проблемы процедурной генерации: чистый рандом даёт хаотичные карты, регулярные сетки — предсказуемые. BSP находит баланс: структурированный хаос, где каждый забег выглядит по-разному, но остаётся проходимым.</p><h2>Разработка с GitHub Copilot CLI</h2><p>Ли Рейли написал GitHub Dungeons на Go — языке, которым он не пользовался регулярно. Copilot CLI позволил сосредоточиться на поведении игры, а не на синтаксисе: вместо того чтобы вспоминать, как работают горутины, можно было описать нужное поведение и получить работающий код.</p><h3>Команда /delegate: асинхронный агент</h3><p>Ключевым инструментом в разработке стала команда /delegate. В отличие от обычного автодополнения, /delegate передаёт задачу облачному агенту Copilot, который работает асинхронно. Разработчик описывает задачу на естественном языке, запускает делегирование и может заниматься чем-то другим. Когда агент завершает работу, он открывает pull request с результатами.</p><p>Например, команда /delegate с описанием задачи на естественном языке вернула готовую реализацию прогрессии сложности в виде PR. Автор просмотрел результат, подправил баланс и влил изменения. Тот же подход использовался для читкодов, системы туман войны и документации.</p><blockquote>Работа с Copilot (особенно через /delegate) — это как иметь армию NPC, готовых делать всё, что я скажу.</blockquote><h3>Команда /yolo: живёшь только раз</h3><p>Для проекта о рогалике команда /yolo оказалась особенно уместной: это алиас для /allow-all, который разрешает Copilot CLI выполнять все действия без дополнительных подтверждений. «You only live once» — именно это слоган permadeath-механики рогаликов. В разработке /yolo ускоряет итерации: не нужно подтверждать каждое действие агента.</p><p>Copilot также сгенерировал «dungeon scribe» — вспомогательного агента, который добавил документацию и ASCII-диаграммы, объясняющие генерацию подземелий. Это органично вписалось в стиль терминального рогалика.</p><h2>Установка и игра</h2><p>Для запуска нужен установленный GitHub Copilot CLI. Расширение устанавливается одной командой:</p><p>После установки запустите игру в директории любого репозитория:</p><p>Управление: стрелки, WASD или Vim-клавиши (hjkl). Цель — найти скрытую дверь и сбежать через пять уровней, сражаясь с врагами и собирая зелья здоровья. Автоатака, туман войны, счётчик убийств и уровней входят в комплект. Остальные возможности придётся обнаружить самостоятельно.</p><h2>Опасная зона: pre-commit хук с ставками</h2><p>Для тех, кто хочет испытать настоящий permadeath в духе рогаликов, автор предлагает привязать игру к git-коммитам. Pre-commit хук запускает GitHub Dungeons перед каждым коммитом: если проигрываете — все несохранённые изменения удаляются.</p><p><b>Внимание:</b> не устанавливайте этот хук, если не понимаете последствий. Поражение в игре ведёт к безвозвратной потере всех незакоммиченных изменений. Редакция GitHub прямо предупреждает: ответственность за последствия несёт автор хука, а не GitHub.</p><h2>Выводы</h2><p>GitHub Dungeons — эксперимент, который демонстрирует несколько интересных вещей одновременно. Во-первых, Copilot CLI меняет паттерн разработки: когда агент берёт на себя незнакомый синтаксис и рутину, разработчик остаётся в режиме дизайнера механик, а не кодировщика. Для этого рогалика это означало итерации по балансу, тайным кодам и пасхалкам вместо бесконечной отладки Go-специфики. Во-вторых, классические алгоритмы вроде BSP решают современные задачи: детерминированный seed из SHA коммита — это не случайность, а осмысленная связь между состоянием кода и состоянием игры. Каждый мердж меняет карту.</p><p>Попробовать GitHub Dungeons можно в любом репозитории: <a href="https://github.com/leereilly/gh-dungeons">github.com/leereilly/gh-dungeons</a>. Оригинальный разбор от автора — <a href="https://github.blog/ai-and-ml/github-copilot/dungeons-desktops-building-a-procedurally-generated-roguelike-with-github-copilot-cli/">на GitHub Blog</a>. Установите, запустите gh dungeons в своём репозитории — и посмотрите, каким подземельем стал ваш последний коммит.</p>]]></content:encoded>
    </item>
    <item>
      <title>Wake-on-LAN: как включить компьютер по сети и написать WOL-инструмент на Go</title>
      <link>https://tproger.ru/translations/wake-on-lan-kak-vklyuchit-kompyuter-po-seti-i-napisat-wol-instr</link>
      <comments>https://tproger.ru/translations/wake-on-lan-kak-vklyuchit-kompyuter-po-seti-i-napisat-wol-instr?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Стребков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/wake-on-lan-kak-vklyuchit-kompyuter-po-seti-i-napisat-wol-instr</guid>
      <description><![CDATA[<p>Разбираем Wake-on-LAN изнутри: Magic Packet, UDP-отправка, ограничения протокола и рабочая реализация на Go. Напишите свой WOL-инструмент за 30 строк кода.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/wake-on-lan-kak-vklyuchit-kompyuter-po-seti-i-napisat-wol-instr">Wake-on-LAN: как включить компьютер по сети и написать WOL-инструмент на Go</a>»</p>]]></description>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Сетевые протоколы]]></category>
      <category><![CDATA[Практика]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Системное администрирование]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 16 Apr 2026 13:30:04 GMT</pubDate>
      <content:encoded><![CDATA[<p>Wake-on-LAN (WOL) — сетевой протокол, который позволяет включить любой компьютер в локальной сети одной командой, без физического доступа к кнопке питания. Удобно, когда нужно срочно добраться до файла на выключенной рабочей машине или запустить ночные обновления на сотне серверов, не обходя каждый.</p><ul><li>Wake-on-LAN — сетевой протокол для удалённого включения компьютера через Magic Packet.</li><li>Magic Packet: 6 байт 0xFF + MAC-адрес, повторённый 16 раз.</li><li>Пакет отправляется по UDP на широковещательный адрес 255.255.255.255, де-факто стандарт — порт 9.</li><li>Ограничения: только в пределах одной сети или VLAN, только по Ethernet, нет подтверждения доставки.</li><li>Реализуем собственный WOL-инструмент на Go с нуля.</li></ul><h2>Что такое Wake-on-LAN</h2><p>Wake-on-LAN (WOL) — протокол канального уровня, который будит компьютер или сервер, когда сетевой интерфейс получает специальный Magic Packet. Сетевая карта с активированной функцией WOL постоянно прослушивает широковещательный трафик даже когда компьютер выключен, но подключён к сети. При обнаружении Magic Packet она посылает сигнал на BIOS, и система загружается.</p><p>Для работы WOL необходимо, во-первых, включить поддержку в BIOS или UEFI (обычно называется Wake-on-LAN или Power On by PCI-E); во-вторых, активировать её в операционной системе для нужного сетевого адаптера. На Linux это делается одной командой:</p><p>Здесь g — режим MagicPacket. Проверить текущее состояние — ethtool eth0 | grep Wake. На Windows нужную опцию ищите в «Свойства сетевого адаптера → Управление электропитанием → Разрешить этому устройству выводить компьютер из ждущего режима».</p><h2>Как устроен Magic Packet</h2><p>Magic Packet — бинарный фрейм с жёстко заданной структурой. Сначала идёт синхропоследовательность: 6 байт 0xFF. Эти байты сигнализируют сетевой карте о начале нового фрейма.</p><p>Сразу после синхропоследовательности — MAC-адрес целевой машины, повторённый 16 раз без пробелов и разделителей. Именно по нему сетевая карта понимает, что пакет адресован ей. В итоге Magic Packet занимает 102 байта: 6 байт синхропоследовательности плюс 6 байт MAC × 16 повторений.</p><p>Пример реального Magic Packet с MAC-адресом 12:34:56:78:9a:bc, захваченного в Wireshark:</p><p>Некоторые реализации WOL поддерживают опциональный пароль в конце пакета — для защиты от несанкционированного включения. Механизм SecureOn использует 6 байт, AMD-спецификация допускает 4 байта. Однако не каждый BIOS поддерживает эту функцию.</p><h2>Как отправить Magic Packet</h2><p>Magic Packet может быть передан поверх любого сетевого протокола — сетевой карте достаточно найти нужную последовательность байт в полученном фрейме. На практике пакет отправляют как UDP-датаграмму на широковещательный адрес.</p><p>Для IPv4 используется широковещательный адрес 255.255.255.255 — он охватывает всю локальную сеть или сегмент. IPv6 вместо broadcast использует multicast. Де-факто стандарт для порта назначения — 9 (Discard Protocol), реже используют 7 или 0.</p><h2>Ограничения Wake-on-LAN</h2><p>Прежде чем настраивать WOL в продакшне, важно понять его ограничения:</p><ul><li><b>Только одна сеть или VLAN.</b> Magic Packet не маршрутизируется — получить его может лишь устройство в той же локальной сети или VLAN, что и отправитель. Для удалённого включения через интернет нужен промежуточный узел в этой сети: VPN, Raspberry Pi или роутер с поддержкой WOL.</li><li><b>Нужен MAC-адрес.</b> WOL работает на канальном уровне, поэтому нельзя разбудить компьютер, зная только его IP-адрес.</li><li><b>Только проводной Ethernet.</b> Большинство Wi-Fi-адаптеров не поддерживают WOL. Исключение — устройства с поддержкой стандарта WoWLAN (Wake on Wireless LAN), но на практике их мало, и настройка требует совместимого драйвера.</li><li><b>Нет подтверждения доставки.</b> UDP — протокол без установления соединения, поэтому после отправки Magic Packet невозможно узнать, получил ли его компьютер и включился ли он.</li><li><b>Зависимость от BIOS.</b> Некоторые материнские платы пробуждаются только из состояний S3 или S4, но не из полного выключения S5. Проверяйте документацию к платформе.</li></ul><h2>Реализация на Go</h2><p>Напишем собственный WOL-инструмент на Go — одна из немногих задач, где стандартной библиотеки хватает полностью. Если хочется погрузиться в Go глубже, у нас есть <a href="https://tproger.ru/articles/sravnenie-golang-veb-frejmvorkov-2026-goda--top-5-luchwih-variant">обзор Golang-фреймворков 2026 года</a>. Нам понадобятся две функции: CreateMagicPacket для формирования пакета и SendMagicPacket для его отправки.</p><h3>CreateMagicPacket: формируем пакет</h3><p>Функция принимает MAC-адрес строкой и возвращает готовый байтовый срез или ошибку. Первым делом проверяем валидность MAC-адреса с помощью регулярного выражения:</p><p>После валидации убираем разделители из MAC-адреса, затем повторяем его 16 раз:</p><p>Объединяем синхропоследовательность с повторённым MAC-адресом и декодируем hex-строку в байтовый срез:</p><h3>SendMagicPacket: отправляем пакет</h3><p>Функция принимает Magic Packet ([]byte), IP-адрес назначения и порт. Сначала проверяем валидность IP через стандартную функцию net.ParseIP — в отличие от regex, она корректно обрабатывает и IPv4, и IPv6:</p><p>Открываем UDP-соединение через net.Dial. WOL не требует установления соединения — UDP идеально подходит: быстро, без handshake. Ключевое слово defer гарантирует закрытие соединения по завершении функции:</p><p>Отправляем Magic Packet в сеть через conn.Write. Если функция возвращает nil — пакет ушёл в сеть. Получил ли его компьютер и включился ли — WOL не сообщает, это ограничение протокола:</p><p>Полный рабочий код обеих функций и готовую утилиту командной строки можно найти на GitHub: <a href="https://github.com/xaner4/Gowakeup">xaner4/Gowakeup</a>. Типичный вызов после сборки — ./gowakeup -mac AA:BB:CC:DD:EE:FF.</p><h2>Выводы</h2><p>Wake-on-LAN — простой и элегантный протокол канального уровня. Всего 102 байта — и компьютер включается по сети без дополнительной инфраструктуры. Ограничения (только Ethernet, только локальная сеть, нет подтверждения) — следствие намеренной простоты протокола: он работает даже тогда, когда ОС не загружена. В отличие от устаревших сетевых стеков, которые <a href="https://tproger.ru/news/iz-linux-udalili-nebezopasnyj-setevoj-protokol----kotoryj-vse-eshhe-ispolzuetsya-v-windows-11">ядро Linux постепенно отбрасывает</a>, WOL остаётся в строю уже третье десятилетие.</p><p>Реализация на Go показывает, как стандартная библиотека net и базовые операции со строками позволяют собрать рабочий сетевой инструмент в нескольких десятках строк. Готовый проект: <a href="https://github.com/xaner4/Gowakeup">github.com/xaner4/Gowakeup</a>. Исходная статья: <a href="https://blog.xaner.dev/post/wake-on-lan/">blog.xaner.dev</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Полнотекстовый поиск на Go без Elasticsearch — гайд по Bleve</title>
      <link>https://tproger.ru/translations/polnotekstovyj-poisk-na-go-bez-elasticsearch---gajd-po-bleve</link>
      <comments>https://tproger.ru/translations/polnotekstovyj-poisk-na-go-bez-elasticsearch---gajd-po-bleve?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Михайлишин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/polnotekstovyj-poisk-na-go-bez-elasticsearch---gajd-po-bleve</guid>
      <description><![CDATA[<p>Bleve — встраиваемый полнотекстовый движок для Go. Разбираем кастомные маппинги, мультиязычные индексы, курсорную пагинацию и настройку Scorch для продакшена.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/polnotekstovyj-poisk-na-go-bez-elasticsearch---gajd-po-bleve">Полнотекстовый поиск на Go без Elasticsearch — гайд по Bleve</a>»</p>]]></description>
      <category><![CDATA[Лучшая практика]]></category>
      <category><![CDATA[Оптимизация]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sat, 28 Mar 2026 15:25:26 GMT</pubDate>
      <content:encoded><![CDATA[<p>Когда в проекте появляется задача полнотекстового поиска, первая мысль — поставить <a href="https://www.elastic.co/elasticsearch">Elasticsearch</a> или <a href="https://www.meilisearch.com/">Meilisearch</a>. Оба инструмента отлично справляются. Но что, если вы не хотите зависеть от внешнего сервиса — или вам нужен полный контроль над хранением и обработкой данных?</p><p>В Go для этого есть <a href="https://blevesearch.com/">Bleve</a> — файловая библиотека полнотекстового индексирования. Она умеет индексировать любые Go-структуры с разумными настройками по умолчанию, поддерживает встроенный язык запросов в стиле Google, работает с миллионами записей и не требует отдельного сервера.</p><p>В этой статье — практический гайд: от простого индекса до кастомных анализаторов, мультиязычного поиска, пагинации курсором и тонкой настройки производительности.</p><blockquote><b>Ключевые выводы</b><br /><br />- Bleve — встраиваемый полнотекстовый движок для Go: не нужен отдельный сервер, достаточно одной зависимости<br />- Кастомные маппинги позволяют настроить анализатор, стемминг и стоп-слова для каждого поля отдельно<br />- IndexAlias объединяет несколько индексов (например, по языкам) в один виртуальный — с единым интерфейсом поиска<br />- Курсорная пагинация через SearchAfter / SearchBefore работает стабильно даже при обновлении индекса между запросами<br />- Scorch-настройки (воркеры, размер сегментов, порог мёржа) критичны для производительности под нагрузкой</blockquote><h2>Создаём простой индекс</h2><p>Начнём с минимального примера. Два базовых действия — <b>индексирование</b> (сохранение документа для последующего поиска) и <b>запрос</b> (извлечение документов, отсортированных по релевантности).</p><p>Несколько важных деталей:</p><ul><li><b>bleve.New vs bleve.Open</b> — New создаёт новый индекс по указанному пути, Open открывает существующий. Паттерн из примера (сначала New, при ошибке — Open) — идиоматический способ обработки первого и повторных запусков.</li><li><b>NewIndexMapping()</b> — возвращает маппинг по умолчанию: текстовые поля токенизируются, приводятся к нижнему регистру и фильтруются через список стоп-слов английского языка.</li><li><b>Автоматическое обнаружение полей</b> — Bleve использует рефлексию для анализа структуры. Все экспортируемые поля автоматически токенизируются и становятся доступными для поиска.</li><li><b>Уникальные ID документов</b> — строковый идентификатор, передаваемый в Index, используется для обновлений и удалений. Повторный вызов Index с тем же ID заменяет документ.</li><li><b>SearchRequest.Fields</b> — по умолчанию Bleve возвращает только ID и релевантность. Укажите имена нужных полей или []string{"*"}, чтобы получить все.</li><li><b>hit.Score</b> — каждый результат содержит числовой показатель релевантности на основе BM25. Чем выше — тем точнее совпадение.</li></ul><h2>Кастомные маппинги полей</h2><p>Маппинг по умолчанию подходит для быстрого старта, но в реальных проектах нужен контроль над тем, как Bleve анализирует и хранит каждое поле. <b>Маппинг</b> определяет тип поля, анализатор для токенизации, необходимость хранения оригинального значения и включение в индекс.</p><p>Маппинги позволяют:</p><ul><li><b>Управлять токенизацией</b> — разбивать текст на термы по пробелам, языковым правилам, edge n-граммам и другим стратегиям</li><li><b>Фильтровать входные данные</b> — приводить к нижнему регистру, удалять HTML, применять стоп-слова и стемминг (чтобы «running» и «runs» находились по запросу «run»)</li><li><b>Исключать поля из индекса</b> — пропускать чувствительные или нерелевантные данные для экономии дискового пространства</li><li><b>Создавать кастомные анализаторы</b> — комбинировать любой токенизатор с произвольной цепочкой фильтров</li></ul><p>Пример ниже применяет стемминг английского языка к полям Text и Title, а поле с сырым HTML исключает из индексирования:</p><p>Результат buildIndexMapping() передаётся в bleve.New или bleve.NewUsing при создании индекса. Маппинги закрепляются за индексом на этапе создания и не могут быть изменены позже. Чтобы применить новый маппинг, нужно создать свежий индекс и переиндексировать все документы.</p><h2>Мультиязычный поиск</h2><p>Bleve умеет прозрачно работать с несколькими индексами одновременно через <a href="https://pkg.go.dev/github.com/blevesearch/bleve/v2#IndexAlias">IndexAlias</a>. Алиас — это виртуальный индекс, который отправляет запрос во все реальные индексы и объединяет результаты в единый ранжированный список.</p><p>Это особенно полезно, когда у каждого языка свой индекс с собственным анализатором (английский стемминг, французские стоп-слова, кастомная токенизация), а искать нужно по всем сразу:</p><p>Алиасы также упрощают горячую замену (hot-swap). Когда нужно перестроить индекс (например, применить новый маппинг), можно собрать новый индекс в фоне, а затем атомарно подменить его вызовом alias.Swap(newIndexes, oldIndexes). Текущие запросы завершатся на старом индексе, новые сразу пойдут на свежий — без даунтайма.</p><h2>Пагинация с курсором</h2><p>У SearchRequest в Bleve есть поле From для офсетной пагинации: 0 для первой страницы, 20 для второй и так далее. Это работает, но имеет серьёзную проблему: Bleve вынужден оценивать и сортировать <i>все</i> совпавшие документы вплоть до From + Size на каждый запрос. Глубокие страницы становятся всё дороже по памяти и CPU.</p><p>Хуже того, если между двумя запросами в индекс были добавлены новые документы, смещение сдвигается — и пользователь видит дубликаты или пропуски.</p><p>Правильный подход — курсорная пагинация через <a href="https://pkg.go.dev/github.com/blevesearch/bleve/v2#SearchRequest.SetSearchAfter">SearchAfter</a> и <a href="https://pkg.go.dev/github.com/blevesearch/bleve/v2#SearchRequest.SetSearchBefore">SearchBefore</a>. Эти методы продолжают выдачу с известной позиции, а не пересканируют результаты с начала:</p><p>На что обратить внимание:</p><ul><li><b>Стабильная сортировка обязательна.</b> SearchAfter использует ключ сортировки последнего результата в качестве курсора. Если ключ нестабилен, курсор станет невалидным.</li><li><b>Sort — всегда []string.</b> Даже при сортировке по числовому полю Bleve сериализует ключ в строку. Читайте курсор из hit.Sort и передавайте напрямую в SetSearchAfter.</li><li><b>SearchBefore работает аналогично,</b> но в обратном направлении — полезно для кнопки «предыдущая страница».</li></ul><h2>Оптимизация производительности</h2><p>Настройки производительности Bleve не слишком хорошо документированы, но существенно влияют на работу под нагрузкой. Конфигурация передаётся как map[string]any в <a href="https://pkg.go.dev/github.com/blevesearch/bleve/v2#NewUsing">NewUsing</a> или <a href="https://pkg.go.dev/github.com/blevesearch/bleve/v2#OpenUsing">OpenUsing</a> вместо обычных New / Open.</p><p>Эти параметры относятся к Scorch — дефолтному бэкенду хранения Bleve. Полный список доступных опций и значений по умолчанию можно найти в <a href="https://github.com/blevesearch/bleve/blob/master/index/scorch/persister.go#L67">исходном коде персистера</a>.</p><h3>Пакетная индексация</h3><p>Если нужно проиндексировать большой объём данных, используйте Batch вместо одиночных вызовов Index. Пакетная запись группирует операции в одну транзакцию, что значительно снижает нагрузку на диск:</p><p>Оптимальный размер пакета зависит от объёма документов и доступной памяти. Как правило, пакеты по 100-1000 документов дают хороший баланс между скоростью и потреблением ресурсов.</p><h2>Выводы</h2><p>Bleve — одна из недооценённых жемчужин экосистемы Go. Библиотека позволяет добавить полнотекстовый поиск в приложение без сложной инфраструктуры. Настройки по умолчанию дают рабочий результат за минуты, а кастомные маппинги, композитные запросы и тонкая настройка Scorch — инструменты для решения специфических задач оптимально.</p><p>Официальная документация местами неполна, но issues на GitHub и реальные open-source-проекты отлично её дополняют. Рабочий пример всех описанных концепций можно найти в <a href="https://github.com/asciimoo/hister/tree/master/server/indexer">пакете indexer</a> проекта Hister.</p><p><i>Адаптированный перевод статьи <a href="https://hister.org/posts/data-indexing-in-golang">Data Indexing in Golang</a> из блога Hister.</i></p>]]></content:encoded>
    </item>
    <item>
      <title>Переписали JSONata на Go с помощью ИИ за день — экономия $500K в год</title>
      <link>https://tproger.ru/translations/perepisali-jsonata-na-go-s-pomoshhyu-ai-za-den---ekonomiya--500k-v</link>
      <comments>https://tproger.ru/translations/perepisali-jsonata-na-go-s-pomoshhyu-ai-za-den---ekonomiya--500k-v?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Михайлишин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/translations/perepisali-jsonata-na-go-s-pomoshhyu-ai-za-den---ekonomiya--500k-v</guid>
      <description><![CDATA[<p>Инженер из Reco переписал JSONata на Go за 7 часов с ИИ. Библиотека gnata дала ускорение до 1000x и сэкономила $500 000 в год на инфраструктуре Kubernetes.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/translations/perepisali-jsonata-na-go-s-pomoshhyu-ai-za-den---ekonomiya--500k-v">Переписали JSONata на Go с помощью ИИ за день — экономия $500K в год</a>»</p>]]></description>
      <category><![CDATA[Лучшая практика]]></category>
      <category><![CDATA[Оптимизация]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Переводы]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sat, 28 Mar 2026 07:52:12 GMT</pubDate>
      <content:encoded><![CDATA[<p>Один инженер. Семь часов работы. $400 на токены для ИИ. Результат — чистая Go-библиотека, которая заменила целый флот Node.js-подов в Kubernetes и сэкономила компании $500 000 в год на инфраструктуре.</p><p>Это не абстрактный кейс из маркетингового блога. Это реальная история от <a href="https://www.reco.ai/">Reco</a> — SaaS-платформы безопасности, которая обрабатывает миллиарды событий в день. Их инженер Нир Барак взял подход, описанный Cloudflare в статье о <a href="https://blog.cloudflare.com/how-we-rebuilt-nextjs-with-ai-in-one-week/">переписывании Next.js с помощью ИИ</a>, и применил его к собственной инфраструктуре. Получилась библиотека <a href="https://github.com/RecoLabs/gnata">gnata</a> — полная реализация JSONata 2.x на чистом Go с ускорением до 1000x на типовых выражениях.</p><p><a href="https://jsonata.org/">JSONata</a> — это язык запросов и трансформации JSON-данных. Его можно представить как jq, но с поддержкой лямбда-функций и более выразительным синтаксисом. JSONata позволяет писать сложные правила обработки данных без необходимости лезть в код основного приложения. Это делает его популярным в системах, где бизнес-аналитики или исследователи пишут правила детекции, а инженеры обеспечивают инфраструктуру.</p><blockquote>Главное из статьи:<br /><br />- JSONata-выражения через RPC обходились в $300 000/год на инфраструктуру<br />- ИИ-ассистированная перезапись на Go заняла 7 часов и стоила $400 в токенах<br />- Результат: 13 000 строк Go-кода, 1 778 пройденных тестов из официального набора<br />- Ускорение до 1000x на простых выражениях за счёт устранения RPC и JSON-парсинга<br />- Суммарная экономия после оптимизации пайплайна — $500 000/год</blockquote><h2>Проблема — JSONata как узкое место</h2><p>У Reco есть policy engine, который проверяет JSONata-выражения на каждом событии в потоке данных. Миллиарды событий, тысячи различных выражений. Исследователи безопасности пишут правила детекции на JSONata, а инженеры обеспечивают их выполнение в реальном времени.</p><p>Загвоздка: <b>референсная реализация JSONata написана на JavaScript</b>, а весь пайплайн Reco — на Go. Годами компания держала в Kubernetes отдельный флот Node.js-подов (jsonata-js), к которым Go-сервисы обращались через RPC.</p><p>Для каждого события и каждого выражения это означало:</p><ol><li>Сериализовать данные на стороне Go</li><li>Отправить по сети в Node.js-под</li><li>Выполнить JSONata-выражение</li><li>Сериализовать результат</li><li>Отправить обратно в Go-сервис</li></ol><h3>Во что это обходилось</h3><p>Прямые затраты на инфраструктуру jsonata-js составляли <b>около $300 000 в год</b>, и сумма росла с каждым новым клиентом и правилом детекции. На одном из крупных кластеров количество реплик jsonata-js перевалило за 200 — и команда столкнулась с лимитом IP-адресов в Kubernetes.</p><p>Но денежные затраты были даже не главной проблемой. RPC round-trip занимает ~150 микросекунд ещё до начала вычисления. Для простого выражения вроде user.email = "admin@co.com", которое должно выполняться за наносекунды, основная цена — пересечение языковой границы. На масштабе Reco эти микросекунды складываются в ощутимые задержки.</p><p>Команда пробовала разные подходы: оптимизировала выражения, кэшировала результаты, даже встраивала V8 прямо в Go-процесс. Всё это давало инкрементальные улучшения, но не решало корневую проблему — <b>данные всё равно пересекали языковую границу</b>.</p><h2>Решение — переписать на Go с помощью ИИ</h2><p>Толчком стала статья Cloudflare о том, как один инженер за неделю переписал API Next.js на Vite, потратив $1 100 на токены. Нир Барак прочитал её и понял: у Reco та же самая ситуация — есть спецификация, есть тестовый набор, нужна реализация на другом языке.</p><h3>Подход: спецификация + тесты = контракт</h3><p>Метод прямолинейный:</p><ol><li>Портировать официальный тестовый набор jsonata-js на Go</li><li>Направить ИИ на реализацию, пока все тесты не пройдут</li><li>Добавить оптимизации, специфичные для Go и задачи Reco</li></ol><p>В выходные Нир составил план, разбитый на «волны» (с помощью ИИ). На следующий день нажал «старт».</p><h3>Инструменты и затраты</h3><p>Конкретные модели и инструменты автор не раскрывает, но ключевые цифры говорят сами за себя:</p><ul><li><b>Время работы:</b> 7 часов (один инженер)</li><li><b>Стоимость токенов:</b> $400</li><li><b>Результат:</b> 13 000 строк Go-кода</li><li><b>Тесты:</b> 1 778 пройденных тест-кейсов из официального набора jsonata-js</li></ul><p>Библиотека получила название <a href="https://github.com/RecoLabs/gnata">gnata</a> — полная реализация спецификации JSONata 2.x на чистом Go.</p><h2>Технические результаты</h2><h3>Двухуровневая архитектура вычислений</h3><p>gnata использует двухуровневую архитектуру оценки выражений. На этапе компиляции каждое выражение анализируется и классифицируется.</p><p><b>Быстрый путь (fast path)</b> обрабатывает простые выражения: поиск по полям, сравнения и 21 встроенную функцию на чистых путях (например, $exists(a.b) или $lowercase(name)). Эти выражения вычисляются прямо по сырым JSON-байтам, без полного парсинга документа. Для выражения вроде account.status = "active" результат — <b>ноль аллокаций в куче</b>.</p><p><b>Полный путь (full path)</b> — полноценный парсер и вычислитель с полной семантикой JSONata 2.x. Он парсит JSON, но только нужные поддеревья, а не весь документ целиком.</p><h3>Потоковая обработка</h3><p>Поверх двухуровневой оценки работает потоковый слой (StreamEvaluator), спроектированный под конкретную задачу Reco: применить N скомпилированных выражений к каждому событию, где события структурно похожи.</p><ul><li>Все пути из всех выражений объединяются в один проход по данным — количество выражений не влияет на скорость чтения</li><li>После прогрева горячий путь работает без блокировок (lock-free)</li><li>Планы вычислений создаются один раз на схему событий и кэшируются неизменяемо — чтение через один атомарный load без синхронизации</li><li>Память ограничена: кэш с настраиваемой ёмкостью, вытесняющий старые записи</li></ul><h3>Бенчмарки</h3><p>Ускорение на простых выражениях — в основном за счёт полного устранения RPC: gnata вычисляет прямо по сырым байтам без парсинга JSON. На сложных выражениях, где нужен полный парсинг и AST-вычисление, разрыв сужается, но они всё равно <b>в 25–90 раз быстрее</b>, чем через RPC.</p><p>На простых lookups ускорение достигает <b>1000x</b>.</p><h3>Пример использования</h3><h2>Экономический эффект</h2><h3>Этап 1: устранение RPC-флота</h3><p>Первый и самый очевидный эффект — полное устранение jsonata-js подов в Kubernetes:</p><ul><li><b>До:</b> ~$25 000/мес на compute для jsonata-js (200+ реплик Node.js)</li><li><b>После:</b> $0 — gnata работает как библиотека внутри существующих Go-сервисов</li><li><b>Экономия:</b> ~$300 000/год</li></ul><h3>Этап 2: рефакторинг rule engine</h3><p>Но на этом история не закончилась. Старый JSONata через RPC мог обрабатывать только одно выражение за раз, и вся инфраструктура вокруг него была вынуждена подстраиваться. Rule engine запускал десятки тысяч горутин для максимизации параллелизма — со всеми вытекающими: избыточное потребление памяти и высокая конкуренция за CPU.</p><p>gnata не имеет таких ограничений. Команда заменила внутренности rule engine на более простую и эффективную реализацию с just-in-time батчингом (паттерн request coalescing), короткоживущими кэшами и групповыми запросами обогащения данных.</p><p>Результат: ещё <b>~$18 000/мес</b>, или <b>~$200 000/год</b> экономии.</p><h3>Итого</h3><p><b>$500 000/год</b> снято с пайплайна за две недели работы. Из них 7 часов — создание gnata, остальное — тестирование, code review и раскатка.</p><h2>Как внедряли — от shadow mode до продакшена</h2><p>Создать библиотеку — половина дела. Вторая половина — убедиться, что она выдаёт ровно те же результаты, что и оригинал, на миллиардах реальных событий.</p><p>У Reco уже была инфраструктура для shadow-тестирования: feature flags, параллельное вычисление, логирование расхождений. Подключить gnata к ней было несложно.</p><p>Хронология раскатки:</p><ul><li><b>День 1:</b> gnata готова, PR открыт</li><li><b>Дни 2–6:</b> code review, QA на реальных продакшен-выражениях, деплой в preprod в shadow mode. gnata вычисляет всё, но результаты jsonata-js остаются основными. Расхождения логируются и алертятся. Найденные edge-кейсы исправляются</li><li><b>День 7:</b> три дня подряд ноль расхождений. gnata переведена в primary</li></ul><p>К моменту перевода gnata уже обработала миллиарды событий и выдала идентичные результаты. Более того, в процессе обнаружились баги в самом jsonata-js — случаи, где референсная реализация не соответствует собственной спецификации.</p><p>Побочный эффект: gnata стала одним из первых крупных PR в Reco, где ИИ-агенты ревьюили ИИ-сгенерированный код. Агенты помечали всё подряд — и реальные проблемы с конкурентностью, и косметические замечания. Команде пришлось научить их отличать одно от другого, и этот опыт теперь используется шире.</p><h2>Уроки — когда ИИ-переписывание работает</h2><p>gnata — удачный кейс. Но не каждая задача подходит для ИИ-переписывания. Вот что сделало этот проект идеальным кандидатом:</p><ol><li><b>Чёткая спецификация.</b> JSONata имеет формальную спецификацию и обширный тестовый набор. ИИ не нужно придумывать поведение — нужно реализовать заданное</li><li><b>Детерминированная проверка.</b> Каждое выражение имеет однозначный правильный ответ. Можно автоматически проверить корректность — не нужен человек для оценки каждого результата</li><li><b>Глубокая экспертиза инженера.</b> Нир не просто «нажимал кнопку». Он спроектировал двухуровневую архитектуру, потоковую обработку и стратегию кэширования. ИИ генерировал код, но архитектурные решения принимал человек</li><li><b>Существующая инфраструктура тестирования.</b> Shadow mode, feature flags, сравнение результатов — всё это было готово до gnata. Без этого раскатить ИИ-сгенерированный код в продакшен было бы рискованно</li><li><b>Ограниченная область.</b> JSONata — это чётко ограниченная задача. Не «перепишите весь бэкенд», а «реализуйте этот конкретный язык на другом стеке»</li></ol><p>Как отметил Андрей Карпати: программирование становится неузнаваемым, и на верхних уровнях глубокая техническая экспертиза — «ещё больший мультипликатор, чем раньше, из-за увеличенного рычага». gnata — хорошая иллюстрация этой мысли.</p><h2>FAQ</h2><h3>Что такое JSONata и зачем он нужен?</h3><p>JSONata — это язык запросов и трансформации для JSON-данных. Он позволяет писать выражения для фильтрации, преобразования и агрегации JSON без написания кода на языке общего назначения. Используется в IoT-платформах, ETL-пайплайнах и системах обработки событий.</p><h3>Почему нельзя было просто оптимизировать существующий подход?</h3><p>Reco пробовали: оптимизация выражений, кэширование, встраивание V8 в Go. Всё это давало инкрементальные улучшения, но корневая проблема — пересечение языковой границы через RPC — оставалась. Единственное радикальное решение — нативная реализация на Go.</p><h3>Насколько gnata совместима с оригинальной JSONata?</h3><p>gnata проходит 1 778 тест-кейсов из официального набора jsonata-js и 2 107 интеграционных тестов в продакшен-обёртке Reco. В процессе тестирования были обнаружены баги в самом jsonata-js, где референсная реализация не соответствует собственной спецификации.</p><h3>Можно ли повторить этот подход в другом проекте?</h3><p>Да, если есть формальная спецификация и тестовый набор. Подход Cloudflare (vinext) и Reco (gnata) одинаков: берём спеку + тесты, направляем ИИ на реализацию до прохождения всех тестов. Ключевое требование — детерминированная проверка результата.</p><h2>Выводы</h2><p>История gnata — это не про то, что ИИ «волшебным образом» пишет продакшен-код. Это про то, как опытный инженер с глубоким пониманием задачи использует ИИ как мультипликатор своей экспертизы.</p><p>Ключевые выводы:</p><ul><li><b>ИИ-переписывание работает</b>, когда есть чёткая спецификация и автоматизированная проверка</li><li><b>Экономический эффект может быть огромным:</b> $400 на токены превратились в $500 000/год экономии</li><li><b>Архитектура важнее генерации кода:</b> двухуровневая оценка, потоковая обработка и батчинг — решения инженера, не ИИ</li><li><b>Shadow mode обязателен:</b> ИИ-сгенерированный код нельзя просто «выкатить» — нужна параллельная проверка на реальных данных</li><li><b>ROI считается просто:</b> если задача имеет спеку и тесты, стоимость ИИ-переписывания предсказуема</li></ul><p>gnata доступна как open-source библиотека: <a href="https://github.com/RecoLabs/gnata">github.com/RecoLabs/gnata</a>.</p><p><i>Источник: <a href="https://reco.ai/blog/we-rewrote-jsonata-with-ai">We Rewrote JSONata with AI</a> — блог Reco.</i></p>]]></content:encoded>
    </item>
    <item>
      <title>Создаём микросервис обработки изображений на Go с gRPC</title>
      <link>https://tproger.ru/articles/sozdayom-mikroservis-obrabotki-izobrazhenij-na-go-s-grpc-2</link>
      <comments>https://tproger.ru/articles/sozdayom-mikroservis-obrabotki-izobrazhenij-na-go-s-grpc-2?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Go разработчик]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/sozdayom-mikroservis-obrabotki-izobrazhenij-na-go-s-grpc-2</guid>
      <description><![CDATA[<p>В этой статье мы рассмотрим создание микросервиса обработки изображений на golang с использованием технологии gRPC. Цель статьи - показать как может выглядеть такой сервис и что он может в себя включать.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/sozdayom-mikroservis-obrabotki-izobrazhenij-na-go-s-grpc-2">Создаём микросервис обработки изображений на Go с gRPC</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Микросервисы]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Pet-проекты]]></category>
      <category><![CDATA[gRPC]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 17 Mar 2026 05:00:02 GMT</pubDate>
      <content:encoded><![CDATA[<p><b>Вступление</b></p><p>В этой статье мы рассмотрим создание микросервиса обработки изображений на golang с использованием технологии **gRPC**. Цель статьи - показать как может выглядеть такой сервис и что он может в себя включать. В результате мы получим полностью рабочий сервис по обработке изображений, который принимает данные, сохраняет исходную картинку,сжимает её, накладывает на неё ватермарку, изменяет размер изображения, и конвертирует его в нужный формат.</p><p>Разберём возможные варианты взаимодействия клиента с сервером для обработки больших объектов, в нашем случае это картинки:</p><p><b>1. HTTP/1.1 (REST)</b></p><p>Передача изображений в виде текстовых чанков (например, base64) приводит к значительным накладным расходам: бинарные данные увеличиваются на ~33% при кодировании в Base64, а текстовый формат неэффективен для больших объёмов.</p><p><b>2. WebSocket</b></p><p>Подходит для долгоживущих сессий и двустороннего обмена, но избыточен, если нам нужно просто «принять изображение → обработать → вернуть результат». Удержание тысяч соединений ради однократных операций — неоптимально.</p><p><b>3. gRPC</b> использует:</p><p><b>Protocol Buffers</b> — строго типизированный, компактный бинарный формат,</p><p><b>HTTP/2</b> — мультиплексирование, потоки, сжатие заголовков,</p><p><b>Client-Streaming</b> — идеально подходит для передачи одного большого файла (например, изображения) в одном вызове.</p><p><b>I. Постановка задачи</b></p><p><b>Сервис должен:</b></p><p>Принимать изображение и параметры (format, compress, watermark, width[], height[]),</p><p>Сохранять оригинал с уникальным путём (./download/YYYY/MM/DD/UUID/img/...),</p><p>Накладывать водяной знак,</p><p>Генерировать версии заданных размеров,</p><p>Сохранять полученные изображения,</p><p>Возвращать список путей.</p><p>Пример:</p><p>Запрос с width = [1920, 1280], height = [1080, 720], format = "webp", watermark = "logo.png"</p><p>→ Сервис вернёт два пути:</p><p>./download/2026/02/08/abc123/img/abc123_1920x1080.webp</p><p>./download/2026/02/08/abc124/img/abc124_1280x720.webp</p><p><b>II. Архитектура приложения</b></p><figure><img src="https://media.tproger.ru/user-uploads/136053/2026-02-23/af4f6a18-dac9-4728-bbb3-decfe99bc1c5.webp" alt="" /></figure><p><b>Обработка происходит в строгом порядке:</b></p><p>1.Приём → 2. Сохранение исходного файла→ 3. Сжатие → 4. Watermark → 5. Resize → 6. Конвертация → 7. Ответ.</p><p><b>Структура хранения:</b></p><p>./download/2026/02/08/a1b2c3d4-.../img/</p><p>├── a1b2c3d4-....jpg          ← оригинал</p><p>├── a1b2c3d4-..._800x600.png</p><p>└── a1b2c3d4-..._1024x768.png</p><p><b>Необходимые инструменты:</b></p><p>Для работы с WebP мы используем библиотеку <a href="https://pkg.go.dev/golang.org/x/image/webp" rel="nofollow">golang.org/x/image/webp</a> , а исходные утилиты можно скачать на <a href="https://developers.google.com/speed/webp/download?hl=ru" rel="nofollow">официальной странице Google</a>.</p><p>Для генерации protobuff нам нужен  <b>protoc-gen-go</b></p><p><b>protoc-gen-go-grpc</b></p><p>Позволяет генерировать определения сервисов Go для буфера протокола, заданного нашим .proto файлом <a href="https://github.com/grpc/grpc-go/releases" rel="nofollow">protoc-gen-go-grpc</a></p><p>Также для работы webp нам потребуется работа с CGO, которую мы рассмотрим отдельно.</p><p><b> III. Реализация proto файла</b></p><p>Для начала работы опишем наш proto файл. Это будет сервис с единственным rpc который будет обрабатывать картинки пользователей.</p><p>./proto/image.proto</p><p>Мы используем Client-Streaming RPC — клиент может отправить несколько сообщений, сервер — один ответ. Этот способ поможет нам в случае необходимости гибкого расширения и избежания ограничений на размер одного сообщения.</p><p><b>V. Реализация основных функций</b></p><p><b>1. Создание сервера</b></p><p><b>1.1 Генерация  go файлов из .proto:</b>  Сгенерируем файлы для реализации сервера с помощью protoc:</p><p>У нас должно получиться 2 файла image.pb.go и image_grpc.pb.go в директории proto</p><p><b>1.2 Реализуем конструктор сервера и interceptor</b> (аналог middleware в grpc) восстановления после паники:</p><p>./internal/app/server.go</p><p>Теперь реализуем функцию запуска нашего grpc сервера:</p><p>Мы создали наш grpc сервер, но пока нет никакой реализации ImageServiceServer который сгенерировал нам protoc, это просто интерфейс который нам и нужно реализовать.</p><p><b>2. Реализация ImageServiceServer</b></p><p>Нам необходимо создать структуру ImageServer которая реализует интерфейс ImageServiceServer с его методом DownloadImage, также создадим конструктор для него :</p><p>./internal/app/image.go</p><p>Нам осталось реализовать ключевые функции для нашего сервиса, а именно: saveSourceFiles: отвечает за сохранение исходных файлов и их сжатие, watermark: наложение ватермарки , resizeAndSave: изменения размера картинки и его конвертация в нужный формат изображения.</p><p><b>3. Сохранение оригинала</b></p><p>Мы создаем путь для сохранения картинки, сохраняем её с необходимым для клиента уровнем сжатия и потом для удобства всю метаинформацию об картинке помещаем уже в нашу структуру и работаем в дальнейшем только с ней:</p><p>./internal/app/save.go</p><p>Для ускорения нашего процесса обработки все этапы мы будем выполнять конкурентно с помощью горутин.</p><p><b>4. Водяной знак </b></p><p>Следующим этапом идёт наложение водяного знака на нашу картинку. Процесс наложения: мы передаем каждой горутине по изображению, они его обрабатывают, а для того чтобы убедиться что они все обработались мы применяем sync.WaitGroup. Сам процесс наложения водяного знака это задание параметров для установки его на исходную картинку, в нашем случае мы делаем её полупрозрачную с небольшим углом поворота и в случайном месте и сохраняем её:</p><p>./internal/app/watermark.go</p><p>Остаётся только изменить размер и сохранить в нужном формате наши обработанные изображения.</p><p><b>5. Resize и конвертация.</b></p><p>Теперь создадим файл resize.go и реализуем функцию изменения размера изображении и сохранения в нужном нам формате:</p><p>./internal/app/resize.go</p><p>Теперь реализуем main.go в котором создадим и вызовем наш сервис обработки изображений.</p><p>./internal/cmd/main.go</p><p><b>VI. CGO</b></p><p>Наше приложение полностью готово, но теперь нужно удостовериться, что у нас работает поддержка CGO. Для начала нужно убедиться что мы скачали и установили webp по ссылке [официальная страница Google](https://developers.google.com/speed/webp/download?hl=ru). Далее нам необходимо установить GCC, без него go не может распознать импортированные C файлы, скачиваем и устанавливаем [официальные зеркала GNU](https://gcc.gnu.org/mirrors.html). Теперь нужно проверить, что переменная CGO_ENABLED=1, для этого используем команду go env и проверяем, если она равна 0, то используем go set  CGO_ENABLED=1 и проверяем ,что она применилась, если нет то перезагружаем нашу систему и проверяем. Теперь мы готовы собрать наше приложение и приступить к тестированию.</p><p><b>VII. Тестирование и оптимизация</b></p><p><b>Тестирование с Bruno</b></p><p>Здесь вы можете тестировать удобными для вас средствами такими как Postman, Bruno, Yaak, grpccurl и т.д., главное чтобы они поддерживали тестирование grpc методов. Рассмотрим пример с Bruno:</p><p>1.Конвертируйте изображение в Base64: Image to Base64 Converter</p><figure><img src="https://media.tproger.ru/user-uploads/136053/2026-02-23/3b10f151-2654-42b1-b6a2-1e6805d79ba2.webp" alt="" /></figure><p>2.Откройте Bruno создайте новый grpc запрос</p><figure><img src="https://media.tproger.ru/user-uploads/136053/2026-02-23/94dba9c1-7930-43f5-accf-1753036005db.webp" alt="" /></figure><p>3. Выбираем метод grpc:</p><figure><img src="https://media.tproger.ru/user-uploads/136053/2026-02-23/b614edcd-171f-49e5-8ba2-cd4b73283551.webp" alt="" /></figure><p>4.Уберите ползунок с reflection и укажите .proto файл</p><figure><img src="https://media.tproger.ru/user-uploads/136053/2026-02-23/8a88b632-4d1a-41a0-9818-0822a6613551.webp" alt="" /></figure><p>5.Выберите метод DownloadImage</p><figure><img src="https://media.tproger.ru/user-uploads/136053/2026-02-23/2a0f8f65-cb62-4442-a867-10d3c69f145d.webp" alt="" /></figure><p>6.В поле message заполните поле в соответствии с параметрами, например:</p><figure><img src="https://media.tproger.ru/user-uploads/136053/2026-02-23/8f454490-7182-4641-8a31-f56fe6236546.webp" alt="" /><figcaption>если появляются проблемы при подключении к сервису, то не выносите текстовое представление картинки в переменную</figcaption></figure><p>В поле image нужно скопировать текстовую строку ,что идёт после запятой, сгенерированную на шаге 1</p><p>7.Далее нужно запустить наше приложение и подключиться к нему с помощью кнопки →</p><figure><img src="https://media.tproger.ru/user-uploads/136053/2026-02-23/4a166e9e-22d3-4369-be1e-b68534623765.webp" alt="" /></figure><p>В случае успеха должен появиться статус streaming</p><p>8.Отправляем наше сообщение/сообщения нажав на кнопку "Send message" один или несколько раз и завершаем нашу передачу сообщений с помощью кнопки → (если не нажать то приложение будет ожидать приёма сообщений). Результатом будет возврат путей наших обработанных сообщений</p><figure><img src="https://media.tproger.ru/user-uploads/136053/2026-02-23/7e269ec1-2cec-4926-8ccc-a9de76d3e9ff.webp" alt="" /></figure><p><b>VIII. Заключение</b></p><p>Подведем итоги, мы создали сервис который:</p><p>Использует gRPC для эффективной передачи данных,</p><p>Поддерживает WebP, JPEG, PNG,</p><p>Безопасен в конкурентной среде,</p><p>Можно легко масштабировать.</p><p>В результате получился сервис обработки изображений. Этот подход применим не только к изображениям, но и к любым бинарным данным.</p><p>Исходный код доступен по <a href="https://github.com/art9276/image-converter" rel="nofollow">ссылке</a></p><p><b>Спасибо за внимание!</b></p>]]></content:encoded>
    </item>
    <item>
      <title>Datadog уменьшила размер Go-бинарников на 77% без потери функций. Как им это удалось?</title>
      <link>https://tproger.ru/news/datadog-umenwila-razmer-go-binarnikov-na-77--bez-poteri-funkcij</link>
      <comments>https://tproger.ru/news/datadog-umenwila-razmer-go-binarnikov-na-77--bez-poteri-funkcij?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/datadog-umenwila-razmer-go-binarnikov-na-77--bez-poteri-funkcij</guid>
      <description><![CDATA[<p>Datadog сократила Go-бинарники на 77%: аудит зависимостей, включение оптимизаций линкера и удаление plugin дали минус сотни мегабайт</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/datadog-umenwila-razmer-go-binarnikov-na-77--bez-poteri-funkcij">Datadog уменьшила размер Go-бинарников на 77% без потери функций. Как им это удалось?</a>»</p>]]></description>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Оптимизация]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Kubernetes]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 25 Feb 2026 04:53:36 GMT</pubDate>
      <content:encoded><![CDATA[<p>За пять лет размер артефактов Datadog Agent вырос с 428 МБ до 1,22 ГБ.</p><p>Новые фичи, интеграции, поддержка Kubernetes и облаков сделали продукт мощнее... и заметно тяжелее. Это стало проблемой для serverless, IoT и контейнеров.</p><p>Вместо того чтобы урезать функциональность, команда решила «переломить кривую роста». За полгода (v7.60.0 → v7.68.0) им удалось сократить размер Go-бинарников до 77%.</p><h2>Аудит зависимостей: минус 36 МБ одной правкой</h2><p>Первый шаг — полный разбор зависимостей. С помощью go list, goda и go-size-analyzer разработчики искали пакеты, которые подтягиваются в бинарник случайно.</p><p>В одном случае trace-agent тащил 526 пакетов Kubernetes из-за одной функции, которая фактически не использовала k8s-код. Перенос ее в отдельный пакет позволил компилятору выбросить все лишнее — минус 36 МБ.</p><p>И таких случаев нашли десятки.</p><h2>Разблокировка «скрытой» оптимизации линкера</h2><p>Вторая находка дала еще ~20% выигрыша. В Go есть оптимизация method dead code elimination, но она отключается, если используется reflect.MethodByName с динамическими именами (например, в text/template).</p><p>Команда нашла проблемные вызовы через -dumpdep и утилиту <i>whydeadcode</i>, пропатчила зависимости и даже форкнула text/template, чтобы отключить динамические вызовы методов. Результат — еще минус около 100 МБ.</p><h2>Удаление plugin = минус 245 МБ</h2><p>Самый неожиданный эффект дал пакет plugin. Его импорт заставлял линкер сохранять все методы типов, отключая оптимизацию.</p><p>Выяснилось, что зависимость приходила через <i>containerd</i>, хотя агент ее не использовал. После добавления build-тега и обновления зависимостей, основной Linux amd64-бинарник «похудел» на 245 МБ.</p><h2>Итог</h2><ul><li>Security Agent: −77%</li><li>Process Agent: −74%</li><li>Trace Agent: −74%</li><li>Общий .deb: 1,22 ГБ → 688 МБ</li></ul><p>И главное — все это <b>без удаления функций</b>. Только системная чистка зависимостей, грамотные build-теги и возвращение оптимизаций линкера.</p>]]></content:encoded>
    </item>
    <item>
      <title>Сравнение golang веб-фреймворков 2026 года: топ-5 лучших вариантов</title>
      <link>https://tproger.ru/potoksoznaniya/sravnenie-golang-veb-frejmvorkov-2026-goda--top-5-luchwih-variant</link>
      <comments>https://tproger.ru/potoksoznaniya/sravnenie-golang-veb-frejmvorkov-2026-goda--top-5-luchwih-variant?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Картофельный Повелитель]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/potoksoznaniya/sravnenie-golang-veb-frejmvorkov-2026-goda--top-5-luchwih-variant</guid>
      <description><![CDATA[<p>Сравнение веб‑фреймворков 2026 года: разбираем топ‑5 вариантов на Go — Gin, Fiber, Echo, Chi и Beego. Анализируем производительность, потребление памяти, поддержку асинхронности, удобство маршрутизации и экосистему. Помогаем выбрать оптимальный фреймворк под ваш проект: от MVP до enterprise.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/potoksoznaniya/sravnenie-golang-veb-frejmvorkov-2026-goda--top-5-luchwih-variant">Сравнение golang веб-фреймворков 2026 года: топ-5 лучших вариантов</a>»</p>]]></description>
      <category><![CDATA[#Случайные открытия]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Бэкенд]]></category>
      <category><![CDATA[Фреймворки и библиотеки]]></category>
      <category><![CDATA[#Потоксознания]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 20 Feb 2026 15:11:28 GMT</pubDate>
      <content:encoded><![CDATA[<h2>Почему стоит выбрать Go для веб-разработки?</h2><p>Go стал очень популярным языком для бэкенд-API, потому что он предоставляет:</p><ul><li>Очень высокая производительность (компилируемый язык)</li><li>Простой параллелизм с помощью горутин</li><li>Простое развертывание (один бинарный файл)</li><li>Отлично подходит для микросервисов и облачных приложений</li></ul><p>Такие крупные компании, как Google, Uber, Twitch, Dropbox, активно используют Go для серверных сервисов.</p><h2>5 лучших веб-фреймворков Go в 2026 году</h2><h2>Gin — безопасный выбор по умолчанию</h2><p><i></i><i>Сайт </i>→ <a href="https://gin-gonic.com/" rel="nofollow">https://gin-gonic.com/</a></p><p><i>GitHub </i>→ <a href="https://github.com/gin-gonic/gin" rel="nofollow">https://github.com/gin-gonic/gin</a></p><p><b>Gin</b> — пожалуй, самый популярный фреймворк на Go на сегодняшний день. Если вы не знаете, что выбрать, выбирайте Gin.</p><p><b>Скорость изучения:</b> 1–2 дня</p><p><b>Идея для бенчмарка: </b>~50–70 тыс. запросов в секунду</p><p><b>Преимущества</b> 👍</p><p>• Очень прост в настройке</p><p>• Огромное сообщество и промежуточное ПО</p><p>• Стабилен и проверен в реальных условиях</p><p>• Работает со стандартной экосистемой net/http</p><p><b>Недостатки</b> 👎</p><p>• Непредвзятость → большие проекты могут стать запутанными</p><p>• Отсутствие встроенной системы внедрения зависимостей</p><p>• Некоторым не нравится стиль с использованием контекста</p><h2>Fiber — стиль Express.js для Go</h2><p><i>Сайт</i> → <a href="https://gofiber.io/" rel="nofollow">https://gofiber.io/</a></p><p><i>GitHub</i> → <a href="https://github.com/gofiber/fiber" rel="nofollow">https://github.com/gofiber/fiber</a></p><p><b>Fiber</b> похож на Express.js, но написан на Go. Если вы знакомы с Node.js, он вам понравится.</p><p><b>Скорость обучения</b>: 1 день</p><p><b>Идея бенчмарка:</b> ~70–110 тыс. запросов в секунду</p><p><b>Преимущества</b> 👍</p><p>• Чрезвычайно быстрый</p><p>• Очень удобен для разработчиков на Node</p><p>• Множество встроенных функций</p><p>• Чистый и простой синтаксис</p><p><b>Недостатки</b> 👎</p><p>• Использует fasthttp вместо net/http</p><p>• Некоторые библиотеки Go не работают</p><p>• Отладка может быть затруднена</p><p>• Экосистема меньше, чем у Gin</p><h2>Echo — чистый и продуманный фреймворк</h2><p><i></i><i>Сайт</i>→ <a href="https://echo.labstack.com/" rel="nofollow">https://echo.labstack.com/</a></p><p><i>GitHub</i> → <a href="https://github.com/labstack/echo" rel="nofollow">https://github.com/labstack/echo</a></p><p><b>Echo</b> — это сбалансированный фреймворк. Не слишком маленький, не слишком большой.</p><p><b>Скорость изучения:</b> 2–3 дня</p><p><b>Идея бенчмарка:</b> ~50–65 тыс. запросов в секунду</p><p><b>Преимущества</b> 👍</p><p>• Чистая структура</p><p>• Встроенная система проверки и промежуточное ПО</p><p>• Хорошая документация</p><p>• Развитая и стабильная</p><p><b>Компромиссы</b> 👎</p><p>• Экосистема меньше, чем у Gin</p><p>• Для некоторых расширенных функций требуются дополнительные библиотеки</p><p>• Не такой быстрый, как Fiber</p><h2>Chi — легковесный маршрутизатор для чистой архитектуры</h2><p><i>Сайт</i> → <a href="https://go-chi.io/" rel="nofollow">https://go-chi.io/</a></p><p><i>GitHub</i> → <a href="https://github.com/go-chi/chi" rel="nofollow">https://github.com/go-chi/chi</a></p><p><a href="https://github.com/go-chi/chi" rel="nofollow"></a><b>Chi</b> — это не полноценный фреймворк. Это маршрутизатор, который используется во многих серьезных микросервисах.</p><p>Время обучения: несколько часов</p><p>Идея бенчмарка: ~45–60 тыс. запросов в секунду</p><p>Преимущества 👍</p><p>• Очень легкий</p><p>• Использует стандартную сеть/http</p><p>• Идеально подходит для чистой архитектуры</p><p>• Простое тестирование</p><p>Компромиссы 👎</p><p>• Не подходит для новичков</p><p>• Все нужно создавать самостоятельно</p><p>• Нет встроенной объектно-реляционной модели или вспомогательных инструментов</p><p>• Медленное начало работы над небольшими проектами</p><h2>Beego — полноценный MVC-фреймворк</h2><p><i>Сайт</i> → <a href="https://beego.vip/" rel="nofollow">https://beego.vip/</a></p><p><i>GitHub</i> → <a href="https://github.com/beego/beego" rel="nofollow">https://github.com/beego/beego</a></p><p><b>Beego</b> похож на Django. В нем есть ORM, интерфейс командной строки, сессии, шаблоны.</p><p><b>Скорость освоения:</b> 1–2 недели</p><p><b>Идея бенчмарка:</b> ~20–40 тыс. запросов в секунду</p><p><b>Преимущества</b> 👍</p><p>• Все встроено</p><p>• Быстрая разработка монолитных приложений</p><p>• Хорошие инструменты командной строки</p><p>• Встроенная объектно-реляционная модель и шаблоны</p><p><b>Компромиссы</b> 👎</p><p>• Более низкая производительность</p><p>• Больше весит по сравнению с Gin или Fiber</p><p>• Сегодня сообщество меньше</p><p>• Не подходит для микросервисов</p><h2>Откуда взяты эти показатели производительности</h2><p>Приведенные выше цифры не случайны. Вы можете проверить их здесь:</p><p>👉 <a href="https://www.techempower.com/benchmarks/" rel="nofollow">https://www.techempower.com/benchmarks/</a></p><p>Это самый надежный бенчмарк в сфере бэкенд-разработки. Он тестирует фреймворки на одном и том же оборудовании с одинаковой нагрузкой.</p><p><b>Но помните</b> ⚠️</p><p>Реальная производительность зависит от:</p><p>• использования базы данных</p><p>• ведения журналов</p><p>• аутентификации</p><p>• размера полезной нагрузки</p><p>• TLS</p><p>• аппаратного обеспечения</p><p><i>Поэтому всегда проводите собственное тестирование.</i></p><h2>Мои рекомендации на 2026 год:</h2><p>- Если вы новичок → начните с Gin</p><p>- Если вам нужна максимальная производительность → попробуйте Fiber</p><p>- Если вам нужна сбалансированная структура → используйте Echo</p><p>- Если вам нравится чистая архитектура → используйте Chi</p><p>- Если вам нужен полноценный MVC → используйте Beego</p><figure><img src="https://media.tproger.ru/user-uploads/133946/2026-02-20/854421c7-0f72-43e3-b742-2ca15d690417.webp" alt="" /></figure><p>Помните, что идеального фреймворка не существует. Выберите тот, который подходит вашей команде и проекту.</p><p><a href="https://dev.to/mahdi0shamlou/go-web-frameworks-comparison-2026-top-5-picks-gin-fiber-echo-chi-beego-mahdi-shamlo-57d4">Перевод статьи</a></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>Go, LLM и 1,4 млн охвата: как Островок делает единственный регулярный travel-tech хакатон в стране</title>
      <link>https://tproger.ru/articles/go--llm-i-1-4-mln-ohvata--kak-ostrovok-delaet-edinstvennyj-regul</link>
      <comments>https://tproger.ru/articles/go--llm-i-1-4-mln-ohvata--kak-ostrovok-delaet-edinstvennyj-regul?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Екатерина Соколова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/go--llm-i-1-4-mln-ohvata--kak-ostrovok-delaet-edinstvennyj-regul</guid>
      <description><![CDATA[<p>O!Хакатон — полностью внутренний проект Островка: от разработки архитектуры бота до продвижения силами собственных сотрудников.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/go--llm-i-1-4-mln-ohvata--kak-ostrovok-delaet-edinstvennyj-regul">Go, LLM и 1,4 млн охвата: как Островок делает единственный регулярный travel-tech хакатон в стране</a>»</p>]]></description>
      <category><![CDATA[Конференции]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 11 Feb 2026 11:19:37 GMT</pubDate>
      <content:encoded><![CDATA[<p><b>⭐ Участник Продуктовой Премии Tproger 2025 — проголосовать за кейс можно <a href="https://tprg.ru/jqeN">по ссылке</a></b></p><p><i>Найти топ-специалистов в ИТ — задача сложная, особенно когда нужны люди со специфическими навыками и знанием английского. Островок решил эту задачу через O!Хакатон — единственный в России регулярный travel-tech хакатон, который проводится уже два года подряд. Это полностью внутренний проект: от разработки архитектуры бота до продвижения силами собственных сотрудников.</i></p><p>Команда из 5 человек за 8–9 месяцев готовит ивент, который собирает тысячи регистраций и сотни участников со всего мира. Последний <a href="https://tprg.ru/f1QF" rel="nofollow">хакатон</a> показал ВАУ результаты: 1,4 млн охвата в промо и технические решения, одно из которых эксперты назвали «невозможным для реализации за неделю».</p><p>В сентябре 2026 года проект вернется снова, чтобы объединить тех, кто любит путешествия так же сильно, как код.​ А теперь давайте узнаем, как хакатон создавался в прошлом году.</p><h2>Задача: привлечь профи и показать реальный travel-tech</h2><p>Бизнес-цель — транслировать ценности компании на широкую ИТ-аудиторию и привлечь подходящих кандидатов. Островок быстро растет, и конкуренция за специалистов высокая. Хакатон помогает качественно погрузить аудиторию в задачи бизнеса, познакомить со стеком и командой в неформальной обстановке.</p><p>Техническая задача — создать удобную платформу для онлайн-участия из любой точки мира. Нужно было автоматизировать регистрацию, управление командами и проверку решений, чтобы минимальными силами обработать поток из тысяч заявок. При этом важно было сохранить независимость и сделать всё силами инициативных сотрудников без сторонних агентств.​</p><h2>Параметры проекта</h2><ul><li>Срок подготовки: 8–9 месяцев.</li><li>Команда: в основной команде было 8 сотрудников, которые еженедельно работали над проектом. Кроме этого, во время хакатона 18 экспертов оценивали задания участников.</li><li>Технологический стек: Go+PocketBase (backend бота), Next.js (лендинг) и LLM для проверки кода.</li><li>Охват: 1,4 млн человек в промо.</li><li>Результаты: 800 регистраций, 19 тыс. визитов на лендинг и прямой найм в команду.</li><li>Статус: ежегодный проект, следующее мероприятие в сентябре 2026 года .</li></ul><h2>Архитектура: бот на Go и микропотребление ресурсов</h2><p>Для управления хакатоном разработали специального Telegram-бота:</p><ol><li>Бэкенд: Написан на Go с использованием фреймворка PocketBase.</li><li>Скорость разработки: Благодаря помощи LLM на создание и поддержку бота ушло всего 8 часов чистого времени.</li><li>Ресурсы: Бот потребляет всего 10MB RAM и минимум ресурсов процессора, стабильно работая при больших нагрузках.</li><li>Интеграции: Автоматическая выдача прав в GitHub для участников прямо через Telegram.</li></ol><p>Регистрация проходит пошагово в боте. Это позволяет оперативно делать рассылки и дособирать данные, если участники что-то забыли указать. Капитаны команд сами управляют составом участников через интерфейс мессенджера.</p><h2>Три главных технических фишки</h2><p><b>1. LLM как ассистент жюри</b></p><p>LLM использовали для первичной проверки решений участников. Модель помогала отсеивать пустые или совсем сырые работы. Далее решения проверяли члены жюри: они оценивали техническую и продуктовую эффективность предложенных идей.</p><p><b>2. Полная автоматизация в Telegram</b></p><p>Весь путь участника — от регистрации до управления составом команды — проходил в Telegram. Бот взял на себя сбор данных, коммуникацию, выдачу доступов и напоминания. Это снизило нагрузку на команду организаторов и сделало участие максимально удобным.</p><p><b>3. Инхаус-реализация промо</b></p><p>Островок отказался от услуг сторонних компаний. Внешнее продвижение команда реализовала своими силами. Опыт показал, что инициативные сотрудники продвигают проект качественнее и нативнее. Это позволило не только сэкономить бюджет, но и точнее попасть в целевую аудиторию, обеспечив 1,4 млн охвата и высокий уровень заявок.​</p><h2>Трудности и решения</h2><p>🔴 <b>Проблема: Нехватка данных после регистрации</b></p><p>Во время предыдущего хакатона команде организаторов приходилось дозапрашивать часть информации у участников уже после регистрации. Это замедляло процесс и увеличивало количество ручной работы.</p><p>✅ <b>Решение: Обновленная форма регистрации</b></p><p>Команда пересмотрела форму регистрации и добавила все недостающие поля. Это позволило собирать полный набор данных с первого шага и сократить количество уточнений.</p><p>🔴 <b>Проблема: Однотипные вопросы от участников</b></p><p>Участники часто задавали одни и те же вопросы о правилах, сроках и формате участия.</p><p>✅ <b>Решение: Шаблоны и гайды</b></p><p>Команда разработала инструкции, сделала шаблоны презентаций. Это помогло участникам быстрее ориентироваться в правилах и сроках.</p><h2>Итоги и планы на сентябрь</h2><p>Второй <a href="https://tprg.ru/f1QF" rel="nofollow">О!Хакатон</a> побил собственный рекорд по количеству участников: 460 команд удивили экспертов разнообразием подходов к выполнению travel tech-задач. Все финалисты показали высокий уровень навыков и порадовали креативом: один из участников в качестве бонуса реализовал «Tinder для отелей».</p><p>Островок планирует проводить хакатон ежегодно. Для разработчиков это отличная возможность познакомиться с компанией, а для бизнеса — найти свежие идеи и сильных кандидатов.</p><p>Следите за новостями в <a href="https://tprg.ru/BKk9" rel="nofollow">Telegram-канале проекта</a>, чтобы не пропустить старт регистрации 2026!</p><p><i>Реклама. ООО «Бронирование Гостиниц», ИНН 7703389880, erid: 2W5zFFwA6N5</i></p>]]></content:encoded>
    </item>
    <item>
      <title>Go: 15 самых популярных докладов 2025 года на YouTube</title>
      <link>https://tproger.ru/articles/go--15-samyh-populyarnyh-dokladov-2025-goda-na-youtube</link>
      <comments>https://tproger.ru/articles/go--15-samyh-populyarnyh-dokladov-2025-goda-na-youtube?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Валерия Турчак]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/go--15-samyh-populyarnyh-dokladov-2025-goda-na-youtube</guid>
      <description><![CDATA[<p>Go 1.25, кодовые агенты, тулчейн, наблюдаемость, безопасность, тестирование, производительность и работа высокодоступных систем.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/go--15-samyh-populyarnyh-dokladov-2025-goda-na-youtube">Go: 15 самых популярных докладов 2025 года на YouTube</a>»</p>]]></description>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[На английском языке]]></category>
      <category><![CDATA[QA]]></category>
      <category><![CDATA[YouTube]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 23 Dec 2025 14:10:03 GMT</pubDate>
      <content:encoded><![CDATA[<p><i>Это перевод и адаптация от Тпрогер </i><a href="https://www.techtalksweekly.io/p/100-most-watched-talks-in-java-rust" rel="nofollow">оригинальной статьи</a><i>. Все доклады доступны на английском языке. Вы можете смотреть их в браузере с включенным синхронным переводом на русский язык (Yandex, как вариант) или с субтитрами.</i><br /><br /><b>Что мы уже опубликовали: </b></p><p><a href="https://tproger.ru/articles/java--15-samyh-populyarnyh-dokladov-2025-goda-na-youtube">Java: 15 самых популярных докладов 2025 года на YouTube</a></p><p>В 2025 году вокруг Go много движется именно в рантайме и инструментах: язык остаётся максимально прикладным и ориентированным на продакшен.</p><p>В этой подборке — 15 самых просматриваемых докладов по Go за год: Go 1.25, кодовые агенты, тулчейн, наблюдаемость, безопасность, тестирование, производительность и работа высокодоступных систем.</p><h3>1. What’s coming in Go 1.25 — Daniel Marti</h3><p>Конференция - 9500 просмотров - 17 сентября 2025 - 51 минута​</p><p>Доклад даёт технический обзор изменений в языке, тулчейне и стандартной библиотеке Go 1.25: новые итераторы, стабильный PGO (profile-guided optimization), улучшения компилятора, поддержка FIPS и доработки рантайма. Спикер подробно объясняет, что попало в релиз в августе и почему это важно для команд, которые используют Go в энтерпрайзе.</p><p><b>Почему стоит посмотреть: </b>если пишете бэкенд на Go и планируете обновляться до 1.25, доклад помогает быстро понять, какие изменения реально влияют на ваш код и производительность, а какие можно отложить.</p><h3>2. Building a coding agent from scratch — Bill Kennedy</h3><p>Конференция - 3700 просмотров - 18 сентября 2025 - 49 минут</p><p>Живой live-coding‑доклад о том, как собрать практичного «кодового агента» на базе Ollama и gpt-oss. Пошагово показывается, как научить агента читать файлы, листать структуру проекта, вносить правки в код и вызывать инструменты, при этом объясняются принципы tool calling и reasoning.</p><p><b>Почему стоит посмотреть:</b> если хотите встроить агента в реальный Go-проект, здесь можно подсмотреть рабочие паттерны и архитектуру, а потом собрать своего помощника по тем же шагам.</p><h3>3. The Things I Find Myself Repeating About Go — Dave Cheney | GopherCon EU 2025</h3><p>Конференция - 3400 просмотров - 9 сентября 2025 - 31 минута</p><p>Опытный Go-разработчик делится тем, что повторяет снова и снова: идиомы, подходы к неймингу, структуре пакетов и организации кода. Разбираются main.run‑паттерн, guard‑clause стиль, как лучше раскладывать файлы и пакеты, когда использовать вспомогательные функции и дженерики вместо копипасты, и как мышление влияет на стиль Go-кода.</p><p><b>Почему стоит посмотреть: </b>отличная база по стилю и архитектуре на Go, особенно если вы мидл и хотите упростить кодовую базу и сделать её более идиоматичной.</p><h3>4. Unleashing the Go Toolchain — Kemal Akkoyun</h3><p>Конференция - 2800 просмотров - 18 сентября 2025 - 59 минут</p><p>Доклад показывает, как через флаг toolexec превратить каждый go build в программируемый пайплайн. На реальных проектах демонстрируется, как внедрять кастомный анализ, генерацию кода и хуки наблюдаемости прямо на этапе компиляции, не убивая скорость сборки.</p><p><b>Почему стоит посмотреть:</b> если хотите выжать из Go‑тулчейна максимум — автогенерировать куски инфраструктуры, внедрять свои линтеры и метрики — это практическое руководство по расширению стандартных инструментов.</p><h3>5. Observability made painless: Go, Otel &amp; LGTM stack — Haseeb Majid</h3><p>Конференция - 2800 просмотров - 18 сентября 2025 - 1 час 00 минут</p><p>Практический разбор, как использовать Go‑сервисы с помощью OpenTelemetry и LGTM‑стека (Loki, Grafana, Tempo, Mimir и т.п.). Спикер показывает, когда использовать трассировки, метрики или логи, зачем в этом всём context.Context и какие практики помогают строить масштабируемую телеметрию без сложной теории.</p><p><b>Почему стоит посмотреть:</b> если у вас микросервисы на Go и хаос в логах, доклад даёт конкретный план, как выстроить наблюдаемость, не утонув в инструментах.</p><h3>6. The Right Kind of Abstraction — John Cinnamond</h3><p>Конференция - 2300 просмотров - 17 сентября 2025 - 46 минут</p><p>В Go разработчики часто скептически относятся к абстракциям, и небезосновательно. Доклад предлагает понятную рамку, как решать, какая абстракция действительно нужна, а от какой стоит отказаться, разбирая реальные кейсы и компромиссы.</p><p><b>Почему стоит посмотреть:</b> помогает не городить лишние уровни интерфейсов, сохраняя код простым и поддерживаемым.</p><h3>7. Go Security – Past, Present, and Future — Roland Shoemaker</h3><p>Конференция - 2000 просмотров - 17 сентября 2025 - 31 минута</p><p>Для языка с 15‑летней историей у Go удивительно тихое прошлое с точки зрения громких инцидентов безопасности. Доклад разбирает, какие ошибки допускались в экосистеме, что уже исправлено и какие изменения готовятся, чтобы сделать Go‑проекты ещё безопаснее.</p><p><b>Почему стоит посмотреть:</b> если вы отвечаете за безопасность сервисов на Go, это концентрированный обзор рисков, фиксов и будущих улучшений, который сэкономит много времени на самостоятельное изучение.</p><h2>8. Swiss Maps in Go — Bryan Boreham</h2><p>Конференция - 1900 просмотров - 18 сентября 2025 - 49 минут</p><p>Доклад показывает, как переработанные Go‑maps (так называемые Swiss Maps в Go 1.24) используют битовые трюки и SIMD‑оптимизации в компиляторе, чтобы выжать максимум производительности из CPU. Спикер также подробно разбирает подводные камни нового поведения, о которых важно знать.</p><p><b>Почему стоит посмотреть:</b> если вы упираетесь в производительность, активно используете map и хотите понимать, как они устроены под капотом, это отличный технический разбор.</p><h3>9. How Just Eat uses tooling to deploy Go micro-services in minutes — Ainsley Clark</h3><p>Конференция - 1600 просмотров - 18 сентября 2025 - 42 минуты</p><p>На примере Just Eat показывается, как их внутренний тулкит для микросервисов на Go помогает быстро поднимать сервисы, настраивать event‑driven‑воркфлоу и автоматически генерировать инфраструктуру как код и CI/CD. В результате сложные системы реально деплоятся за минуты, а не недели.</p><p><b>Почему стоит посмотреть: </b>если вы строите платформу для микросервисов на Go, здесь можно подсмотреть архитектуру, пайплайны и подход к автоматизации.</p><h3>10. Climbing the Testing Pyramid: From Real Service to Interface Mocks in Go — Naveen Ramanathan</h3><p>Конференция - 1400 просмотров - 17 сентября 2025 - 48 минут</p><p>Доклад про тестирование Go‑сервисов, работающих с S3 и другими внешними системами. Пошагово показываются стратегии: от тестов против реального S3 и хаоса через Toxiproxy до LocalStack, httptest/httpmock и генерации моков по интерфейсам, чтобы честно проверять отказоустойчивость.</p><p>​<b>Почему стоит посмотреть: </b>если вы не уверены, как правильно тестировать интеграции и ошибки в Go‑сервисах, этот доклад даёт понятную лестницу подходов, от реальных окружений до быстрых моков.</p><p>11. When Failure Is Not an Option: Surviving Cloud Outages in Go — Kevin Holditch</p><p>Конференция - 1300 просмотров - 18 сентября 2025 - 30 минут</p><p>Реальная история команды, которая ушла с single‑cloud Java‑решения на multi‑cloud платформу на Go: активная/активная/активная архитектура на Kubernetes, CockroachDB и NATS, чтобы выдерживать банковские SLA. Команда гоняет 24‑часовые «kill‑тесты» провайдеров прямо в продакшене.</p><p><b>Почему стоит посмотреть:</b> если вам нужно понимать, как выглядит настоящая отказоустойчивость в multi‑cloud мире на Go, это редкий доклад без маркетинга и с деталями.</p><h3>12. Hello, MCP World! — Daniela Petruzalek</h3><p>Конференция - 1300 просмотров - 17 сентября 2025 - 30 минут</p><p>Model Context Protocol (MCP) — попытка стандартизировать, как приложения общаются с LLM‑моделями. Доклад разбирает клиент‑серверные компоненты, транспорта, инструменты, промпты и ресурсы, показывая практические примеры на Go для AI‑ассистируемого кода и текста.</p><p><b>Почему стоит посмотреть:</b> если вы хотите встроить LLM в Go‑приложения через понятный протокол, это хорошая точка входа.</p><h3>13. Deep dive into a Go binary — Jesús Espino</h3><p>Конференция - 1200 просмотров - 18 сентября 2025 - 49 минут</p><p>Глубокое погружение в то, как устроен бинарник Go: ELF‑секции, метаданные рантайма и трюки линковки, которые спрятаны внутри исполняемого файла. Подойдёт тем, кто любит разбирать, что происходит после go build.</p><p><b>Почему стоит посмотреть:</b> помогает лучше понимать поведение приложения в продакшене, от работы рантайма до особенностей деплоя и отладки.</p><h3>14. The Quest for Speed: Journey to 50% Better P99 Times with Go — David Vella</h3><p>Конференция - 1200 просмотров - 17 сентября 2025 - 50 минут</p><p>Инженерный постмортем, как команде удалось вдвое улучшить P99‑латентность сервиса на Go. Разбираются профилирование, реальные метрики, типичные анти‑паттерны, которые убивали производительность, и конкретные исправления.</p><p><b>Почему стоит посмотреть:</b> если у вас есть медленный, но рабочий Go‑сервис, доклад даёт чек-лист, по которому можно пройтись и вытащить реальные проценты по скорости.</p><h3>15. A Gopher’s Guide to Vibe Coding — Daniela Petruzalek</h3><p>Конференция - 1100 просмотров - 18 сентября 2025 - 1 час 01 минута</p><p>Vibe coding — модный термин, когда большую часть кода за вас пишет LLM, а вы больше управляете процессом и допиливаете результаты. В докладе делятся опытом нескольких месяцев такой работы: плюсы и минусы, влияние на скорость, качество, идиоматичность Go-кода, поддерживаемость и тестируемость, плюс практические советы по промптам и контексту.</p><p><b>Почему стоит посмотреть: </b>если вы хотите использовать LLM не эпизодически, а встроить в ежедневный процесс разработки на Go, здесь много честных наблюдений и приёмов.</p><p>Итого вы получили 15 докладов, которые покрывают все актуальные направления современного Go — от новых возможностей Go 1.25 и оптимизации производительности до интеграции с AI-агентами, построения высокодоступных multi-cloud систем и работы с современным стеком наблюдаемости.</p><p>В следующей части — 15 самых просматриваемых докладов по Rust, где язык выходит за границы системного программирования и захватывает веб, десктоп и корпоративные платформы.</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>Экспорт приватных типов в Go: почему это антипаттерн</title>
      <link>https://tproger.ru/articles/eksport-privatnyh-tipov-v-go--pochemu-eto-antipattern</link>
      <comments>https://tproger.ru/articles/eksport-privatnyh-tipov-v-go--pochemu-eto-antipattern?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Даниил]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/eksport-privatnyh-tipov-v-go--pochemu-eto-antipattern</guid>
      <description><![CDATA[<p>азбираем антипаттерн, его последствия для инкапсуляции и архитектуры, а также показываем идиоматичные способы инициализации структур и сервисов в Go.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/eksport-privatnyh-tipov-v-go--pochemu-eto-antipattern">Экспорт приватных типов в Go: почему это антипаттерн</a>»</p>]]></description>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Динамическая типизация]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sat, 25 Oct 2025 12:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Разработчики, переходящие в Go из классических ООП-языков вроде Java или PHP, часто пытаются применять знакомые подходы — например, экспортировать приватные типы. Но в Go это не просто лишнее — это антипаттерн.</p><p>Это первая наша пробная статья, но написана по заготовке нашего разработчика с опытом более 15 лет. В этой версии она более ужата, ранее мы писали об этом на нашем сайте, сейчас хотим предоставить её более широкой публике.</p><h2>Почему это плохо</h2><p>Неэкспортируемые типы в Go созданы для внутреннего использования внутри пакета. Они скрывают реализацию и защищают код от нежелательного вмешательства извне. Когда такой тип делают экспортируемым, нарушается принцип инкапсуляции — одна из базовых идей Go.</p><p>Это приводит к тому, что:</p><ul><li>невозможно использовать тип в интерфейсах других пакетов;</li><li>ломается архитектура и DI (dependency injection);</li><li>документация GoDoc не видит такие типы;</li><li>код становится неидиоматичным и сбивает с толку других разработчиков.</li></ul><h2>Правильный подход</h2><h2>Правильный подход</h2><p>Go поощряет простую инициализацию структур. Многие стандартные типы например,</p><p>работают корректно без конструктора. Для сложных сервисов используйте именованные конструкторы, которые проверяют зависимости и возвращают ошибку при некорректной инициализации. Это — идиоматичный путь Go: лучше обработать ошибку явно, чем скрывать её за “удобством”.</p><p>service, err := NewDomainService(cfg, deps)</p><p>if err != nil {</p><p>log.Fatal(err)</p><p>}</p><h2>Итог</h2><p>Экспортировать приватные типы — соблазнительно, но опасно. Это разрушает архитектуру и противоречит философии Go. Используйте приватные структуры только внутри пакета и придерживайтесь идиоматичных решений — они делают ваш код безопаснее и понятнее.</p><p>Источник статьи наш блог, опыт разработчика Webdelo</p>]]></content:encoded>
    </item>
    <item>
      <title>Cloudflare поймала редкий баг в компиляторе Go для arm64: падения при разворачивании стека</title>
      <link>https://tproger.ru/news/cloudflare-pojmala-redkij-bag-v-kompilyatore-go-dlya-arm64--padeniya-pri-razvorachivanii-steka</link>
      <comments>https://tproger.ru/news/cloudflare-pojmala-redkij-bag-v-kompilyatore-go-dlya-arm64--padeniya-pri-razvorachivanii-steka?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Даровская Маша]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/cloudflare-pojmala-redkij-bag-v-kompilyatore-go-dlya-arm64--padeniya-pri-razvorachivanii-steka</guid>
      <description><![CDATA[<p>На arm64 Go обнаружен баг: async preemption могла прервать корректировку стека и вызвать краш в runtime.(*unwinder).next. Исправлено в Go 1.24.6, 1.23.12 и 1.25.0+.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/cloudflare-pojmala-redkij-bag-v-kompilyatore-go-dlya-arm64--padeniya-pri-razvorachivanii-steka">Cloudflare поймала редкий баг в компиляторе Go для arm64: падения при разворачивании стека</a>»</p>]]></description>
      <category><![CDATA[Компиляторы]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Cloudflare]]></category>
      <category><![CDATA[Баги и ошибки]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 09 Oct 2025 11:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Cloudflare опубликовала технический <a href="https://blog.cloudflare.com/how-we-found-a-bug-in-gos-arm64-compiler/">разбор</a> редкой, но критичной проблемы в экосистеме Go: из-за ошибки в генерации кода для arm64 в некоторых случаях возникала гонка на уровне одной инструкции, приводившая к крашам рантайма при разворачивании стека (stack unwinding) в runtime.(*unwinder).next.</p><p>Cloudflare связала учащение «фатальных паник» на arm64 с кодом, где выполнялась работа с Netlink, но корневая причина оказалась глубже — в связанке компилятор ↔ ассемблер Go для arm64 и в том, как разбивалось большое смещение стека на две инструкции ADD со «сдвигом на 12 бит». Если прерывание попадало между этими двумя ADD, стековый указатель оказывался «наполовину скорректирован», и трассировщик стека считывал нерелевантные данные как адрес возврата, что заканчивалось segfault/фатальной паникой. Схожие аварии ранее <a href="https://github.com/golang/go/issues/73259">отмечали</a> и другие команды, в частности Datadog: именно в runtime.(*unwinder).next на Linux/arm64 (Go 1.23.x/1.24.x).</p><h2>Что именно ломалось</h2><ul><li>Сценарий сбоя: асинхронная предвыборка (preemption) <a href="https://github.com/golang/go/issues/63830">попадает</a> между двумя инструкциями корректировки SP (split ADD), после чего GC/трассировка начинают разворачивать некорректный фрейм, обращаясь по невалидному SP. Итог — падение в (*unwinder).next.</li><li>Подтверждение на практике: сходные трассы стеков и «рандомные» крэши на arm64 фиксировались у сторонних команд; проблема оформлена в ишью #73259 в репозитории Go и была <a href="https://github.com/golang/go/issues/73259">признана</a> кандидатом на бэкпорт.</li></ul><h2>Как починили (и какие версии содержат фикс)</h2><p>Исправление прошло через бэкпорт и доступно в поддерживаемых ветках Go:</p><ul><li>Go 1.24.6 — явное упоминание бэкпорта по <a href="https://github.com/golang/go/issues/74694">ишью #73259</a>.</li><li>Go 1.23.12 — <a href="https://go.dev/doc/devel/release">минор</a> с правками рантайма (включая бэкпорт по связанным arm64-сбоям).</li><li>Go 1.25.0 и новее — <a href="https://tip.golang.org/doc/go1.25">фиксация</a> на мажорной ветке.</li></ul><p>Суть изменения: вместо двух поочерёдных ADD для большого смещения теперь собирают оффсет в временный регистр и выполняют одну атомарную корректировку SP.</p><p>Это исключает «окно» между ADD-инструкциями и делает разворачивание стека предсказуемым даже при async preemption. (Подробные обсуждения и сопутствующие arm64-проблемы рантайма см. также в #<a href="https://github.com/golang/go/issues/63830">63830</a>, #<a href="https://github.com/golang/go/issues/65449">65449</a>, #<a href="https://github.com/golang/go/issues/73413">73413</a>.)</p><h2>Кому это важно</h2><ul><li>Все сервисы Go на arm64, где возможны большие стековые фреймы и активна асинхронная предвыборка (по умолчанию с Go 1.14+). В условиях продакшн-нагрузок редкая гонка становится статистически вероятной. Читайте подробнее: https://unskilled.blog/posts/preemption-in-go-an-introduction/</li></ul><h2>Что делать инженерам прямо сейчас</h2><ol><li>Обновиться до: Go 1.25.x или минимум до 1.24.6 / 1.23.12 (если «зажаты» веткой).</li><li>Пересобрать сервисы, критичные по доступности, и раскатить обновления в первую очередь на arm64-инфраструктуру.</li><li>Если апгрейд временно невозможен — минимизируйте большие стек-фреймы (вынос больших буферов в heap), снизьте вероятность попадания preemption в эпилог и проверьте зависимости на предмет собственного asm/unsafe-кода.</li><li>Отслеживайте релизы Go и связанные тикеты об unwinding/arm64 (см. #73259 и бекпорт #74694).</li></ol><p>Источники и материалы:</p><ul><li>Обсуждение с примерами падений: runtime: segfaults in runtime.(*unwinder).next (GitHub, #73259).  https://github.com/golang/go/issues/73259</li><li>Бэкпорт фикса в ветку 1.24: (GitHub, #74694) — релиз Go 1.24.6. https://github.com/golang/go/issues/74694</li><li>История релизов, минор Go 1.23.12 с правками рантайма. <a href="https://go.dev/doc/devel/release?utm_source=chatgpt.com">https://go.dev/doc/devel/release</a></li><li>Release notes Go 1.25 (фикс присутствует в мажорной ветке).  https://tip.golang.org/doc/go1.25</li><li>Ранние разборы проблем разворачивания стека/прерываний на arm64 https://github.com/golang/go/issues/63830</li></ul>]]></content:encoded>
    </item>
    <item>
      <title>Релиз Golang 1.25 за 10 минут — что улучшили и добавили в новой версии языка</title>
      <link>https://tproger.ru/articles/reliz-golang-1-25-za-10-minut---chto-uluchwili-i-dobavili-v-novoj-versii-yazyka</link>
      <comments>https://tproger.ru/articles/reliz-golang-1-25-za-10-minut---chto-uluchwili-i-dobavili-v-novoj-versii-yazyka?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Вадим Егорцев]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/reliz-golang-1-25-za-10-minut---chto-uluchwili-i-dobavili-v-novoj-versii-yazyka</guid>
      <description><![CDATA[<p>Что нового в Go 1.25 — узнайте про самые заметные изменения за 10 минут. Новый сборщик мусора Green Tea, пакет encoding/json/v2, улучшение логики GOMAXPROCS, пакет testing/synctest. Обзор заметок о релизе Golang 1.25.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/reliz-golang-1-25-za-10-minut---chto-uluchwili-i-dobavili-v-novoj-versii-yazyka">Релиз Golang 1.25 за 10 минут — что улучшили и добавили в новой версии языка</a>»</p>]]></description>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Боты]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 12 Sep 2025 10:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Релиз Golang 1.25 <a href="https://go.dev/doc/go1.25">направлен</a> на производительность и улучшение инструментов. Добавили новый сборщик мусора, автонастройку GOMAXPROCS для контейнеров, пакеты testing/synctest, json/v2. В публикации собрали самые заметные изменения Go 1.25 и рассказали про сценарии их применения.</p><h2>Сборщик мусора Green Tea</h2><p>Приложения на Go создают огромное количество мелких объектов. Сборщик мусора тратит время на обработку этих объектов, из-за чего в приложении возникают паузы GC. Новый сборщик должен решить проблему использования памяти.</p><p><b>Green Tea</b> — это альтернативный алгоритм сборки мусора. Он настроен на борьбу с мелкими объектами. Пока что это экспериментальная функция, судьба Green Tea зависит от результатов тестирования сообществом.</p><p>Green Tea очищает последовательные блоки памяти (батчи). Размер блоков 8 КБ, в них хранятся объекты до 512 МБ. Объекты больше этого лимита обрабатываются по старому алгоритму.</p><p><b>Green Tea показывает впечатляющие результаты в тестах производительности</b>. Например, 32-кратное <a href="https://www.reddit.com/r/golang/comments/1kw7fpd/gos_experimental_green_tea_gc_how_important_is/">ускорение</a> маркировки в алгоритмах обхода графов. Green Tea GC эффективнее использует преимущества последовательного размещения данных в памяти.</p><p>В <a href="https://www.reddit.com/r/golang/comments/1n5jhfb/greentea_gc_in_go_125_vs_classic_gc_real_world/?tl=ru">нагрузочных тестах</a> с миллионом объектов Green Tea использовал на 22% меньше CPU, на 8% меньше потреблял память. Время выполнения тоже улучшилось на 5%.</p><p>Время пауз в основном остаётся коротким, но 99-й процентиль показал более длительные остановки — 1.84 мс против 0.92 мс у классического GC. То есть в редких случаях всё же могут возникать заметные задержки.</p><h2>Пакет synctest</h2><p>Ситуация: вы написали код с таймерами и хотите его протестировать. Паузы длятся по несколько секунд — совсем немного. Проблема в том, что у нас 100 тестов, т. е. одна итерация тестирования займёт несколько минут.</p><p>До synctest у вас было на выбор четыре сценария:</p><ul><li>пропускать тесты,</li><li>ждать все таймауты,</li><li>создавать интерфейсы-обёртки,</li><li>передавать функции времени как параметры.</li></ul><p>В Golang 1.25 можно сделать проще — обернуть тест в synctest.Run() и пропустить время ожидания.</p><p><b>Как работает synctest</b></p><p>Функция подменяет системное время. Например, когда код вызывает time.Sleep(5 * time.Second), виртуальные часы переводятся на 5 секунд вперёд, и выполнение теста мгновенно продолжается.</p><p><b>Ограничения</b></p><p>Synctest работает только со стандартными функциями. Подменять системное время бесполезно, если ваш код обращается, например, к PostgreSQL, или читает timestamp из файла.</p><h2>Пакет encoding/json/v2</h2><p>Разработчики Golang не стали изменять существующий пакет, чтобы сохранить обратную совместимость. Вместо этого добавили вторую версию пакета — <b>encoding/json/v2</b>.</p><p>По скорости новая версия <a href="https://github.com/go-json-experiment/jsonbench#readme">сравнима</a> с внешними библиотеками вроде <a href="https://pkg.go.dev/github.com/json-iterator/go">jsoniter</a>. При декодировании v2 быстрее предыдущей версии в 3-10 раз. Ещё json/v2 в 38,6 раза быстрее <a href="https://github.com/kubernetes/kube-openapi/issues/315#issuecomment-1240030015">читает</a> JSON.</p><p><b>Прямая работа с Reader и Writer</b></p><p>Функции MarshalWrite и UnmarshalRead работают напрямую с io.Writer и io.Reader. Они экономят память при обработке большого JSON, т. к. не создаются промежуточные байтовые буферы Encoder и Decoder.</p><p><b>Настройки прямо при вызове</b></p><p>В encoding/json/v2 можно передавать опции прямо в функции маршалинга.</p><p>Например, добавлять отступы для читаемости, представлять числа как строки в месте вызова. Раньше для каждого варианта форматирования создавали отдельный Encoder.</p><p><b>Новые теги для структур</b></p><ul><li>inline встраивает поля вложенной структуры на уровень родителя — больше не нужно дублировать поля адреса в структуре пользователя.</li><li>case строго сопоставляет имена полей при парсинге JSON — с настройкой «ignore» программа будет считать одинаковыми userName, user_name и UserName. С настройкой «strict» потребует точного совпадения регистра и символов.</li><li>unknown собирает все неизвестные поля в одну map — удобно для работы с динамическими API, где набор полей может меняться.</li><li>format указывает формат для времени, дат и других типов прямо в структуре.</li></ul><p><b>Кастомные преобразователи без изменения типов</b></p><p>В Go 1.24 для кастомной логики сериализации приходилось создавать новый тип и реализовывать Marshaler/Unmarshaler. Теперь можно написать функцию-преобразователь через MarshalFunc и использовать её только там, где нужно.</p><p><b>Изменения в поведении по умолчанию</b></p><p>encoding/json/v2 может сломать существующий код:</p><ul><li>Nil-слайсы теперь кодируются как пустые массивы [] вместо null, nil-карты — как пустые объекты {} вместо null.</li><li>Байтовые массивы автоматически кодируются в base64-строки, а не в массивы чисел.</li><li>При декодировании имена полей сравниваются с учётом регистра — поле «name» в JSON не найдёт поле Name в структуре.</li></ul><p><b>Улучшена потоковая обработка</b></p><p>Добавили функции UnmarshalDecode и MarshalEncode для работы с большими JSON-файлами, где данные идут потоком (логи, экспорты БД). Они работают с jsontext.Decoder и jsontext.Encoder, обрабатывая по одному JSON-объекту за раз без загрузки файла в память.</p><p><b>Композиция настроек и маршалеров</b></p><p>Опции и маршалеры объединяются через JoinOptions и JoinMarshalers. Т. е. можно создавать переиспользуемые наборы настроек для разных сценариев.</p><p>Например, один набор для внешнего API с красивым форматированием, другой для внутренних сервисов с компактным выводом.</p><h2>Метод WaitGroup.Go</h2><p>Добавили новый метод Go(), чтобы упростить работу с горутинами. Изменение небольшое, но очень полезное — ваш код в версии 1.25 станет чище и безопаснее.</p><p>Метод упаковывает часто используемый код в удобную функцию. WaitGroup.Go() автоматически вызывает wg.Add(1), запускает переданную функцию в новой горутине и добавляет defer wg.Done() в начало выполнения функции.</p><h2>Work Pattern для go.work</h2><p>Представьте, что у вас есть большой проект с множеством микросервисов: сервис A, сервис B, сервис C и так далее. Раньше, чтобы запустить тесты во всех сервисах, приходилось писать длинные команды, явно указывая каждый модуль:</p><p>В Go 1.25 можно просто написать:</p><p>И тесты запустятся автоматически во всех модулях, указанных в файле go.work.</p><h2>Трассировка runtime/trace.FlightRecorder</h2><p>Трейсинг в Go — это дорогое удовольствие. Обычное трассирование записывает всё подряд с самого начала до конца программы. Flight Recorder работает по-другому:</p><ul><li>использует круговой буфер — как кольцевая память;</li><li>хранит только последние события программы;</li><li>автоматически удаляет старую информацию;</li><li>в результате получается компактный файл с только нужными данными.</li></ul><p>FlightRecorder вызовы функций, активность горутин, время выполнения операций, использование памяти, работу сборщика мусора.</p><h2>Группировка атрибутов в slog</h2><p>За группировку атрибутов отвечает метод slog.Group(). Он принимает второй параметр типа []any, куда можно передать абсолютно любые данные — строки, числа, объекты. Проблема в том, что компилятор не знает, действительно ли вы передаёте корректные атрибуты для логирования.</p><p>В Go 1.25 появился метод <b>groupAttrs</b>, который принимает строго типизированный слайс атрибутов []slog.Attr. В этом случае компилятор сможет проверить корректность данных на этапе компиляции.</p><p>Если попытаетесь добавить в слайс что-то кроме slog.Attr, получите ошибку компиляции.</p><h2>GOMAXPROCS учитывает запуск в контейнерах</h2><p>Эта переменная окружения определяет максимальное количество потоков ОС для одновременного выполнения горутин. По умолчанию GOMAXPROCS равняется количеству логических процессоров на машине.</p><p>Например, ваше приложение запущено в Docker-контейнере с ограничением 2 CPU на сервере с 16 ядрами. В старых версиях Go пытается использовать все 16 ядер. Чтобы приложение соблюдало ограничения, разработчики вынужденно ставили стороннюю библиотеку <a href="https://pkg.go.dev/go.uber.org/automaxprocs">automaxprocs</a>.</p><p>В новой версии Go автоматически:</p><ol><li>Читает настройки cgroups.</li><li>Определяет доступное количество CPU для контейнера.</li><li>Устанавливает GOMAXPROCS в соответствии с этими ограничениями.</li></ol><p>Если контейнер ограничен 2 CPU, Go автоматически установит GOMAXPROCS=2, независимо от количества ядер у физического сервера.</p><h2>Исправление бага в компиляторе Go 1.21+</h2><p>Компилятор переставляет местами строки кода во время компиляции. Если вы писали код, который использовал результат функции без предварительной проверки ошибки, то могли наткнуться на этот баг.</p><p>Например, вы открываете файл и сразу пытаетесь с ним работать. По логике Go, если файл не открылся, вы должны получить панику при попытке обратиться к nil-указателю:</p><p>В Go 1.21-1.24 компилятор «оптимизировал» код, переставляя строку name = f.Name() после проверки ошибки. Поэтому программа завершалась без паники.</p><p>В Go 1.25 компилятор выдаёт «invalid memory address or nil pointer dereference», как и должно быть.</p><p><i>Ждёте стабильную версию GC Green Tea в Golang 1.26? Расскажите в комментариях, как новый сборщик показал себя на реальных рабочих нагрузках — другим разработчикам будет интересно почитать про ваш опыт.</i></p>]]></content:encoded>
    </item>
    <item>
      <title>Rust как потенциальная замена Go — хайп или реальность?</title>
      <link>https://tproger.ru/articles/rust-kak-potencialnaya-zamena-go---hajp-ili-realnost-</link>
      <comments>https://tproger.ru/articles/rust-kak-potencialnaya-zamena-go---hajp-ili-realnost-?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Вадим Егорцев]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/rust-kak-potencialnaya-zamena-go---hajp-ili-realnost-</guid>
      <description><![CDATA[<p>Сравнение Go и Rust в 2025 году: области применения, анализ производительности. Простота Go против надёжности Rust.  Скорость разработки, обучения программистов, развёртывание приложений.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/rust-kak-potencialnaya-zamena-go---hajp-ili-realnost-">Rust как потенциальная замена Go — хайп или реальность?</a>»</p>]]></description>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Rust]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 10 Sep 2025 10:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Ядро Linux <a href="https://www.securitylab.ru/news/562025.php">переписывают</a> на Rust, новый драйвер NVIDIA NOVA разрабатывают на «ржавом» языке, во фронтенде появился фулстек-фреймворк <a href="https://leptos.dev/">Leptos</a>. Rust становится универсальным решением, и кажется, что заменит Golang.</p><p>Давайте разберёмся, корректно ли сравнивать эти языки, посмотрим на плюсы, минусы технологий и выясним, в каких сценариях раскрываются их сильные стороны.</p><p>Комментарии по теме предоставили: разработчики Василий Зорин, Эдуард Дыкман; автор курсов в Яндекс Практикуме Кирилл Федченко; участники сообщества <a href="https://t.me/golangl">Golang Go</a> и <a href="https://t.me/rust_chats">Rust</a>.</p><p>⚠️ <i>Мы не ищем язык-убийцу. В публикации собрали популярные мнения, чтобы помочь в принятии взвешенного решения для ваших проектов.</i></p><h2>Почему Go и Rust считают конкурентами, если они такие разные?</h2><p>Первый со сборщиком мусора больше похож на Java. Второй без сборки мусора, и напоминает продвинутый C++. Но постойте!</p><p><b>Во-первых</b>, языки появились практически одновременно. Go заявил о себе в 2009 году, Rust показали в 2010-м. «Современный язык для разработки быстрых и безопасных приложений», — так говорили про Go, так говорили про Rust.</p><p><b>Во-вторых</b>, несмотря на разные подходы к управлению памятью, оба языка метят в одну и ту же аудиторию. К ним приходят разработчики, которым нужно быстрее Python, но безопаснее C++.</p><p><b>В-третьих</b>, на этих языках пишут схожие типы приложений: веб-серверы, микросервисы, CLI-инструменты и системное ПО. Например, на Go написаны Docker и Kubernetes, а на Rust — Firecracker (AWS), движок Servo, <a href="https://github.com/vectordotdev/vector/">Vector</a>.</p><blockquote>Оба языка конкурируют в backend-разработке, облачных вычислениях и инструментах DevOps, где ключевыми являются масштабируемость и параллелизм. Например, в области:<br /><br />— микросервисов: оба языка используются для создания распределенных систем, при этом функции безопасности Rust могут быть предпочтительнее для критически важных компонентов; <br />— сетевого взаимодействия: такие инструменты, как gRPC или HTTP-серверы, реализованы в обоих языках;<br />— облачной инфраструктуры: компании используют Go из-за его простоты, а Rust для компонентов, критически важных для производительности.<br /><br />Rust лучше подходит для системного программирования (компиляторы, драйверы, ОС), в то время как Go более распространен в крупномасштабных сервисах высокой доступности, где приоритетна быстрая разработка.</blockquote><h2>Простота сейчас или надёжность потом?</h2><p>Go следует принципу «<b>простота превыше всего</b>»: минимум синтаксического сахара, встроенная поддержка горутин, автоматическая сборка мусора.</p><blockquote>Наши программисты — гуглеры, а не исследователи. Они не способны понять гениальный язык, но мы хотим, чтобы они создавали хорошее ПО. Поэтому язык, который мы им даём, должен быть простым для понимания и лёгким для освоения.</blockquote><blockquote>Иногда Golang называют дубовым языком, и считают это преимуществом. Вообще вопросов к нему много: можно рассуждать о проблемах обработки ошибок, об отсутствии тернарников, энумов и т. д.</blockquote><p>У Rust другая философия — «<b>лучше потратить время на борьбу с компилятором сейчас, чем часы на отладку багов потом</b>».</p><p>Система типов и borrow checker заставляют контролировать жизненный цикл данных, помнить про безопасность потоков и обработку ошибок ещё до запуска программы. Компилятор не позволит собрать код с потенциальными проблемами.</p><blockquote>Я ценю Rust за баланс производительности и низкоуровневого контроля с гарантиями безопасности языков высокого уровня. Модель владения исключает ошибки, такие как гонки данных и разыменование нулевых указателей, что повышает надежность сложных систем и сокращает время отладки. Бесплатные абстракции языка позволяют писать высокоуровневый код, который компилируется в эффективный машинный, без потерь в выразительности. Инструментарий Cargo значительно упрощает управление зависимостями, тестирование и сборку. А растущая экосистема и поддержка сообщества означают, что для большинства задач уже есть проверенные библиотеки и фреймворки.</blockquote><blockquote>Что привлекает в Rust — это инструментарий и экосистема. Язык развивается предсказуемо: стабильные обновления выходят по календарю, есть понятная схема nightly → beta → stable.<br /><br />Из минусов — интеграция с другими языками требует дополнительных усилий по настройке FFI, но решения для этого есть (#[repr(C)]). Возникают вопросы к архитектуре: например, async/await добавили раньше, чем проработали корутины, и теперь приходится подгонять одно под другое не самыми элегантными методами. Ещё Rust компилируется заметно дольше других языков.<br /></blockquote><h2>Сколько нужно времени на обучение Rust и Go?</h2><p>Golang с нуля можно освоить за 2-4 недели. <a href="https://go.dev/doc/">Документация Go</a> содержит исчерпывающую информацию о синтаксисе, стандартной библиотеке и концепциях программирования. Больше всего времени потребуется на изучение горутин, каналов, системы интерфейсов.</p><p><a href="https://doc.rust-lang.ru/book/title-page.html">Документация Rust</a> не менее подробная. Синтаксис языка сложнее. Обучение затягивается из-за уникальной системы владения памятью (ownership) и концепции времени жизни (lifetimes). Ещё нужно время на принятие borrow checker, когда кажется, что компилятор специально мешает писать код.<a href="https://doc.rust-lang.ru/book/title-page.html"></a></p><figure><img src="https://media.tproger.ru/user-uploads/105601/2025-08-29/0f30d904-b26c-4d80-96d4-3f71ad85e109.jpg" alt="Borrow checker" /></figure><blockquote>Borrow checker — лучший друг программиста, он следит за соблюдением модели владения. Основное правило гласит, что в любой момент времени на переменную может ссылаться либо одна мутабельная ссылка (с правом записи), либо сколько угодно иммутабельных (только чтение). Это нужно соблюдать в любом языке, который поддерживает многопоточность. В Golang, например, с data races приходится бороться своими силами. Также borrow checker убеждается в отсутствии «висячих» указателей (когда ссылка живёт дольше, чем данные).</blockquote><blockquote>Входной порог может быть высоким: освоить владение и заимствование, особенности синтаксиса и обработки ошибок бывает непросто не только новичкам, но и опытным разработчикам. Существуют курсы, помогающие плавно перенастроить профессиональный стек под другой язык, например, «Rust для действующих разработчиков» в Яндекс Практикуме помогает быстро перейти к практике.</blockquote><h3>Вы знали, что код на Rust в 2,6 раза проще кода на Go?</h3><p>В июне 2025 года TIOBE <a href="https://www.tiobe.com/knowledge/article/which-programming-language-produces-the-most-complex-code/">проанализировало</a> 1,5 миллиарда строк кода, измеряли сложность программ на разных ЯП. Считали количество путей выполнения в функциях — чем меньше число, тем проще код для понимания и поддержки.</p><figure><img src="https://media.tproger.ru/user-uploads/105601/2025-08-29/c595d6d4-5076-42bd-ad01-4c0eff204f6e.jpg" alt="Исследование TIOBE" /><figcaption>Rust показал лучший результат — 1.32 балла. Go набрал больше — 3.39.</figcaption></figure><p>Как получилось, что Golang в 2,6 раза сложнее Rust?</p><p>Простота синтаксиса не всегда означает простоту итогового кода. В Go обрабатывают ошибки через if-конструкции, из-за этого в гошной программе больше дополнительных веток — это и повлияло на результаты исследования.</p><p>Синтаксис Go минималистичнее и проще для новичков, но код получается более разветвлённым. На Rust пишут программы с меньшим количеством путей выполнения, поэтому кажется, что код проще для понимания и поддержки.</p><blockquote>Большое преимущество Go — это низкий порог входа (25 ключевых слов против 70 в Rust). Стандартная библиотека довольно небольшая, но в ней есть практически всё. По моему опыту, в средней кодовой базе на Golang разобраться больше шансов, чем в Rust.</blockquote><h2>Когда Rust работает быстрее Go, и где это используют?</h2><p>Представим интернет-магазин: пользователь заходит на страницу товара, сервер идёт в базу данных и отдаёт JSON. В таких случаях Go и Rust работают примерно одинаково быстро — узкое место в скорости ответов БД.</p><p>Теперь вы обрабатываете видео в реальном времени или анализируете миллионы финансовых транзакций. В этом случае предпочтительнее Rust, и вот почему.</p><p>В Go сборщик мусора может внезапно остановить программу на несколько миллисекунд — «подожди, я тут память чищу». В видеостриме это означает подвисание картинки, в торговых алгоритмах — потерю денег. <b>Rust работает без неожиданных пауз, потому что вы сами управляете памятью</b>.</p><blockquote>В Golang накапливается «мусор», который в какой-то момент будет обработан сборщиком, что по времени может совпасть с внешней полезной нагрузкой и ухудшить время отклика сервера.<br /><br />В Rust память удаляется автоматически, как только её владелец выходит из области видимости. Так что любые приложения, в которых важным аспектом производительности является управление памятью, могут выиграть за счёт использования Rust (БД, ОС, браузеры, видеоигры).<br /></blockquote><blockquote>Rust приносит реальную пользу в продакшене там, где простои и уязвимости стоят дорого:<br /><br />— встроенные системы (устройства IoT, ПО для автомобилей) — безопасность и эффективность Rust снижают вероятность сбоев оборудования, от которого зависят жизни людей.<br />— финансовые услуги — высокочастотные торговые платформы, использующие Rust, могут обрабатывать транзакции быстрее и с меньшим количеством ошибок, что повышает конкурентоспособность.<br />— облачная инфраструктура — высокая производительность и минимализм Rust в области сетевого взаимодействия и параллелизма (например, в Tokio) позволяют снизить затраты на сервер, что напрямую влияет на размер прибыли</blockquote><h3>Параллельная обработка</h3><p>Допустим, вам нужно скачать 3000 файлов. В Go можно написать цикл с горутинами — синтаксис интуитивно понятный, и базовый вариант заработает без глубокого изучения теории.</p><p>В случае с Rust придётся почитать про async/await, разобраться с библиотекой Tokio, понять разницу между async fn и обычными функциями. Зато получите полный контроль над тем, как именно выполняется код.</p><h3>Потребление ресурсов</h3><p>Go жирнее по памяти. Каждая горутина занимает от 2 КБ, плюс сборщик мусора держит в памяти объекты про запас. Для веб-сервиса не критично, для встраиваемых систем может стать проблемой.</p><p>Rust экономнее — вы платите только за то, что реально используете. Программу на Rust можно запустить на микроконтроллере с 32 КБ памяти. Go туда не поместится.</p><h2>В чём разница между развертыванием Go и Rust приложений?</h2><p>Оба языка компилируются в один исполняемый файл — просто скопировали на сервер и запустили. Docker-образы получаются крошечными, особенно у Rust (можно упаковать в scratch-образ размером несколько мегабайт). Go чуть проще интегрируется с существующей инфраструктурой.</p><blockquote>На мой взгляд, разница минимальна. Оба языка отлично собираются в машинный код для любых платформ. В Go это проще, можно просто указать компилятору нужную платформу. В Rust есть тулзы для кроссплатформенной сборки. Также в Rust сложнее собирать код, который использует FFI.</blockquote><h2>В каких сферах Go и Rust делят рынок программирования?</h2><h3>Go</h3><ul><li>Идеален для микросервисов и REST API. Фреймворки Gin и Echo помогают быстро собрать рабочий сервис — например, для регистрации пользователей или каталога товаров.</li><li>Docker, Kubernetes, Terraform — все написаны на Go. Язык используют для консольных приложений: получается один файл, который запускается везде без дополнительных зависимостей.</li><li>В больших командах с частой сменой разработчиков Go встречается чаще. Простой синтаксис означает, что новые разработчики быстрее разбираются в коде проекта.</li></ul><h3>Rust</h3><ul><li>Операционные системы, драйверы — области, где Rust конкурирует с C++. Язык предлагает сопоставимую производительность, но защищает от ошибок с памятью.</li><li>Rust компилируется в эффективный <a href="https://tproger.ru/articles/pochemu-webassembly-vsyo-eshhyo-ne-pereplyunul-js-i-ts">WebAssembly</a> для запуска вычислений в браузере. Используется в играх, обработке изображений, криптографии.</li><li>Ripgrep (аналог grep) и exa (аналог ls) демонстрируют возможности Rust — они работают быстрее классических Unix-утилит.<br /></li></ul><blockquote>Rust лучше подходит для системного программирования (компиляторы, драйверы, ОС), в то время как Go более распространен в крупномасштабных сервисах высокой доступности, где приоритетна быстрая разработка</blockquote><h2>Стоит ли изучать Rust, если более простой Go справляется с большинством задач?</h2><p>Всё зависит от ваших целей. Кирилл Федченко отмечает:</p><p>— Go подходит для быстрой разработки микросервисов, API, облачных инструментов благодаря простоте, масштабируемости и легковесному параллелизму.</p><p>— Rust стоит изучить, если вам нужен максимальный контроль над производительностью, безопасностью или низкоуровневыми сущностями (операционные системы, встраиваемые системы). Если ваша цель — создание высокопроизводительных, критически важных систем, то инвестиция времени в изучение Rust один из эффективных способов.</p><p>Go часто достаточно для решения задач, но более широкое применение и растущий спрос на Rust делают его ценным навыком для карьеры. Уже восемь лет подряд язык <a href="https://insights.stackoverflow.com/survey/">признается</a> лучшим в опросе Stack Overflow, а его сообщество <a href="https://www.slashdata.co/post/state-of-the-developer-nation-23rd-edition-the-fall-of-web-frameworks-coding-languages-blockchain">растет</a> быстрее, чем у других языков. Именно поэтому многие переучиваются на Rust с Go, C++ или Python, особенно при переходе в системное программирование или области, где безопасность имеет ключевое значение.</p><h2>Почему Rust не вытеснит Go, несмотря на все преимущества?</h2><p>Rust не заменит язык Go, потому что последний хорошо решает свои задачи.</p><blockquote>Golang и Rust используют для разных целей. Сценариев применения Rust меньше, чем для Go. Поэтому Golang популярнее, но это не замена Rust.</blockquote><blockquote>Оба языка далеки от идеала для написания бизнес-логики, она теряется за синтаксическими конструкциями. В зависимости от области, для бизнес-логики я бы предложил рассмотреть typescript, java/kotlin, elixir, clojure.</blockquote><p><i>Комментарии открыты: в каких проектах вы наблюдали, как неправильный выбор языка негативно отразился на продукте?</i></p>]]></content:encoded>
    </item>
    <item>
      <title>В ESET нашли первый ИИ-вымогатель PromptLock — написан на Go, крадёт и шифрует данные</title>
      <link>https://tproger.ru/news/v-eset-nawli-pervyj-ii-vymogatel-promptlock---napisan-na-go--kradyot-i-wifruet-dannye</link>
      <comments>https://tproger.ru/news/v-eset-nawli-pervyj-ii-vymogatel-promptlock---napisan-na-go--kradyot-i-wifruet-dannye?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/v-eset-nawli-pervyj-ii-vymogatel-promptlock---napisan-na-go--kradyot-i-wifruet-dannye</guid>
      <description><![CDATA[<p>ESET обнаружила первый ИИ-вымогатель PromptLock: он написан на Go, генерирует Lua-скрипты с помощью AI и шифрует данные на Windows и Linux</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/v-eset-nawli-pervyj-ii-vymogatel-promptlock---napisan-na-go--kradyot-i-wifruet-dannye">В ESET нашли первый ИИ-вымогатель PromptLock — написан на Go, крадёт и шифрует данные</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Искусственный интеллект]]></category>
      <category><![CDATA[Windows]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Lua]]></category>
      <category><![CDATA[Хакеры]]></category>
      <category><![CDATA[Кибербезопасность]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 28 Aug 2025 04:57:30 GMT</pubDate>
      <content:encoded><![CDATA[<p>Компания ESET, известная своим антивирусом, <a href="https://www.welivesecurity.com/en/ransomware/first-known-ai-powered-ransomware-uncovered-eset-research/">сообщила</a> о выявлении первого в истории вымогателя, использующего искусственный интеллект. Новый вирус получил название <i>PromptLock</i>.</p><p>Несмотря на то, что пока нет подтверждений использования PromptLock в реальных атаках, эксперты считают находку важным предупреждением: злоумышленники уже научились внедрять ИИ в инструменты для автоматизированных кибератак.</p><h2>Что умеет PromptLock</h2><p>По данным ESET, PromptLock:</p><ul><li>написан на языке <b>Golang</b>, с версиями для <b>Windows</b> <b>и Linux</b>;</li><li>использует <b>ИИ-модель gpt-oss-20b</b> через локальный API Ollama;</li><li><b>генерирует вредоносные Lua-скрипты на лету</b>, которые сканируют файловую систему, выбирают цели для атаки, шифруют и похищают данные;</li><li>потенциально способен <b>уничтожать данные</b>, но эта функция пока не реализована.</li></ul><p>Фактически, вирус на ходу использует ИИ, чтобы адаптировать поведение скриптов в зависимости от окружения.</p><p>Это делает его особенно опасным: поведение может меняться при каждом запуске, а скрипты — генерироваться динамически, что усложняет обнаружение.</p><h2>Зачем в вирусе нужен ИИ</h2><p>Искусственный интеллект используется не для общения с жертвой или фишинга — он создаёт исполняемый вредоносный код на основе <b>заранее заданных подсказок</b> (промтов). То есть, вместо статического набора функций, злоумышленники получают возможность модифицировать поведение вируса под любую цель и инфраструктуру.</p><blockquote>Именно такие примеры показывают, как ИИ может автоматизировать все этапы атаки — от разведки до кражи данных. Подобные инструменты меняют масштаб и скорость атак</blockquote><h2>Почему это тревожный сигнал</h2><p>Хотя PromptLock пока выглядит как <b>прототип или доказательство концепции</b>, его появление сигнализирует об одном: инструменты на базе ИИ становятся доступными не только бизнесу, но и киберпреступникам.</p><p>Теперь для создания продвинутого вредоносного ПО не обязательно быть опытным программистом — достаточно задать правильный промпт. Сама угроза особенно актуальна в контексте:</p><ul><li>распространения <b>локальных моделей</b> и open-source решений;</li><li><b>снижения технического порога</b> входа для атакующих;</li><li>роста интереса APT-групп к <b>ИИ-автоматизации атак</b>.</li></ul><h2>Что делать</h2><p>Эксперты рекомендуют:</p><ul><li>пересмотреть защиту ИТ-инфраструктуры от<b> динамически генерируемых скриптов</b>;</li><li>уделить внимание <b>аномалиям в поведении программ</b>, а не только сигнатурам;</li><li>следить за <b>новыми классами угроз с участием ИИ</b>.</li></ul>]]></content:encoded>
    </item>
    <item>
      <title>Релиз Go 1.25: умный GOMAXPROCS для контейнеров, ускоренный на 40% GC и «черный ящик» для отладки</title>
      <link>https://tproger.ru/news/reliz-go-1-25--umnyj-gomaxprocs-dlya-kontejnerov--uskorennyj-na-40--gc-i--chernyj-yashhik--dlya-otladki</link>
      <comments>https://tproger.ru/news/reliz-go-1-25--umnyj-gomaxprocs-dlya-kontejnerov--uskorennyj-na-40--gc-i--chernyj-yashhik--dlya-otladki?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/reliz-go-1-25--umnyj-gomaxprocs-dlya-kontejnerov--uskorennyj-na-40--gc-i--chernyj-yashhik--dlya-otladki</guid>
      <description><![CDATA[<p>Go 1.25 получил container-aware GOMAXPROCS, GC быстрее на 40%, «черный ящик» Flight Recorder и новые инструменты для отладки и тестирования</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/reliz-go-1-25--umnyj-gomaxprocs-dlya-kontejnerov--uskorennyj-na-40--gc-i--chernyj-yashhik--dlya-otladki">Релиз Go 1.25: умный GOMAXPROCS для контейнеров, ускоренный на 40% GC и «черный ящик» для отладки</a>»</p>]]></description>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[JSON]]></category>
      <category><![CDATA[Отладка]]></category>
      <category><![CDATA[Windows]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[macOS]]></category>
      <category><![CDATA[ARM]]></category>
      <category><![CDATA[Kubernetes]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 13 Aug 2025 07:52:43 GMT</pubDate>
      <content:encoded><![CDATA[<p>Состоялся <a href="https://go.dev/doc/go1.25">релиз</a> Go 1.25. Разработчики заметно улучшили рантайм и инструменты, при этом не изменяя сам язык.</p><p>Одно из главных новшеств — <b>container-aware GOMAXPROCS</b>: теперь по умолчанию значение GOMAXPROCS учитывает лимиты CPU в cgroup.</p><p>На Linux это позволит процессам внутри контейнеров (например, в Kubernetes) автоматически адаптировать использование процессорных ресурсов к выделенной квоте.</p><p>Параметр обновляется динамически, если лимиты меняются, и может быть отключен через переменные окружения.</p><h2>Новый сборщик мусора — до 40% быстрее</h2><p>В экспериментальном режиме появился <b>garbage collector нового поколения</b> с улучшенной локальностью и масштабируемостью.</p><p>Он особенно эффективен в приложениях с большим количеством мелких объектов, снижая накладные расходы на GC на 10–40%. Включается через GOEXPERIMENT=greenteagc.</p><h2>Trace Flight Recorder: отладка по горячим следам</h2><p>Введен <b>runtime/trace.FlightRecorder</b> — «черный ящик» для приложений на Go.</p><p>Он постоянно пишет трейс в кольцевой буфер, позволяя при наступлении события выгрузить последние секунды исполнения в файл.</p><p>Нововведение значительно упрощает отладку редких и трудно воспроизводимых багов.</p><h2>Другие изменения в рантайме и инструментах</h2><ul><li>Исправлена ошибка компилятора с отложенной проверкой nil, из-за которой некорректный код мог выполняться без паники.</li><li>Добавлена поддержка DWARF5 — меньше отладочной информации и быстрее линковка.</li><li>Улучшено выделение памяти для слайсов — быстрее в ряде сценариев.</li><li>В Linux теперь можно видеть имена анонимных VMA ([anon: Go: heap]) в отладочных инструментах ядра.</li><li>Новый пакет testing/synctest для тестирования конкурентного кода с виртуальным временем.</li><li>Экспериментальный пакет encoding/json/v2 с ускоренным парсингом и расширенной конфигурацией маршалера.</li><li>Новый метод WaitGroup.Go для удобного запуска горутин с учетом синхронизации.</li></ul><h2>Платформенные изменения</h2><p>Go 1.25 требует macOS 12 и выше. 32-битная Windows/ARM-платформа будет удалена в следующем релизе.</p><p>На RISC-V появился режим сборки плагинов и поддержка профиля RVA23U64.</p>]]></content:encoded>
    </item>
    <item>
      <title>Generics в Go: почему их ждали, а массово не используют?</title>
      <link>https://tproger.ru/articles/generics-v-go--pochemu-ih-vse-zhdali--a-massovo-ne-ispolzuyut-</link>
      <comments>https://tproger.ru/articles/generics-v-go--pochemu-ih-vse-zhdali--a-massovo-ne-ispolzuyut-?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Вадим Егорцев]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/generics-v-go--pochemu-ih-vse-zhdali--a-massovo-ne-ispolzuyut-</guid>
      <description><![CDATA[<p>Сообщество Go годами ждало дженерики — и получило их, но массового внедрения не произошло. Почему разработчики не спешат переписывать код с использованием обобщённых типов?</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/generics-v-go--pochemu-ih-vse-zhdali--a-massovo-ne-ispolzuyut-">Generics в Go: почему их ждали, а массово не используют?</a>»</p>]]></description>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Архитектура приложений]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 08 Aug 2025 14:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Создателей Go 13 лет атаковали просьбами добавить дженерики. Мечта сбылась: новая функция должна была избавить от дублирования кода, упростить работу с алгоритмами и сделать типы более безопасными.</p><p><b>Заметили, что массового внедрения не произошло?</b> Разработчики не спешат переписывать рабочий код на дженериках.</p><p><b>По каким причинам обобщённые типы оказались невостребованными?</b> — ответим на этот вопрос вместе с участниками тг-канала <a href="https://t.me/golangl">Golang GO</a>.</p><h2>Почему дженерики не вытеснили интерфейсы?</h2><p>Интерфейсы задают структуру программы: реализуют паттерны декоратора, роутера, зависимости. Дженерики лишь усиливают существующие интерфейсы, делают их безопаснее.</p><p>Разработчики, ожидавшие революцию в проектировании, <a href="https://www.reddit.com/r/golang/comments/zuqalh/comment/j1oe3yd/?utm_source=share&amp;utm_medium=web3x&amp;utm_name=web3xcss&amp;utm_term=1&amp;utm_content=share_button">обнаружили</a>, что дженерики годятся только для узкого пула задач.</p><blockquote>Тащить их везде может быть чревато не только потерей производительности, но и рефакторингом больших объёмов кода. Далеко не каждая компания сейчас потянет такие затраты. Тем более, если неясны перспективы.</blockquote><p>Наиболее оправданный случай использования дженериков — замена interface{} в местах, где тип известен на этапе компиляции:</p><h2>Когда всё-таки использовать дженерики?</h2><p>Практика показывает, что обобщённые типы <a href="https://www.reddit.com/r/golang/comments/u5m7pb/now_that_golang_has_generic_types_how_do_you_plan/?tl=ru">нашли применение</a> в конкретных областях.</p><blockquote>У нас они часто используются: много дженерик-функций для кеширования, маппингов, сохранения в базы данных, передачи по gRPC, работы с брокерами, почти вся CRUD-админка на дженериках. Из плюсов — меньше кода, из минусов — иногда сложно понять, что происходит с конкретной сущностью</blockquote><h3>1. Пулы соединений и кэширование</h3><p>Наиболее очевидное применение дженериков — создание типизированных контейнеров.</p><p>Например, этот пул соединений будет работать с любым типом ресурсов, поддерживающих закрытие:</p><p>Аналогично с кэшированием. Можно создавать строго типизированный кэш, который возвращает значения правильного типа на этапе компиляции:</p><h3>2. Математические операции</h3><p>Дженерики избавляют от дублирования кода для разных числовых типов:</p><h3>3. Функции высшего порядка</h3><p>С появлением дженериков появилась возможность создавать типобезопасные функции высшего порядка для работы с коллекциями:</p><blockquote>Я не представляю, как можно обойтись без дженериков, если идёт речь про обработку больших массивов разнообразных данных, где нужны собственные структуры и алгоритмы.</blockquote><h3>4. Обёртки для API и протоколов</h3><p>Так выглядит обёртка ответа с типизированным полем результата на дженериках:</p><p>Компилятор гарантирует соответствие типов на этапе компиляции. До дженериков приходилось использовать json.RawMessage и распаковывать на уровне роутинга.</p><h3>5. Репозитории и CRUD-операции</h3><p>Типизированные интерфейсы для работы с данными:</p><h2>Как дженерики повлияли на тесты?</h2><p>Однозначно стало проще создавать универсальных хелперов для тестирования:</p><h2>Почему дженерики в Go не такие, как в других языках?</h2><p>Отсутствие обобщённых типов болезненно воспринимали разработчики, перешедшие в Go из Java, C#, C++ и других языков с дженериками.</p><blockquote>Добавление функционального программирования — это тренд Rust, Kotlin и других современных языков. Без дженериков в Go было бы сложно переписывать код в функциональной парадигме с других языков.</blockquote><p>Реализация фичи подвела: гошные методы не имеют собственные параметры типа. Методы наследуют дженерик-параметры самой структуры, и нельзя добавить новые.</p><p>Например, это работает:</p><p>А такая функция уже не скомпилируется:</p><p>Привычные паттерны из Rust, Java или C# в Go просто не реализуемы. Вместо методов приходится использовать функции:</p><h2>Как дженерики изменили разработку на Go?</h2><p>Типовые задачи в Го до появления дженериков решали иначе. Приходилось использовать пустой interface{}, генерировать типобезопасный код с помощью go:generate, stringer.</p><p>Несмотря на недостатки, дженерики поменяли подход к разработке.</p><blockquote>Если у вас всё строится на дженериках, то можно считать, что нужен совершенно другой инструментарий и образ мышления для работы с таким кодом.</blockquote><p>Обобщённые типы активно используются в библиотеках. Взять тот же samber/lo и функции Map, Filter, Reduce на дженериках. Ещё стандартная библиотека пополнилась пакетами slices и maps.</p><p>Что касается производительности — ожидания не оправдались. Думали, что избавились от преобразований типов и получили прирост скорости? На деле разница минимальна. В реальных приложениях узкое место не в типах, а в работе БД, сетевых запросах или бизнес-логике.</p><h2>Что в итоге?</h2><ul><li>Интерфейсы остаются основой архитектуры Go-приложений, дженерики их дополняют, но не заменяют.</li><li>Обобщённые типы полезны только для конкретных задач. Применяйте по необходимости, когда дженерики устраняют дублирование кода или повышают типобезопасность.</li><li>Упрощайте тестирование — универсальные хелперы для проверок и утверждений.<br /></li><li>Избегайте преждевременного обобщения — не пишите код через дженерики «на всякий случай».</li><li>Параметры типов лучше всего подходят для контейнеров, кэшей, математических функций.</li><li>Привычные паттерны из других языков не реализуемы — приходится адаптировать подходы под Go.</li><li>Усложнение понимания кода — иногда непросто разобраться, что происходит с конкретной сущностью.</li></ul><p><i>Поделитесь опытом использования дженериков — где они реально помогли, а где оказались излишними? Удивите примерами удачного и неудачного применения!</i></p>]]></content:encoded>
    </item>
    <item>
      <title>7 курсов, с которых реально стартуют в IT в 2025</title>
      <link>https://tproger.ru/articles/7-kursov--s-kotoryh-realno-startuyut-v-it-v-2025</link>
      <comments>https://tproger.ru/articles/7-kursov--s-kotoryh-realno-startuyut-v-it-v-2025?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Татьяна Жукова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/7-kursov--s-kotoryh-realno-startuyut-v-it-v-2025</guid>
      <description><![CDATA[<p> Хотите начать карьеру в IT с нуля? Рассказываем, какие курсы в 2025 реально помогают попасть в IT, даже без опыта и тех.образования.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/7-kursov--s-kotoryh-realno-startuyut-v-it-v-2025">7 курсов, с которых реально стартуют в IT в 2025</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Тестирование]]></category>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Навыки]]></category>
      <category><![CDATA[HR]]></category>
      <category><![CDATA[GitLab]]></category>
      <category><![CDATA[Образование]]></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>
      <category><![CDATA[Кибербезопасность]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 11 Jun 2025 15:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>В 2025 году старт карьеры в IT намного сложнее, чем несколько лет назад. Работодатели больше не берут новичков только за диплом или сертификат — теперь всем нужны реальные практические навыки, которые можно сравнить с опытом работы.</p><p>В этой подборке — 7 курсов, после которых реально получить первую работу в IT за 3–6 месяцев.</p><h2>Почему в 2025 попасть в IT и легче, и сложнее одновременно</h2><p>Войти в IT в 2025 реально, но рынок сильно изменился. С одной стороны, спрос на junior-специалистов вернулся: компании снова набирают новичков, открывают стажировки и гибридные программы. Но конкуренция стала выше, а фильтры — жёстче.</p><h3>Что легче</h3><ul><li>После карьерного спада 2022–2023 спрос на junior-специалистов начал восстанавливаться. Появилось больше стажировок и вакансий для начинающих. Согласно отчёту<a href="https://www.roberthalf.com/us/en/insights/research/data-reveals-which-technology-roles-are-in-highest-demand"> Robert Half</a>, начать успешную карьеру могут инженеры по данным, DevOps-инженеры и разработчики ПО. Однако конкуренция остаётся высокой, и работодатели ожидают от кандидатов не только базовых знаний, но и быстрой адаптации к новым инструментам.</li><li>Образование и работа в IT всё чаще переходят в <a href="https://trends.rbc.ru/trends/social/63a374dd9a794731007f44da">гибридный </a>формат: можно совмещать онлайн- и офлайн-обучение, работать удалённо и периодически встречаться в офисе.</li></ul><h3>Что сложнее</h3><ul><li>Конкуренция выше, чем раньше. Даже на стартовые позиции часто подаётся по сотне кандидатов.</li><li>Работодатели ждут не просто знаний или диплома, а быстрой адаптации.</li></ul><h3>Что изменилось в 2025 по сравнению с 2020–2024</h3><p>Во-первых, образование стало прагматичнее. С 2020 по 2022 год рынок был наводнен короткими курсами «на джуна». В 2025-м большинство таких школ либо закрылись, либо переформатировались: люди устали платить за теорию без практики. Сейчас ценятся программы, в которых есть командные проекты, ревью от наставников, работа с Git и проектный пайплайн, близкий к реальному.</p><p>Во-вторых, работодатели всё чаще оценивают кандидатов по их реальным навыкам и опыту, а не по формальному образованию. Согласно <a href="https://dzen.ru/a/aB4XGcZqiXGuE2wI">прогнозам</a>, 39% текущих навыков работников устареют к 2030 году, что подчеркивает необходимость постоянного обновления и адаптации.</p><p>Так, расширяются границы образования. А вместе с ними – появляются онлайн-курсы.</p><h2>7 курсов, с которых начинают карьеру в IT</h2><h3>1. Kata Academy — GO-разработчик</h3><p><a href="https://kata.academy/courses/go-backend-developer?utm_source=web&amp;utm_medium=article&amp;utm_campaign=go&amp;utm_content=tproger_11_06_25">Ссылка на курс</a></p><p>Go (Golang) — это билет в backend-разработку, где в 2025 году крутятся большие деньги и хардовые задачи. Язык, созданный Google, ценят за скорость и простоту, а компании от стартапов до гигантов вроде Яндекса выстраиваются в очередь за Go-разработчиками. Курс от Kata Academy учит писать серверный код, работать с SQL, Git, Linux и Docker, чтобы выпускники могли строить масштабируемые приложения.</p><h4>📚Что получают выпускники</h4><p>На курсе студент осваивает Go и смежные технологии, создает портфолио из практических проектов, готовится к собеседованиям с поддержкой школы и приходит к главной цели — устраивается на работу по новой специальности. Кроме этого:</p><ul><li>Есть карьерная поддержка: резюме, собеседования, вакансии;</li><li>В договоре — гарантированная зарплата от 120 000 ₽ (может быть выше).</li></ul><h4>🎓Длительность и формат</h4><p>Курс проводится полностью онлайн. Длительность обучения — 9 месяцев, включая подготовку к собеседованиям. Нагрузка: от 25 часов обучения в неделю (3-4 часа в день), есть дедлайны. Выпускник устраивается на работу после курса, в течение 1-2 месяцев (в среднем).</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-06-11/8eb864d0-b80e-40a4-9de5-df9ee68d9c5d.png" alt="" /><figcaption>Скриншот траектории обучения с сайта программы</figcaption></figure><h4>👥Кому подойдет</h4><ul><li>Новичкам без опыта в программировании;</li><li>Студентам и начинающим разработчикам, которые хотят освоить Go;</li><li>Может быть интересен тем, кто работает во фронтенде или техподдержке и хочет сменить направление.</li></ul><p>Не требует знаний математики и программирования — рассчитан на обучение с нуля.</p><h4>🏆Возможности после курса</h4><p>На сайте указано, что выпускники устраиваются в компании, такие как Яндекс, Альфа-Банк и Kaspersky, часто в течение первого месяца после завершения основной программы курса. Если выпускник не найдет работу с зарплатой от 120.000 рублей, то оплачивать обучение не придется.</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-06-11/1a7f9220-659a-4942-b49a-f4cfd1c06651.png" alt="" /><figcaption>Отзывы с сайта программы</figcaption></figure><h4>💸 Стоимость и условия участия</h4><p>Есть два варианта обучения:</p><ul><li>Интенсивное (стоимость — 110 000 рублей во время учебы плюс 20% от зарплаты в первый год работы). Для тех, кто живет в Москве или Санкт-Петербурге, или готов туда переехать.</li><li>Асинхронное (стоимость — 262 000 рублей). Обучение в своем темпе, нет дедлайнов. Можно искать работу в любом городе-миллионнике, если не получится устроиться — есть гарантия возврата денег.</li></ul><h3>2. CyberEd — Пентестер</h3><p><a href="https://cyber-ed.ru/b2c-courses/pentester/?utm_medium=tproger&amp;utm_campaign=7kursov">Ссылка на курс</a></p><p>Пентест (тестирование на проникновение) — это процесс поиска уязвимостей в IT-системах путем имитации атак хакеров.</p><p>Курс обучает анализу защищенности веб-приложений, сетей и инфраструктуры, а также использованию инструментов вроде Nessus и Nmap.</p><p>В программе будут техники атак, методы их обнаружения и составление отчетов. Курс готовит специалистов к реальным задачам в области кибербезопасности для работы в топовых компаниях.</p><h4>📚Что получают выпускники</h4><ul><li>Выпускники получают диплом о профессиональной переподготовке или удостоверение о повышении квалификации (зависит от формата).</li><li>Студенты формируют цифровое резюме и портфолио на основе практических заданий.</li><li>Все студенты проходят карьерную подготовку — от тренировки прохождения собеседований до подбора стажировок и вакансий.</li></ul><h4>🎓Длительность и формат</h4><p>Обучение длится 24 недели (365 академических часов) и проходит полностью онлайн. Есть два формата:</p><ul><li>Синхронный формат — с расписанием и онлайн-занятиями в группе. Включает 24 онлайн-семинара по 4 часа, регулярную обратную связь от наставников и карьерные консультации.</li><li>Асинхронный формат — без привязки ко времени: обучение проходит в удобном для студента темпе. Доступ ко всем материалам курса, заданиям и модулям открыт сразу.</li></ul><p>Оба формата включают более 100 практических заданий, поддержку менторов и итоговый проект.</p><h4>👥Кому подойдет</h4><ul><li>Айтишникам, которые хотят научиться пентесту или прокачаться в кибербезопасности.</li><li>Системным администраторам, веб-разработчикам, специалистам по ИБ, а также джунам и миддлам из пентеста, Blue Team или AppSec.</li></ul><p>В общем, полезно будет тем, у кого уже есть хотя бы год опыта и кто хочет перейти на следующий уровень.</p><h4>🏆Возможности стажировки и трудоустройства</h4><p>Выпускники устраиваются на позиции инженеров по безопасности или пентестеров, в том числе в крупные IT-компании. По отзывам студентов, некоторые находят стажировку уже на 4 месяц обучения, а часть получает постоянные позиции в течение 1 года после финала курса.</p><h4>💸 Стоимость и условия участия</h4><p>138 000 рублей за синхронный формат, 74 000 рублей за асинхронный. Доступна рассрочка на 2 года — 6 900 рублей в месяц.</p><p>Для поступления необходимо подать заявку через сайт. Точные требования к участникам не указаны, но курс предполагает наличие базовых знаний IT.</p><h3>3. Яндекс Практикум — Инженер по тестированию</h3><p><a href="https://practicum.yandex.ru/qa-engineer/?utm_source=partners&amp;utm_medium=cpc&amp;utm_campaign=tproger_cpc_RF_Prog_qaEn_b2c_Article_None_None">Ссылка на курс</a></p><p>Инженер по тестированию (QA-инженер) проверяет качество программных продуктов: ищет ошибки  в веб-приложениях, мобильных приложениях и API.</p><p>В программе курса Яндекс Практикума будут основы ручного тестирования, работа с тестовой документацией и инструментами, базовые навыки автоматизации, а также отдельные модули по информационной безопасности, Figma, Python и SQL.</p><p>Из интересного: обучение построено по принципу симуляции стажировки: студенты работают над проектами, которые похожи на реальные рабочие задачи.</p><h4>📚Что получают выпускники</h4><ul><li>В финале курса Практикум выдаёт диплом о профессиональной переподготовке.</li><li>Также у выпускников остаётся портфолио из 7 учебных проектов (в расширенной версии курса — из 9). Среди них, например, — итоговая работа над сервисом Яндекса (тестирование Яндекс.Маршрутов и т.д.).</li><li>Дополнительно открывается доступ к модулю по YandexGPT и YandexART.</li><li>В течение семи месяцев после окончания обучения доступна карьерная поддержка. При желании можно набираться опыта в Мастерской Практикума — это агентство внутри Практикума, где выпускники работают над задачами реальных заказчиков.</li></ul><h4>🎓Длительность и формат</h4><ul><li>Курс рассчитан на пять месяцев — это 318 академических часов, в среднем около 20 часов в неделю. Обучение проходит онлайн.</li><li>Теоретическая часть будет в виде интерактивного учебника, а практические задачи выполняются по спринтам: каждые три недели — новый проект.</li><li>Воркшопы и консультации с наставниками проходят по расписанию. У студентов есть дедлайны по проектным заданиям.</li></ul><h4>👥Кому подойдет</h4><ul><li>Новичкам без опыта в IT — студентам, тем, кто хочет сменить профессию, и специалистам из смежных областей.</li><li>Техническое образование и навыки программирования не требуются, но базовый английский будет плюсом, особенно если планируете развиваться в сторону автоматизации.</li></ul><h4>🏆Возможности стажировки и трудоустройства</h4><p>После завершения программы карьерный центр помогает в трудоустройстве (доступны карьерная поддержка в течение 6+ месяцев после обучения, фриланс-трек для тех, кто хочет работать на себя, вакансии и стажировки от партнёров и мастерская проектов). В среднем, стажёры зарабатывают около 52 000 рублей, джуниоры — 76 000, мидлы — 142 000 рублей.</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-06-11/20143499-8f64-456d-84d7-a9fb2f205b5f.png" alt="" /><figcaption>Отзывы студентов. Скриншот с сайта программы</figcaption></figure><h4>💸 Стоимость и условия участия</h4><ul><li>Junior-трек. Подходит для старта в тестировании. 77 000 ₽ — при полной оплате; 16 500 ₽/мес. × 5 месяцев — при рассрочке.</li><li>Расширенный трек. Тут больше практики и навыков, чтобы быстрее вырасти до мидла. 148 000 ₽ — при полной оплате; 18 500 ₽/мес. × 9 месяцев — при рассрочке.</li><li>От новичка до автоматизатора. Сразу две профессии: ручное и автоматизированное тестирование. 156 000 ₽ — при полной оплате. 20 000 ₽/мес. × 9 месяцев — при рассрочке.</li></ul><p>Перед стартом можно пройти бесплатный вводный модуль на всех треках. Также получить налоговый вычет или частично вернуть деньги, если не понравится.</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-06-11/c167cf4d-f1f8-4308-ad0d-75931e3b8048.png" alt="" /><figcaption>Как выглядит вводный бесплатный модуль. Скриншот с сайта программы</figcaption></figure><h3>4. Rebrain — Мини-практикум Golang с нуля</h3><p><a href="https://rebrainme.com/golang-s-nulya/?utm_source=tproger&amp;utm_medium=post&amp;utm_campaign=devops_mako&amp;utm_content=27052025">Ссылка на курс</a></p><p>Мини-практикум от Rebrain знакомит с основами Go, включая синтаксис, работу с каналами, контекстами и микросервисами. Программа ориентирована на практическое освоение языка через выполнение задач, моделирующих реальные сценарии backend-разработки.</p><h4>📚Что получают выпускники</h4><p>Выпускники получают сертификат Rebrain, подтверждающий освоение основ Go. В программу входят более 10 практических задач, демонстрирующих навыки работы с языком и современными подходами к разработке.</p><p>Доступ к комьюнити и онлайн-мероприятиям Rebrain позволяет продолжать обучение и налаживать профессиональные связи. Теоретические материалы остаются доступными навсегда.</p><h4>🎓Длительность и формат</h4><ul><li>Курс длится около 2 недель, но продолжительность зависит от темпа студента.</li><li>Программа полностью онлайн и асинхронная, что позволяет учиться в удобное время без привязки к расписанию.</li><li>Формат текстовый, без видеолекций, с акцентом на практику (90% времени).</li></ul><p>Студенты выполняют более 10 задач, а менторы на связи для обратной связь и поддержки.</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-06-11/2fcb2893-3d65-4211-a18a-2adde491fc05.png" alt="" /><figcaption>Скриншот программы практикума с сайта Rebrain</figcaption></figure><h4>👥Кому подойдет</h4><ul><li>Студентам с потенциалом для Go;</li><li>Начинающим разработчикам без практического опыта;</li><li>Специалистам из смежных IT-направлений.</li></ul><p>Здесь нужны минимальные навыки работы с системами контроля версий (GitHub/GitLab), но глубокие знания программирования не требуются.</p><h4>🏆Возможности стажировки и трудоустройства</h4><p>HR-центр Rebrain помогает выпускникам с поиском работы, предоставляя консультации по резюме и подготовке к собеседованиям.  Участники комьюнити Rebrain могут попробовать себя в хакатонах и профессиональных событиях, где легче найти работу.</p><h4>💸 Стоимость и условия участия</h4><p>Стоимость курса — 14 990 рублей при полной оплате или 1 249 рублей в месяц при рассрочке на 12 месяцев. Для поступления достаточно подать заявку через сайт; специальных требований, кроме базового понимания IT, нет. Курс подходит для самостоятельного обучения, но требует дисциплины из-за асинхронного формата.</p><h3>5. Systems.Education — Системный аналитик / Проектировщик корпоративных информационных систем</h3><p><a href="https://systems.education/systems-analyst-bootcamp?utm_source=social&amp;utm_medium=tproger&amp;utm_campaign=rp">Ссылка на курс</a></p><p>Цель программы — получить профессию системного аналитика, которая соответствует актуальным требованиям вакансий на рынке.</p><p>На курсе от Systems.Education вы за 3 месяца пройдёте реальный кейс за счёт работы с:</p><ul><li>Формальным моделированием бизнеса и бизнес-проблемы: Event Storming, BPMN, Opportunity canvas.</li><li>Разработкой пользовательских требований: Impact map, User story map, Use case diagram, Use case scenario.</li><li>Концептуальным проектированием ИТ-решений: моделирование предметной области, UML диаграмма состояний, Контекстная диаграмма, Концептуальная модель данных, Макеты приложений.</li><li>Спецификацией требований к системе: Функциональные требования к системе, Нефункциональные требования к системе, Требования к информационной безопасности, Системные алгоритмы.</li><li>Техническим проектированием ИТ-решений: Диаграмма взаимосвязи объектов, диаграммы в нотации С4, Требования к интеграции, UML диаграмма последовательности, Data flow diagram.</li></ul><h4>📚Что получают выпускники</h4><ul><li>Сертификат на основании лицензии об образовательной деятельности, подтверждающий квалификацию системного аналитика уровней 4 и 5 по российскому профстандарту.</li><li>Портфолио, включающее результаты их учебного проекта.</li><li>Демонстрацию финальных результатов кейса перед приглашенными HR и техническими специалистами из компаний-потенциальных работодателей.</li></ul><h4>🎓Длительность и формат</h4><p>Курс длится 3 месяца (200+ академических часов) и проводится полностью онлайн: 8 часов в неделю — занятия с преподавателем в Zoom, дополнительно — командные и индивидуальные созвоны с ментором. Процесс обучения осуществляется в командах, в которых участники работают над реальным кейсом.</p><p>Каждую неделю студенты взаимодействуют с заказчиком, роль которого выполняет ведущий специалист школы SE: команды проводят с ним интервью, собирают требования, выявляют проблемы бизнеса, формируют цель разработки, определяют границы проекта и утверждают концепцию решения. Под руководством ментора переходят от системного анализа к проектированию информационной системы: выбирают подходящий архитектурный паттерн и тип базы данных, проектируют поток информации через интеграции API и брокеров. Каждую неделю студенты получают обратную связь от менторов.</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-06-11/fba4356b-cef4-4b24-b693-1800ca41b24e.png" alt="" /><figcaption>Скриншот отзывов с сайта программы</figcaption></figure><h4>👥Кому подойдет</h4><ul><li>Не системным аналитикам, которые хотят освоить практики проектирования информационных систем и/или стать системными аналитиками.</li><li>Системным аналитикам, которые хотят получить поддержку старших коллег при отработке практик проектирования, а также систематизировать знания в области проектирования ИС.</li></ul><h4>🏆Возможности стажировки и трудоустройства</h4><ul><li>Защитите итоговый проект прямо перед HR и техспецами из компаний.</li><li>Получите портфолио из настоящих проектных документов (артефактов) — всё, что требуют работодатели на позиции младшего системного аналитика.</li><li>В течение всего обучения вас будут сопровождать менторы-практики: помогут с проектом, дадут фидбек, подготовят к собеседованиям.</li></ul><p>По статистике школы, выпускники за год могут дорасти до уровня Middle-аналитика.</p><h4>💸 Стоимость и условия участия</h4><ul><li>205 000 рублей для физических лиц</li><li>255 000 рублей для юридических лиц.</li></ul><p>Действует скидка на раннее бронирование. Потоки стартуют раз в три месяца. Для поступления требуется подать заявку через сайт. Базовые знания IT-процессов желательны, но специальных тестов нет. Гарантируется 100% возврат средств при отказе до начала обучения.</p><h3>6. Karpov.Courses — Аналитик данных</h3><p><a href="https://karpov.courses/analytics?utm_source=tproger&amp;utm_medium=partners&amp;utm_campaign=1_dscoursestartda_tproger_partners_article_course_all_ds_kc">Ссылка на курс</a></p><p>Курс от karpov.courses учит работать с Python, SQL, Power BI и другими нужными инструментами для анализа, визуализации и автоматизации. В программе много практики: решаете реальные задачи — A/B-тесты, расчёт метрик, анализ больших данных, работа с хранилищами.</p><h4>📚Что получают выпускники</h4><ul><li>Сертификат, подтверждающий освоение программы, и портфолио из более чем 10 учебных проектов, включая работу с реальными бизнес-кейсами.</li><li>Доступ к рабочей инфраструктуре и более 490 заданиям, моделирующим задачи аналитиков.</li><li>Карьерную поддержку.</li></ul><p>Материалы курса остаются доступны бессрочно.</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-06-11/3c48685a-bca9-47ac-9375-9fc377a3f790.png" alt="" /><figcaption>Что предлагает программа. Скриншот с сайта Karpov.courses</figcaption></figure><h4>🎓Длительность и формат</h4><p>Курс длится 5 месяцев и проводится полностью онлайн на LMS-платформе. Студенты проходят уроки и выполняют домашние задания в удобном темпе, с ежедневной поддержкой кураторов и экспертов.</p><h4>👥Кому подойдет</h4><ul><li>Новичкам без опыта в IT, студентам, чтобы освоить аналитику данных.</li><li>Маркетологам и менеджерам, чтобы рассчитывать метрики бизнеса и их эффективность.</li><li>Специалистам с релевантным опытом (джуниорам и выше).</li></ul><p>Базовые навыки работы с данными (например, Excel или SQL) полезны, но не обязательны.</p><p>По итогу — будете уметь вытаскивать инсайты из данных, делать понятные дашборды и находить ответы для решения бизнес-задач.</p><h4>🏆Возможности стажировки и трудоустройства</h4><p>Karpov.Courses предлагает карьерную поддержку по поиску работы, чат с консультантами и доступ к вакансиям от партнеров.</p><p>Выпускники могут стать младшими аналитиками данных или Data Scientist с медианной зарплатой на старте 100–120 000 рублей, а если уровень мидл — от 180 000 рублей. По данным школы, 3 месяца — средний срок успешного трудоустройства.</p><h4>💸 Стоимость и условия участия</h4><p>Стоимость базового тарифа — 80 000 рублей при единовременной оплате. Доступна беспроцентная рассрочка на 24 месяца (платёж примерно 4 408 рублей в месяц).</p><p>Для поступления достаточно подать заявку через сайт, специальных требований или вступительных тестов нет.</p><h3>7. Нетология — Инженер по тестированию</h3><p><a href="https://netology.ru/programs/qa-middle#/program_variants">Ссылка на курс</a></p><p>Инженер по тестированию (QA-инженер) отвечает за проверку качества программного обеспечения, выявляя ошибки в веб-приложениях, мобильных сервисах и API. Курс от Нетологии обучает ручному и автоматизированному тестированию, включая работу с инструментами и языками программирования (Python, Java, JavaScript).</p><p>Программа предлагает три трека:</p><ul><li>«Ручное тестирование» для новичков;</li><li>«QA-инженер уровня Junior» с основами автоматизации;</li><li>«QA-инженер уровня Middle» с углубленным изучением JavaScript, мобильного и нагрузочного тестирования.</li></ul><p>Студенты работают над реальными кейсами от партнеров — Dragons, OneTwoTrip и GOD.</p><h4>📚Что получают выпускники</h4><ul><li>Диплом о профессиональной переподготовке и портфолио из 5 крупных проектов, включая тестирование сайтов, веб-сервисов, приложений и командный дипломный проект.</li><li>Программа включает до 74 практических заданий, моделирующих реальные задачи тестировщиков.</li><li>Карьерная поддержка предусматривает тестовые собеседования, помощь в составлении резюме и возможность стажировки у партнеров.</li><li>Дополнительно студенты проходят воркшоп по применению нейросетей для автоматизации задач.</li></ul><p>Материалы курса доступны в личном кабинете навсегда.</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-06-11/0c758546-2119-4983-b661-2b66ba079d76.png" alt="" /><figcaption>Обещают официальный диплом. Скриншот с сайта курса</figcaption></figure><h4>🎓Длительность и формат</h4><ul><li>Курс проводится полностью онлайн, длительность зависит от трека: в среднем, 4–6 месяцев.</li></ul><ul><li>Занятия включают вебинары по расписанию (не чаще 2 раз в неделю после 19:00 МСК), видеолекции, тесты и практические задания.</li></ul><ul><li>На обучение требуется 8–10 часов в неделю. Формат сочетает синхронные вебинары с асинхронной работой через личный кабинет.</li></ul><h4>👥Кому подойдет</h4><ul><li>Новичкам без опыта, студентам и специалистам из смежных сфер.</li></ul><ul><li>Трек Junior подходит для начинающих, интересующихся автоматизацией, а трек Middle — для тех, кто хочет углубить навыки и претендовать на более высокие позиции. Базовый английский полезен, но программирование не обязательно для старта.</li></ul><h4>🏆Возможности стажировки и трудоустройства</h4><p>Программа позволяет начать карьеру в ручном тестировании уже через 2 месяца обучения, на фрилансе или в найме.</p><p>Выпускники трека Junior могут начать карьеру младших QA-инженеров (медианная зарплата около 76 000 рублей), а трека Middle — на более сложные роли с зарплатой от 142 000 рублей.</p><h4>💸 Стоимость и условия участия</h4><p>Стоимость зависит от трека (цены указаны с учетом скидки 40%):</p><ul><li>Ручное тестирование: 56 700 рублей (или 2 487 рублей/мес. на 24 месяца)</li><li>QA-инженер уровня Junior: 105 000 рублей (или 3 070 рублей/мес. на 36 месяцев).</li><li>QA-инженер уровня Middle: 130 500 рублей (или 3 816 рублей/мес. на 36 месяцев).</li></ul><p>Для поступления нужно подать заявку через сайт, вступительных тестов нет. Возможен возврат средств в течение 7 дней, если курс не подошел.</p><h2>Как выбрать правильный курс под себя?</h2><p>Выбор IT-курса в 2025 году зависит от ваших интересов, доступного времени и бюджета. Собрали таблицу, чтобы помочь сориентироваться среди представленных программ.</p><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-06-11/0b69693c-0870-4afb-ae44-921e6856ade6.png" alt="" /></figure><figure><img src="https://media.tproger.ru/user-uploads/102593/2025-06-11/4a01e788-550b-4e34-adba-e1ff701d9527.png" alt="" /></figure><h2>FAQ: частые вопросы от новичков</h2><h3>Можно ли войти в IT без высшего образования?</h3><p>Да, можно. Но в некоторых крупных компаниях или госструктурах формальное образование может быть требованием. Если нет профильного образования, стоит выбирать курсы с сильной практической базой и поддержкой трудоустройства.</p><h3>Реально ли устроиться после курсов?</h3><p>Да, но результат зависит от трёх факторов: качества курса, вашей активности и текущего спроса на рынке труда.</p><h3>Что выбрать: универсальный курс или узкую специализацию?</h3><p>Зависит от вашей подготовки:</p><ul><li>Универсальный курс: подходит новичкам. Дает обзор направлений, помогая выбрать специализацию. Минус — знания менее глубокие.</li><li>Узкая специализация: для тех, кто знает, чего хочет. Дает глубокие навыки для конкретной роли, но требует начальной базы или четкой цели.</li></ul><p>Так НЕ надо:</p><ul><li>Брать узкую специализацию «потому что все советуют», без анализа своих склонностей (например, идти в кибербезопасность, хотя нравится работа с данными).</li><li>Выбирать универсальный курс в надежде потом определиться — это растягивает сроки выхода на рынок.</li></ul><p>Новичкам лучше начать с универсального курса, чтобы понять рынок, а затем углубиться в нишу.</p>]]></content:encoded>
    </item>
    <item>
      <title>Разработчики Go окончательно отказались от изменений синтаксиса обработки ошибок</title>
      <link>https://tproger.ru/news/--razrabotchiki-go-okonchatelno-otkazalis-ot-izmenenij-sintaksisa-obrabotki-owibok</link>
      <comments>https://tproger.ru/news/--razrabotchiki-go-okonchatelno-otkazalis-ot-izmenenij-sintaksisa-obrabotki-owibok?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/--razrabotchiki-go-okonchatelno-otkazalis-ot-izmenenij-sintaksisa-obrabotki-owibok</guid>
      <description><![CDATA[<p>Разработчики Go окончательно отказались менять синтаксис обработки ошибок — if err != nil останется с нами надолго, несмотря на жалобы комьюнити</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/--razrabotchiki-go-okonchatelno-otkazalis-ot-izmenenij-sintaksisa-obrabotki-owibok">Разработчики Go окончательно отказались от изменений синтаксиса обработки ошибок</a>»</p>]]></description>
      <category><![CDATA[Google]]></category>
      <category><![CDATA[IDE]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 04 Jun 2025 04:34:05 GMT</pubDate>
      <content:encoded><![CDATA[<p>Команда разработчиков Go официально <a href="https://go.dev/blog/error-syntax">объявила</a>, что не будет менять синтаксис обработки ошибок в языке.</p><p>После шести лет обсуждений, сотен предложений комьюнити и трех масштабных инициатив от самих авторов Go принято решение прекратить попытки — ни одна из предложенных идей не получила достаточной поддержки.</p><h2>Почему это важно</h2><p>Go часто критикуют за избыточную многословность в обработке ошибок. Код вроде:</p><p>становится настолько повторяющимся, что мешает восприятию логики программы. Попытки изменить это начались еще в 2018 году: сначала через check/handle, затем через упрощенный try, и недавно — с предложением использовать ?, как в Rust.</p><p>Однако ни одно из решений не устраивало всех: одно было слишком сложным, другое скрывало управление потоком, третье вызывало путаницу при отладке.</p><p>В каждом случае обсуждения сопровождались сотнями комментариев и сильным разногласием даже внутри команды Google Go.</p><h2>Что теперь?</h2><p>Разработчики решили остановить все инициативы, связанные с изменением синтаксиса ошибок, и закрыть соответствующие предложения без дальнейшего рассмотрения. Причины:</p><ul><li>Ни один из подходов не получил консенсуса. Новая конструкция затронула бы весь экосистемный код, в отличие от, например, дженериков.</li><li>В Go принято правило — «один способ делать вещи». Добавление альтернатив сломало бы этот принцип.</li><li>Большинство пользователей Go на практике привыкают к текущему подходу и не считают его критичным.</li></ul><p>Вместо этого команда сосредоточится на улучшении стандартной библиотеки (например, функций вроде cmp.Or) и инструментах IDE: возможно, они смогут скрывать повторы при чтении кода, не меняя сам язык.</p><h2>А что с жалобами?</h2><p>Ошибки продолжают занимать первое место в списке недовольств пользователей Go (после того как добавили дженерики). Но, как показала практика, не все хотят изменений ради краткости.</p><p>Особенно если это усложнит отладку или приведет к неидоматичному коду. Команда подчеркивает: они по-прежнему готовы выслушивать идеи — но не по синтаксису.</p><p>Вывод: для Go-мира все остается по-старому. Как и 15 лет назад, ошибки проверяются через if err != nil, и так будет еще долго.</p>]]></content:encoded>
    </item>
    <item>
      <title>Конвейер DevOps, часть 3: пайплайны и хуки в Git</title>
      <link>https://tproger.ru/articles/konvejer-devops--chast-3--pajplajny-i-huki-v-git</link>
      <comments>https://tproger.ru/articles/konvejer-devops--chast-3--pajplajny-i-huki-v-git?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Олег Филон]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/konvejer-devops--chast-3--pajplajny-i-huki-v-git</guid>
      <description><![CDATA[<p>В этой серии статей Олег Филон, ментор Эйч Навыки, рассказывает, как прийти к крутому CI/CD пайплайну. Сегодня разбираемся, как работать с пайплайнами и хуками в Git.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/konvejer-devops--chast-3--pajplajny-i-huki-v-git">Конвейер DevOps, часть 3: пайплайны и хуки в Git</a>»</p>]]></description>
      <category><![CDATA[Тестирование]]></category>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[JSON]]></category>
      <category><![CDATA[unix]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[Tor]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[GitLab]]></category>
      <category><![CDATA[Docker]]></category>
      <category><![CDATA[MIT]]></category>
      <category><![CDATA[ICO]]></category>
      <category><![CDATA[QA]]></category>
      <category><![CDATA[Бэкенд]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[CI/CD]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 26 May 2025 10:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Я — Олег Филон,<a href="https://h.careers/curators/oleg-philon"> ментор Эйч Навыки</a> и Senior DevOps Engineer. В этой статье расскажу, как организовать CI/CD пайплайн для контейнеризованного проекта с использованием утилиты make, сравню подходы для Docker и Podman, а также поделюсь хаком с использованием Git bare репозитория для автоматизации деплоя.</p><p>Первые две части лежат здесь: <a href="https://tproger.ru/articles/konvejer-devops--chast-1--kak-organizovat-rabochee-mesto-i-nastroit-oblako-iz-kvm-libvirt">рабочее место/облако</a> и <a href="https://tproger.ru/articles/konvejer-devops--chast-2--polzuemsya-fedora-core-i-mise">Fedora Core/mise</a>.</p><h2>Начало проекта и утилита make</h2><p>Представим идеальную ситуацию: я не только девопс, но и проектный менеджер, выбираю архитектуру проекта, и инструменты, и команду разработчиков, то есть полностью контролирую проект. В жизни такое вряд ли встретишь, но нам это нужно для примера, чтобы рассмотреть разные варианты.</p><p>Первый — классический пайплайн — это утилита make. Обычно она используется для сборки программ из исходного кода. На самом деле make хорошо подходит для решения сразу нескольких задач.</p><ul><li>Первая задача — отслеживание зависимостей одних файлов от других, например, при изменении сервиса пересобрать только соответствующий контейнер.</li><li>Вторая задача, легко реализуемая через make — сборка в один файл много команд или скриптов, чтобы удобно их организовать. Как правило, сборка образа, его загрузка в репо, удаление временных файлов и прочее делается несколькими рутинными командами. Точно так же можно поместить в Makefile команды запуска сервисов и тестирование приложения локально.</li><li>Если эти этапы прошли успешно, можно выполнить коммит кода в репо проекта, сделать деплой в dev или stage environment. В github actions это называется jobs и steps. В make такая группа команд называется целью, она указывается параметром при вызове.</li></ul><p>Так, несмотря на разную терминологию, по сути можно создать полноценный пайплайн для современного проекта с контейнеризованными сервисами.</p><h3>Разбираемся на практике</h3><p>Возьмём для примера проект с прокси сервером traefik и бэкендом на golang из репозитария <a href="https://github.com/ophilon/awesome-pods">awesome-pods</a>. Этот репо задуман как форк замечательного проекта <a href="https://github.com/docker/awesome-compose">awesome-compose</a>, в котором собраны конфиги docker compose для 41 самого популярного сервиса. Я же пытаюсь сделать что-то похожее для манифестов podman. Приглашаю к сотрудничеству начинающих девопс — сможете поучаствовать в открытом проекте, заработать почётные гитхаб-бейджи и улучшить своё резюме. Подробнее — <a href="https://github.com/ophilon/awesome-pods/blob/main/CONTRIBUTING.md">здесь</a>.</p><p>Мой проект в интересном положении: сделаны манифесты для нескольких сервисов, опробованы описанные выше подходы для миграции конфигов compose.yaml в манифесты kube.yaml. Но захотелось большего: а почему бы не сделать сразу пайплайны для тестирования, коммита в апстрим, деплоя и прочее. Зайдём в каталог traefik-golang и создадим пару мейк-файлов. Для начала сделаем всё это локально, начнём с make_compose:</p><p>Этот файл уже в истории, равно как и соответствующий README.md, привожу его для примера. Так как я делаю конфиги сразу для двух платформ — docker и podman, для включения соответствующего Makefile’а нужно сделать линк на него: ln -s make_compose Makefile.</p><p>Отлично, основную идею обсудили, идём дальше. В docker’е есть замечательная опция context, позволяющая работать с любыми серверами, где настроен доступ. В нашем случае список контекстов выглядит так:</p><p>Здесь я использовал простейший хак — сделал копию дефолтного контекста с именем localhost. Теперь мы можем сделать наш пайплайн способным на удалённый деплой. Достаточно прописать в /etc/hosts имя и адрес нашего dev сервера. Вот новая версия make_compose:</p><p>Поясню немного подробнее.</p><ul><li>Самая первая строка — стандартное объявление списка целей.</li><li>Строки 2-4 задают дефолтное значение переменной, если оно не задано в текущем env.</li><li>В хелп — строки 5-10 — добавлено предупреждение о текущем контексте, он задаётся в глобальной переменной, например, export DKR_CONTEXT=localhost для локального контекста.</li><li>Также добавлена цель commit в репо — строки 17-21 — после выполнения цели test.</li><li>Test — строки 31-32 — в свою очередь, выполняется для текущего контекста, см. хак #1. Имя контекста должно совпадать с именем хоста нашего dev-сервера.</li><li>Добавлена также цель clean: очистка старых образов с локальном репо,и зависимости в цель up. Здесь убеждаемся, что образ пересобран и старые контейнеры остановлены.</li></ul><p>Отлично, пайплайн для докера работает. Пробуем сделать то же самое для подмана. Здесь нас ждёт сюрприз, попробую рассказать в стиле прямого репортажа. Первоначально наш пайплайн для podman выглядел вот так:</p><p>В строке 5 определяются зависимости: target back соберёт исполняемый файл только в том случае, если код main.go или сам make_pods новее уже собранного бинарника.</p><p>Строка 6 удаляет backend контейнер с едва заметным знаком минус -, чтобы игнорировать ошибку, если контейнер с именем backend не существует.</p><p>Строки 7–10 создают контейнер с именем backend из пустого (scratch) контейнера — команды buildah следуют обычным командам Dockerfile, но в нижнем регистре: FROM -&gt; from, COPY -&gt; copy, RUN -&gt; run, ENTRYPOINT -&gt; config –entrypoint и т. д. Здесь вы видите основное отличие от традиционного docker buildx подхода — вы работаете в двух контекстах одновременно: в локальном контексте, используя установленный компилятор go, и в контексте контейнера, копируя файлы в/из контейнера, запуская команды внутри контейнера и т. д. Другая новая возможность buildah — вы можете собирать образ шаг за шагом, то есть отлаживать процесс сборки.</p><p>Строка 8 компилирует main.go в исполняемый файл back с соответствующими флагами.</p><p>Строка 11 создаёт из контейнера новый образ (image) с тегом backend:latest.</p><p>Цель up — строка 16 — зависит от цели down — строка 14, — то есть она сначала останавливает pod и удаляет контейнеры, если они всё ещё запущены, затем запускает новый под.</p><p>Цель down в строке 15 подставляет глобальную переменную $XDG_RUNTIME_DIR из env пользователя в kube.yaml, используемый далее в podman kube командах, принимая новый манифест со стандартного ввода. Это также специфика podman — он работает полностью в пространстве пользователя, контейнеры взаимодействуют через собственный podman.sock. Таким образом, делаем пайплайн независимым от UID.</p><p>В подмане есть фунциональность наподобие docker context, под другим именем, в подкоманде system connection:</p><p>Первым в списке стоит настроенная в <a href="https://tproger.ru/articles/konvejer-devops--chast-2--polzuemsya-fedora-core-i-misel">прошлой статье ВМ</a>. Пока искал правильные опции для создания коннекшена (aka контекст в докере), столкнулся с подсказкой от подмана — «создайте сначала машину», а именно:</p><p>Выполнил эти рекомендации, подман выкачал, настроил и добавил два новых коннекшена для новой ВМ. Какой же меня ждал сюрприз, когда я стал смотреть, что же это за machine. Во-первых, в моём HOME появились новые файлы и каталоги:</p><p>Во-вторых, это полноценная ВМ fedora coreos:</p><p>Конечно, приятно, что моё мнение совпало с мнением авторов подмана, точнее, со стратегией RedHat — fedora coreos наиболее подходящая система для контейнерных приложений. С другой стороны, ВМ в подмане крутится полностью внутри пространства пользователя. У меня уже настроена почти такая же для удалённой работы всей команды разрабов. Решено: останавливаем новую виртуалку и правим мейкфайл для подмана по образцу компоуза, делаем пайплайн для деплоя и локально, и на удалённый дев-сервер.</p><p>Но прежде нам понадобится ещё один хак #2. Если в случае докера переключение контекста можно было сделать любой переменной, то для подмана между локальным соединением через сокет и удалённым, через uri:ssh, имя переменной фиксировано <a href="https://docs.podman.io/en/stable/markdown/podman.1.html">CONTAINER_HOST</a>. Вот как выглядит пайплайн make_pods.v1, настроенный и для локальной сборки, и для деплоя в наш дев-сервер:</p><p>По большей части цели мейкфайла остались теми же, но для удалённого деплоя настраиваем переменную export CONTAINER_HOST=ssh://dev@fc42dev:22/run/user/1001/podman/podman.sock — берём её из коннекшена, она служит переключателем между локальным и удалённым контекстом. Для локального контекста эту переменную надо удалить: unset CONTAINER_HOST. Команды в строках 19, 21 и 23 — это обычные команды шелла, они также меняются на локальное либо удалённое исполнение, переопределяются на основе этой же переменной CONTAINER_HOST.</p><p>Как заметил внимательный читатель, в цели back исчезла сборка контейнера утилитой buildah. Как и для docker compose, используется возможность самого подмана создавать образы на основе Containerfile, он же Dockerfile, эти названия синонимичны. Это намёк: пора отвыкать от слова докер, контейнеры уже давно стали основой облачных вычислений, для них созданы сотни приложений, например, <a href="https://www.cncf.io/">CNCF</a> и <a href="https://adriancitu.com/2021/12/30/containers-landscape-seen-through-oci-and-cncf-standards-lens/">общепризнанные стандарты</a>.</p><h2>Принципиальный вопрос о контейнерах</h2><p>Основное их преимущество — новый способ доставки приложений в облака, решение проблем с зависимостями, версиями библиотек, фреймворков и проч. Сборка контейнеров в контейнерах — побочный эффект облачных сервисов Github, Gitlab и других, с одной стороны, и ограничения Docker — с другой. Он не умеет, в отличие от подмана, точнее, от его сопутствующей утилиты buildah, выполнять билд и создавать образ, используя локальное окружение.</p><p>Основная проблема сборки образа внутри контейнера — неэффективное использование кэша. Да, появились возможности как-то сохранять объемные загрузки внешних библиотек, модулей: это опции --mount=type=cache для <a href="https://docs.docker.com/build/cache/optimize/#use-bind-mounts">некоторых языков</a>. Но, во-первых, эти возможности используются далеко не всегда. Во-вторых, опции для кэширования отличаются в podman и buildah, см. podman-build(1), придётся делать отдельный Containerfile. В-третьих, эффект от такого кэширования минимален. Предлагаю замерить время сборки, сделав ещё одну, третью версию пайплайна. Сначала соберём команды для buildah в отдельный файл:</p><p>и поправим пару строк в пайплайне:</p><p>Уточню условия нашего эксперимента — мы настроили одинаковую среду разработки с помощью утилиты mise (<a href="https://tproger.ru/articles/konvejer-devops--chast-2--polzuemsya-fedora-core-i-mise">предыдущая статья</a>) на нашем дев-сервере и у каждого из разрабов команды. Репозитарий git использует этот же дев-сервер, доступ к репо и серверу по ключу, парольный доступ закрыт. Пайплайны настроены как для локальной сборки, так и на дев-сервере. Перед запуском 3-й версии пайплайна на дев-сервере нужно сделать коммит изменений в репо — buildah не знает о коннекшенах, работает с кодом в текущем каталоге (строка 1): после логина на сервер переключается в корень проекта. Предварительно выкачиваем образ компилятора go для сборки в контейнере — это вполне честно, мы же выкачали и настроили компилятор golang заранее. Замеряем:</p><p>Мы получили 10+-кратный выигрыш по времени сборки образа для подмана. Абсолютные времена не важны, также не влияет, запускали мы сборку локально или на дев-сервере — мы сравниваем только билд в контейнере и в настроенном локальном окружении. Третье измеренное время — сборка в Docker. Он умеет собирать только в контейнере, для него настроили кэширование в Containerfile:</p><p>Но оно не сильно помогло. Конечно, наш проект игрушечный, golang кэширует лучше других языков, но в целом вывод понятен: сборка в контейнере далеко не оптимальный вариант, если есть возможность настроить дев-сервер для работы команды.</p><p>Ещё замечание: конечно, образы, собираемые buildah, совместимы с Docker, их можно использовать в конфигах compose.yaml. Но для этого надо настроить репозиторий образов и сначала загрузить образ в него. Локальные репозитории отличаются: Docker использует общий репо для всех пользователей — Docker Root Dir: /var/lib/docker, а в подмане всё хранится в домашнем каталоге пользователя — graphRoot: /home/$USER/.local/share/containers/storage.</p><p>Как я предположил в самом начале, мы попробовали вариант с гипотетической идеальной командой разрабов, работающей в Линукс и умеющей в make. А как быть обычному девопсу с разношерстой командой, где кто-то сидит на Винде, а кто-то ни за что не откажется от привычного Макбука на M4? Есть вариант и для этого случая. Пусть они пишут код и тестируют его как им нравится, а в нашем репо на дев-сервере мы сделаем хак #3, а именно git hook и bare репозиторий — githooks(5), выполняющий наши цели сборки и старта приложения при коммите в репо.</p><p>Для этого на пару минут придётся стать безжалостным хакером, удаляющим лишнее и открывающим скрытые возможности гита. Выполняем следующие шаги:</p><ol><li>Заходим под юзером dev на сервер, создадим пустой каталог, например, mkdir -pv ~/bare/t0. Это станет новым GIT_DIR, зайдём в него и выполним cd ~/bare/t0;git init --bare.</li><li>Видим, что файлы, обычно спрятанные в каталоге .git, лежат прямо в корне. Сделаем дополнительно каталог для логов mkdir logs. Переходим в каталог hooks и создаём файл, где укажем команды выполнения при каждом изменении в репо.</li></ol><p>Закомментированные строки 3, 8, 9 полезны при отладке пайплайна. Строки 4 и 5 задают, что есть, собственно, репозиторий, переменная GIT_DIR и переменная WORK_TREE (куда будут записываться файлы проекта). В цикле от строки 6 до 14 читаются и обрабатываются три переменные, с которыми гит вызывает этот хук. Строка 11 принимает все изменения в репо и обновляет WORK_TREE — всё то, что гит обычно делает в общем каталоге, как видим, в bare репо они разные. Далее, в 12 строим имя лога и строка 13 — собственно, пайплайн.</p><ol><li>Идём в каталог, где расположен репо проекта. Без страха и сожаления удаляем старый и создаём новый под тем же именем: cd ~/src;rm -rf traefik-golang;mkdir traefik-golang.</li><li>Завершаем сессию на дев-сервере, возвращаемся на рабочий комп и заходим в репо проекта. Конечно, репо цел, клоны репо не так просто уничтожить, пока есть хотя бы одна копия. Теперь смотрим старые настройки git remote -v и удаляем их git remote remove fc42dev в моём случае. Создаём новый remote, указывая новый гит bare репо: git remote add bare.t0 dev@fc42dev:~/bare/t0. Это также нужно сделать всем разрабам в их локальных копиях.</li><li>Проверяем результат. Возможно, нужно сделать новый комит и push в новый remote. Стоит посмотреть подробнее, как изменился репо проекта на сервере: проверить логи в ~/bare/t0/logs, сравнить конфиги обычного репо проекта и на сервере, проверить, какие команды перестали работать в серверном репо. Например, в WORK_TREE не работают команды гит status; branch; commit; log. То есть наш хак #3 с git --bare не только позволил делать деплой на сервере, но также защитил репо от локальных изменений, а серверный репо всегда в чистоте и порядке. Можно редактировать код, но закомитить его только через обычный репо. Изменения на сервере удалятся после любого коммита.</li></ol><p>Надеюсь, мне удалось показать, что пайплайны можно делать на основе древней забытой утилиты make. В следующей статье разберём, как можно добавить в наш скромный дев-сервер нечто похожее на монстров гит-сервисов, Gitlab и Github, создавать пайплайны, совместимые с github Actions, предоставить команде разрабов привычный интерфейс репо в браузере.</p>]]></content:encoded>
    </item>
    <item>
      <title>Тест: Какой язык программирования тебе подходит</title>
      <link>https://tproger.ru/quiz/test--kakoj-yazyk-programmirovaniya-tebe-podhodit</link>
      <comments>https://tproger.ru/quiz/test--kakoj-yazyk-programmirovaniya-tebe-podhodit?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Валерия Турчак]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/quiz/test--kakoj-yazyk-programmirovaniya-tebe-podhodit</guid>
      <description><![CDATA[<p>Пройди наш квиз и проверь, какой язык программирования тебе подходит больше всего. Проверь свои текущие знания и выбирай новое направление!</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/quiz/test--kakoj-yazyk-programmirovaniya-tebe-podhodit">Тест: Какой язык программирования тебе подходит</a>»</p>]]></description>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Языки программирования]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Викторины]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 14 Apr 2025 14:00:04 GMT</pubDate>
      <content:encoded><![CDATA[<p>Выбираешь, с чего начать? Или хочешь понять, куда двигаться дальше?</p><p>Этот тест поможет определить, какой язык программирования подходит именно тебе — по типу задач, стилю мышления и карьерным ориентирам.<br /><br />В конце ты получишь 1–2 языка, которые соответствуют твоим приоритетам, плюс пояснение, где они реально применяются, зачем их учить и как с ними выстраивать карьеру.<br /></p>]]></content:encoded>
    </item>
    <item>
      <title>Энтузиаст рассказал, как запустил Go на PlayStation 2 — через TinyGo, ps2dev и боль</title>
      <link>https://tproger.ru/news/entuziast-rasskazal--kak-zapustil-go-na-playstation-2---cherez-tinygo--ps2dev-i-bol</link>
      <comments>https://tproger.ru/news/entuziast-rasskazal--kak-zapustil-go-na-playstation-2---cherez-tinygo--ps2dev-i-bol?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/entuziast-rasskazal--kak-zapustil-go-na-playstation-2---cherez-tinygo--ps2dev-i-bol</guid>
      <description><![CDATA[<p>Go запустили на PlayStation 2: энтузиаст адаптировал TinyGo и ps2dev для MIPS-процессора консоли и обошёл ограничения LLVMa</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/entuziast-rasskazal--kak-zapustil-go-na-playstation-2---cherez-tinygo--ps2dev-i-bol">Энтузиаст рассказал, как запустил Go на PlayStation 2 — через TinyGo, ps2dev и боль</a>»</p>]]></description>
      <category><![CDATA[JSON]]></category>
      <category><![CDATA[Отладка]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[PlayStation]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 28 Mar 2025 08:22:54 GMT</pubDate>
      <content:encoded><![CDATA[<p>Разработчик под псевдонимом Ricardo <a href="https://rgsilva.com/blog/ps2-go-part-1/">опубликовал</a> подробный отчёт о том, как ему удалось запустить Go-программу на PlayStation 2 — консоли 2000 года.</p><p>Он использовал компилятор TinyGo, SDK ps2dev и собственные костыли, чтобы адаптировать современный язык программирования под устаревшую архитектуру.</p><h2>TinyGo, MIPS и странности платформы</h2><p>PS2 построена на процессоре MIPS R5900 (архитектура MIPS-III с расширениями), который не поддерживается стандартной сборкой Go. Проблему частично решает TinyGo, который компилирует Go-код в LLVM IR.</p><p>Но даже с ним возникли сложности: ни LLVM, ни сам TinyGo не умеют работать с особенностями PS2 «из коробки». Пришлось вручную описывать платформу через ps2.json, определять baremetal-окружение, runtime и заглушки под прерывания.</p><h2>Первые успехи: «Hello from Go»</h2><p>Чтобы код TinyGo можно было линковать с библиотеками из ps2dev (а они скомпилированы под ABI N32), автору пришлось добиваться совместимости: целиться в MIPS-III, использовать hard-float, отключать abicalls и собирать IR с последующей ручной сборкой объектника через Clang с нужными флагами.</p><p>После успешного линка и запуска в эмуляторе PCSX2 программа вывела строку и число на отладочный экран PS2.</p><h2>Собственный main() и отладка</h2><p>Дальше автор отказался от загрузчика на C и написал полноценный main() на Go, вручную выделяя память под кучу и завершая программу через exit() из ps2dev. Он добавил простую обёртку над scr_printf() — теперь можно печатать текст прямо из Go.</p><h2>DDIVU и проклятие деления</h2><p>Серьёзным багом стал сбой fmt.Sprintf: PS2 не поддерживает инструкцию DDIVU, которую LLVM генерирует при делении uint64.</p><p>Автор обошёл это, подключив функции __udivdi3, __divdi3 и прочие, а затем пропатчил компилятор TinyGo, чтобы он использовал их при делении int64 и uint64.</p><h2>Что дальше</h2><p>Демо работает. Go-код запускается напрямую, выводит текст и корректно делит числа.</p><p>Впереди — системные вызовы, inline-ассемблер, поддержка прерываний и, возможно, новая цель в LLVM для процессора r5900.</p>]]></content:encoded>
    </item>
    <item>
      <title>Новый компилятор TypeScript на Go собирает код быстрее, но не делает его быстрее</title>
      <link>https://tproger.ru/news/novyj-kompilyator-typescript-na-go-sobiraet-kod-bystree--no-ne-delaet-ego-bystree</link>
      <comments>https://tproger.ru/news/novyj-kompilyator-typescript-na-go-sobiraet-kod-bystree--no-ne-delaet-ego-bystree?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/novyj-kompilyator-typescript-na-go-sobiraet-kod-bystree--no-ne-delaet-ego-bystree</guid>
      <description><![CDATA[<p>Microsoft переписала компилятор TypeScript на Go: сборка быстрее в 10 раз, но код работает так же. Что это меняет для разработчиков</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/novyj-kompilyator-typescript-na-go-sobiraet-kod-bystree--no-ne-delaet-ego-bystree">Новый компилятор TypeScript на Go собирает код быстрее, но не делает его быстрее</a>»</p>]]></description>
      <category><![CDATA[Microsoft]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[TypeScript]]></category>
      <category><![CDATA[Node.js]]></category>
      <category><![CDATA[WebAssembly]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 25 Mar 2025 05:07:21 GMT</pubDate>
      <content:encoded><![CDATA[<p><b>Microsoft переписывает компилятор TypeScript с JavaScript на Go</b> и <b>обещает 10-кратный прирост производительности</b>.</p><p>Новость быстро разлетелась по сообществам, но на деле всё не так однозначно, <a href="https://www.architecture-weekly.com/p/typescript-migrates-to-go-whats-really">пишет</a> разработчик Оскар Дудич в рамках Architecture Weekly.</p><p><b>Речь идёт о скорости компиляции, а не исполнения кода</b>. Ваши приложения не станут работать быстрее — только собираться. Это как если бы производитель автомобилей сказал, что «машина стала в 10 раз быстрее», а потом уточнил, что речь о производстве, а не скорости на трассе.</p><h2>Почему решили переписать и причём тут Go</h2><p><b>Компилятор — это CPU-bound задача</b>. Он не ждёт ответа от базы данных и не занимается сетевыми запросами. Он грузит процессор на полную, разбирая дерево типов, анализируя код и генерируя выходной файл.</p><p><b>Node.js с его однопоточной моделью и event loop плохо подходит для таких задач</b>. Он отлично работает в веб-серверах — там важна скорость отклика и работа с I/O, но не тяжёлые вычисления. Компилятор TypeScript вырос, стал сложнее, и старая архитектура начала тормозить.</p><p><b>Go здесь оказался подходящим выбором:</b></p><ul><li>у него есть <b>легковесные потоки (goroutines)</b>;</li><li><b>параллельное выполнение</b> встроено на уровне языка;</li><li>нет нужды в трюках с worker threads, как в Node.js;</li><li>проще работать с памятью и сложными структурами.</li></ul><h2>Почему просто не использовать worker threads в Node.js?</h2><p>Это возможно, и они действительно дают параллельность. Но:</p><ul><li><b>переписывать старый код с учётом многопоточности — больно</b>;</li><li>обмен данными между потоками в Node.js идёт через сериализацию;</li><li>каждый поток создаёт свой V8-инстанс, что дорого по ресурсам.</li></ul><p><b>Команда решила не латать старое, а начать с чистого листа</b>. И, как показали первые тесты, даже однопоточный Go-компилятор оказался быстрее, чем старый на Node.js.</p><h2>А что с браузерами и плагинами?</h2><p>Это пока не ясно. <b>В браузерах Go не работает нативно</b>, и придётся либо компилировать его в WebAssembly, либо сохранить JS-версию для playground'ов. Вопросов больше, чем ответов:</p><ul><li>как сохранить совместимость с TypeScript-плагинами;</li><li>будет ли 100% повторяемость в поведении компилятора;</li><li>изменятся ли ошибки, предупреждения и тонкости типов.</li></ul><h2>Зачем вообще об этом думать</h2><p><b>Это кейс о масштабировании и выборе инструментов</b>. То, что хорошо работало в 2012 году, перестаёт тянуть в 2025-м. Переписывание проекта — не всегда трагедия. Иногда это необходимость, если фундамент начал мешать росту.</p><p><b>Важно не повестись на «10x быстрее»</b>. Такие цифры всегда требуют контекста. Но и отрицать ценность изменений не стоит — особенно если вы работаете с большими кодовыми базами и каждый процент ускорения важен.</p>]]></content:encoded>
    </item>
    <item>
      <title>Go-разработчик 2025: что нужно знать на каждом грейде</title>
      <link>https://tproger.ru/articles/go-razrabotchik-2025--chto-nuzhno-znat-na-kazhdom-grejde</link>
      <comments>https://tproger.ru/articles/go-razrabotchik-2025--chto-nuzhno-znat-na-kazhdom-grejde?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Danil Dinko]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/go-razrabotchik-2025--chto-nuzhno-znat-na-kazhdom-grejde</guid>
      <description><![CDATA[<p>Даниил Динько, тимлид в компании-лидере в международном кибербезе и эксперт Эйч Навыки, собрал стартер-паки для Go-разработчика каждого уровня.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/go-razrabotchik-2025--chto-nuzhno-znat-na-kazhdom-grejde">Go-разработчик 2025: что нужно знать на каждом грейде</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Микросервисы]]></category>
      <category><![CDATA[SQL]]></category>
      <category><![CDATA[DevOps]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Базы данных]]></category>
      <category><![CDATA[Навыки]]></category>
      <category><![CDATA[Kubernetes]]></category>
      <category><![CDATA[PostgreSQL]]></category>
      <category><![CDATA[Бизнес]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 19 Feb 2025 10:00:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>Грейды — штука абстрактная, поскольку у каждой компании есть свое мнение на этот счет. Для одних ты можешь быть джуном+, а для других — сильным сеньором. Тем не менее, можно однозначно наметить общие тренды в требованиях по индустрии.</p><p>Я — <a href="https://h.careers/curators/daniil-dinko?utm_source=tg_bot&amp;utm_medium=rassilka&amp;utm_campaign=161024">Даниил Динько</a>, веду свой личный <a href="https://t.me/thestrikemch">телеграм-канал</a>, где рассказываю о себе, об IT и о Golang. Также являюсь экспертом и спикером в компании <a href="https://h.careers/skills?utm_source=site_tproger&amp;utm_medium=article">Эйч Навыки</a>, TeamLeadом в компании-лидере в международном кибербезе, ex. старшим разработчиком в Ozon Tech. Вместе разбираемся, что объединяет Go-разрабов каждого грейда.</p><p>А почитать о том, как сейчас стать Go-разрабом, можно в предыдущей <a href="https://tproger.ru/articles/kak-sejchas-stat-go-razrabotchikom-s-nulya--vse-puti">статье</a>.</p><h2>Навык собеседований vs. навык работы</h2><p>Для начала важно разделять два понятия: навык прохождения собеседований и навык работы. Интервью длится 3-4 часа — этого невероятно мало, чтобы прочувствовать весь ваш кругозор в бою, поэтому индустрия использует стандартные задачи-заглушки. У большинства компаний такие задачи примерно про одно и то же, поэтому сейчас не редка ситуация, когда на собеседовании ваш реальный грейд на единицу или полторы выше реального — как раз потому, что такие заглушки отскакивают от зубов.</p><ul><li><b>Что это значит для кандидата:</b> в такой ситуации можно быстрее вырасти в реальном навыке работы, потому что через навык собеседований вы получаете грейд. Эти задачи не даются просто так на позиции, которая соответствует навыку реальной работы. Так, в стрессовой ситуации вы максимально выравниваетесь за короткий срок.</li><li><b>Что это значит для компании:</b> для работодателя это плохо, поскольку  определить грейд —  еще сложнее. И есть шанс нанять кандидата, на которого потратят больше денег, чем он теоретически может принести.</li></ul><p>Теперь разберем, что требуется от Go-разработчиков на каждом уровне.</p><h2>Что нужно с точки зрения навыка собеседований</h2><p>Сейчас интервью стали гораздо жестче: конкуренция растет, а требования к кандидатам повышаются.</p><p>Дисклеймер: не обязательно знать все из списка ниже — в нем представлено максимальное количество навыков и верхняя граница знаний по грейду. Поэтому если вы что-то не знаете, это отличный способ понять, что наверстывать.</p><h3>Грейд: Junior</h3><p>Сейчас на рынке Go очень много джунов — он перегрет, и попасть в компанию без коммерческого опыта будет крайне сложно. Более того, от начинающих разработчиков ждут немало знаний и навыков. О них — ниже.</p><h4>Углубленное знание Go</h4><ul><li>Уметь абстрактно рассказать про очереди в планировщике.</li><li>Знать про мапу под капотом: как устроено хеширование, коллизии и разрешение конфликтов.</li><li>Уметь решать задачи по concurrency на относительно базовом уровне (воркер пул) и на слайсы</li><li>Понимать принципы работы горутин и каналов.</li></ul><h4>Базы данных</h4><ul><li>Знать виды баз данных и рассказать про максимальное количество юзкейсов из опыта с разными типами данных.</li><li>Знать индексы и ACID и уметь их базово  писать.</li><li>Знать SQL, уметь составлять схемы и идейно понимать, как работают самые известные базы —  PostgreSQL, ClickHouse.</li><li>Понимать репликацию и шардирование</li></ul><h4>Системный дизайн</h4><p>Да-да, теперь даже джуну нужно иметь абстрактное понимание сисдиза:</p><ul><li>Монолит vs. микросервисы: знать плюсы и минусы каждой архитектуры.</li><li>Знать варианты коммуникаций между сервисами (брокеры сообщений, REST API, gRPC).</li></ul><h4>Алгосы и Computer Science</h4><ul><li>Уметь решать медиум-задачки на LeetCode. Фокус при этом на задачах со слайсами, деревьями и графами.</li><li>В Computer Science — знать про устройство Linux, планировщик, потоки/процессы, а еще про устройство сети — OSI, TCP/IP, протоколы и т.д.</li></ul><p>Также  в некоторых компаниях сейчас ко всему этому требуют еще и знание Kubernetes.</p><p>Вот <a href="https://miro.com/app/board/uXjVLGihxYs=/">здесь</a> собрал дорожную карту, как влиться в IT на примере Go. Из полезных ссылок:</p><ol><li><a href="https://www.youtube.com/watch?v=eQPfHdiz_KI">Один из лучших курсов по Go на Youtube</a></li><li><a href="https://www.youtube.com/watch?v=d6BtxBKhQoc&amp;t=3178s">Крутой урок по системному дизайну</a></li><li><a href="https://www.youtube.com/watch?v=ZTJcaP4G4JM">Все про каналы в Go</a></li></ol><p>А <a href="https://miro.com/app/board/uXjVLIldoLE=/">здесь</a> можно посмотреть, как джуну стать мидлом.</p><h3>Грейд: Middle</h3><p>Схема примерно такая же, как и с джунами, правда, знать все нужно гораздо глубже.</p><h4>Go</h4><ul><li>Знать планировщик на уровне того, какая структура данных используется в локальных очередях.</li><li>В слайсах — уметь решать задачи со срезом по capacity, плюс более уверенное решение кейсов по concurrency.</li></ul><h4>Базы данных</h4><ul><li>MVCC,</li><li>Проблема разбухания индексов,</li><li>Селективность,</li><li>Шардирование на уровне реальных решений основной проблемы решардинга — Consistent Hash,</li><li>Реприликация и паттерн Raft.</li></ul><p>А еще важно уметь писать нормальные индексы и эффективные SQL запросы. Плюс ожидается, что у вас будет больше юзкейсов работы с разными типами баз данных.</p><h4>Сисдиз</h4><p>Нужно знать про паттерны межсервисного взаимодействия: Saga, Transactional Outbox, Circuit Breaker. На мидла могут уже спокойно давать практические задачи на внедрение каких-то идейных дизайнерских штук, например, идемпотентности.</p><h4>Алгосы и Computer Science</h4><p>Здесь они играют меньшую роль. Главное — показать коммерческий опыт, рассказать о кейсах и блеснуть знаниями в Go, базах и проектировании.</p><h3>Грейд: Senior</h3><p>Сеньоры — моя любимая тема, самый абстрактный и спорный грейд. Здесь требуется все то же, что и на мидла, но знания должны быть еще более глубокие. Вот примерный список:</p><h4>Go</h4><p>Нужно знать библиотеку Reflection со всякими приколами, которые могут ускорить concurrency. Также разбираться в аренах памяти и планировщике.</p><h4>Сисдиз</h4><p>В паттернах межсетевого взаимодействия история с обычным рассказом не пройдет — юзкейсы здесь must-have. Поэтому важно уметь проходить System Design-интервью — собирать функциональные и нефункциональные требования, считать нагрузку, проектировать на разных уровнях абстракции, углубляться и решать проблемы в своей же архитектуре. Это сложно, и без хотя бы косвенного соприкосновения с проектированием, будет непросто. Поэтому в качестве совета — стремитесь максимально участвовать на архитектурных сессиях и грумингах, будучи мидлом.</p><h4>Базы данных</h4><p>Будет круто знать, как под капотом реализован, например, PostgreSQL: как он поднимает что-то в буфер, как хранит данные на диске, что такое чекпоинты и бэкапы и как реализована MVCC.</p><p>В случае с ClickHouse лучше верхнеуровнево понимать LSM-дерево, а с ElasticSearch — инвертированные индексы.</p><h4>Алгосы и Computer Science</h4><p>Алгоритмы уже почти не играют роли в большинстве компаний, а Computer Science требуется примерно на том же уровне, что и на джуна. Единственное — в Linux могут чуть капнуть.</p><p>Также в зависимости от компании могут требовать углубленные знания в DevOps, но мы про это говорить не будем — не самый частый кейс. Однако базовое понимание того, как что развернуть, какие могут быть проблемы и как их решить идейно, должно быть.</p><p>Мне часто на трансляциях говорят: «Зачем мне знать планировщик или уметь решать сложные задачи по concurrency? Когда мне это пригодится в работе?». Действительно, на эффективность в решении рабочих задач это влияет незначительно, но все же это особенность собеседований (подробнее можно посмотреть <a href="https://t.me/thestrikemch/68">здесь</a>):</p><ul><li><b>Собес ≠ работа. </b>Принято считать, что знания, требуемые на собеседовании, пригодятся в работе — это не так. За несколько часов невозможно полностью оценить кандидата, поэтому интервью строятся на проверке общих знаний и концепций.</li><li><b>Почему спрашивают про планировщик?</b> Банально узнают софты.</li><li><b>Жесткая конкуренция. </b>Все просто: знание — сила.</li></ul><h2>Что нужно с точки зрения реальной работы</h2><p>На мой взгляд, самое важное, помимо знания технологий — прокаченные софт-скиллы. И наработать их можно только с опытом.</p><ul><li><b>Грейд Junior.</b> Нужно уметь делать максимально базовые задачи. Например, добавить поле или прокинуть фича-флаг. Или же при курировании и ревью быть мотивированными. Этого достаточно. Да, как бы грустно это ни звучало, здесь по классике предполагается, что тебе нельзя доверить что-то серьезное без сторонней помощи.</li><li><b>Грейд Middle.</b> Относительно безболезненно брать на себя полноценные части продукта в зону ответственности, фича-лидить. Здесь предполагается, что ты можешь действовать относительно самостоятельно, приходя с вопросами лишь иногда. Тут уже желательно участвовать в каких-либо технических обсуждениях.</li><li><b>Грейд Senior.</b> Здесь нужно разрабатывать фичи любого уровня сложности под ключ. Тебе достаточно предоставить бизнес-требования, сходить с ними по командам с экспертизой. Затем спроектировать качественную архитектуру, которая развалится с минимальной вероятностью, самому реализовать и принести лиду  таску в Done. Здесь также важно менторить сотрудников, активнейшим образом участвовать на грумингах и любых других технических созвонах.</li></ul><p>Конкуренция растет, требования становятся все жестче, поэтому самое главное — постоянное развитие. Учитесь, ходите на собеседования, участвуйте в грумингах и обсуждениях. И помните, что навык проходить интервью и реальная работа — разные вещи, но без них никуда.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как сейчас стать Go-разработчиком с нуля? Все пути</title>
      <link>https://tproger.ru/articles/kak-sejchas-stat-go-razrabotchikom-s-nulya--vse-puti</link>
      <comments>https://tproger.ru/articles/kak-sejchas-stat-go-razrabotchikom-s-nulya--vse-puti?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Danil Dinko]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-sejchas-stat-go-razrabotchikom-s-nulya--vse-puti</guid>
      <description><![CDATA[<p>Даниил Динько, тимлид в компании-лидере в международном кибербезе и эксперт Эйч Навыки, рассказывает, как новичкам вкатиться в разработку на Go.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-sejchas-stat-go-razrabotchikom-s-nulya--vse-puti">Как сейчас стать Go-разработчиком с нуля? Все пути</a>»</p>]]></description>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Практика]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Советы]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Навыки]]></category>
      <category><![CDATA[Образование]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 18 Feb 2025 10:00:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>Из всех телевизоров говорят, что в IT дефицит — критически не хватает специалистов. На самом деле, это не совсем так:  не  хватает мидлов (уже даже middle+) и выше, а вот стажеров и джунов в России слишком много. Но спешу вас обрадовать, вкатиться еще можно и с вполне неплохими шансами!</p><p>Я — <a href="https://h.careers/curators/daniil-dinko?utm_source=tg_bot&amp;utm_medium=rassilka&amp;utm_campaign=161024">Даниил Динько</a>, веду свой личный <a href="https://t.me/thestrikemch">телеграм-канал</a>, где рассказываю о себе, об IT и о Golang. Также являюсь экспертом и спикером в компании <a href="https://h.careers/skills?utm_source=site_tproger&amp;utm_medium=article">Эйч Навыки</a>, TeamLeadом в компании-лидере в международном кибербезе, ex. старшим разработчиком в Ozon Tech. Вместе разбираемся, что нужно тем, кто только знакомится с Go, для старта в IT.</p><p>В статье будет две части: первая — как построить процесс обучения, и вторая — как конкретно обучаться и вкатываться. По статистике менторства считаю, что самое сложное — правильно выстроить процесс, поэтому настоятельно рекомендую уделить этому достаточно внимания.</p><p>Кстати, в следующей статье я собрал стартер-пак Go-разрабов на каждом грейде — почитать можно <a href="https://tproger.ru/articles/go-razrabotchik-2025--chto-nuzhno-znat-na-kazhdom-grejde">здесь</a>.</p><h2>Для начала: почему Golang на хайпе</h2><p>Сейчас Go бьет рекорды по популярности — почти весь бигтех пишет что-то на этом языке. Я каждый раз открываю для себя больше и больше сфер применения: казино, криптовалюта, борьба с киберпреступлениями, логистика, финтех, даже сервисы аптек.</p><p>Мне кажется, Go валиден почти в любой сфере. Его основные преимущества:</p><ul><li>простота по отношению к другим языкам,</li><li>крутая модель многопоточности,</li><li>заточенность языка под часто высоконагруженную серверную разработку.</li></ul><p>Хотя не обязательно высоконагруженную: Go используют на всех уровнях бизнеса.</p><p>Также в Go <a href="https://dreamjob.ru/salary/golang-razrabotchik#:~:text=%D0%A1%D0%BA%D0%BE%D0%BB%D1%8C%D0%BA%D0%BE%20%D0%B7%D0%B0%D1%80%D0%B0%D0%B1%D0%B0%D1%82%D1%8B%D0%B2%D0%B0%D0%B5%D1%82%20golang%20%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%87%D0%B8%D0%BA%20%D0%B2%20%D0%A0%D0%BE%D1%81%D1%81%D0%B8%D0%B8&amp;text=%D0%A1%D1%80%D0%B5%D0%B4%D0%BD%D0%B5%D0%BC%D0%B5%D1%81%D1%8F%D1%87%D0%BD%D0%B0%D1%8F%20%D0%B7%D0%B0%D1%80%D0%BF%D0%BB%D0%B0%D1%82%D0%B0%20%D0%B4%D0%BB%D1%8F%20%D0%B4%D0%BE%D0%BB%D0%B6%D0%BD%D0%BE%D1%81%D1%82%D0%B8%20golang,%E2%82%BD%20%D0%BD%D0%B0%20%D1%80%D1%83%D0%BA%D0%B8%20%D0%B2%20%D0%BC%D0%B5%D1%81%D1%8F%D1%86.">крутые зарплаты</a> — в основном, выше рынка. Новички могут получать от 100 000 рублей в месяц, а сеньоры — даже 500 000. В среднем — 160 000 рублей.</p><h2>Какие есть подходы для старта карьеры</h2><p>Глобально есть четыре подхода:</p><ol><li><b>Курсы.</b> Вас ведут за ручку и не нужно ничего самому искать. Есть мотивация, но нет прокачки двух самых важных навыков —  поиска информации и самообразования.</li><li><b>Менторство.</b> На начальных этапах вообще не рекомендую, оверхед, лучше думать в сторону курсов.</li><li><b>Сообщество. </b>Здесь вы объединяетесь с другими начинающими ребятами. Это лучший вариант — бесплатно, сохраняются все преимущества, за исключением того, что придется самому вести себя за ручку и искать всю нужную информацию. Но в начале должно быть именно так. В сообществе вы идете командой, и с корабля просто так не спрыгнешь: будет банально неудобно перед другими ребятами.</li><li><b>Расти самому. </b>Плюсов меньше, чем в варианте выше, а минусов — больше. Например, нет видимой конкуренции и взаимной мотивации друг друга.</li></ol><p>Я рекомендую третий вариант: практика показывает, что он самый эффективный в плане процента «доходимости». Единственное, в его рамках предстоит решить несколько вопросов.</p><p>Как найти таких людей, с которыми можно будет вместе двигаться?</p><p>Тут довольно просто: беседы в Telegram, воронки, взлетевшие видео на ютубе по Go — их полно. Например, этот <a href="https://www.youtube.com/watch?v=eQPfHdiz_KI">курс</a> считаю одним из лучших. Поэтому план простой: находим подобное видео, переходим в беседу, в ней ищем себе товарищей, списываемся, предлагаем совместный рост и созваниваемся.</p><p>Крайне важно правильно выбрать себе друзей, поскольку они будут играть значительную роль в вашем становлении разработчиком. Основные критерии, по моему мнению, —  мотивация к работе (горящие глаза), детерминированная причина стать Go-разработчиком, идейная заинтересованность в программировании, уровень силы воли и организованности человека (без этого никак).</p><p>Как найти человека, которому можно задавать свои вопросы?</p><p>Тоже все просто. Во многих tg-каналах, например, в моем, открыты комментарии, и в них часто можно увидеть полотна текста. Вероятно, автор комментария заинтересован обсуждать Go и учить других. При этом, его уровень будет довольно высоким, поэтому спокойно пишите и начинаете задавать вопросы. А вообще в моих ближайших планах — создать коммьюнити, в котором каждый сможет получить такую помощь еще более простым путем.</p><p>*А еще не забываем про ChatGPT или DeepSeek — они должны быть вашими основными консультантами.</p><p>Так, мы нашли людей, с которыми будем двигаться вместе, и тех, у кого будем спрашивать. Теперь давайте ответим на последний вопрос.</p><p>Как учиться?</p><p>Пока мы не умеем учиться сами, поэтому задача — экстерном влететь в этот навык. Здесь лучшее бесплатное предложение —  <a href="https://www.coursera.org/learn/learning-how-to-learn">Learning How to Learn от Coursera</a> (оно на английском, но есть субтитры). Там собрались эксперты, профессора крупных университетов, чтобы научно подойти к вопросу и дать практические советы по тому, как можно эффективно обучаться. Честно говоря, сам бы пересмотрел курс, если бы было больше свободного времени. Считаю его лучшим вариантом вкатиться в эффективное самообразование. Особенно рекомендую обратить внимание на технику помидоров, она, мне кажется, значительно ускоряет перформанс.</p><h2>Главное: какие есть пути вката в разработку на Go</h2><p>Теперь у нас есть все необходимое: окружение замотивированных товарищей, люди, к которым можно подходить с вопросами, и базовое умение обучаться. Давайте переходить к конкретным путям входа и требуемым знаниям. Технологии, обучающие видео и советы для новичков я собрал в большом <a href="https://miro.com/app/board/uXjVLGihxYs=/?share_link_id=212919331976">роадмапе</a>.</p><p>А теперь — об основных путях «входа в айти».</p><h3>Стажировки</h3><p>Чтобы попасть на программу, рекомендую решать каждый день 2-3 задачки с<a href="http://leetcode.com/"> leetcode.com</a> (Если совсем тяжело — сначала решаем на<a href="http://codewars.com/"> codewars.com</a>, а потом переходим на литкод). Затем, все просто (ну, почти): стучимся во все возможные наборы на стажировку в бигтех: Ozon Route 256, VK, Т-Банк, школа стажеров Wildberries — перечень можно легко найти в Гугле. Вариант довольно сложный и требует в большинстве случаев хорошую алгоритмическую подготовку. Но она нарабатывается за 3-4 месяца ежедневного решения задач на leetcode, кажется, не так много. Навык решения алгоритмических задач будет на протяжении всей карьеры расширять список потенциальных компаний для трудоустройства, так что временная инвестиция вполне валидная.</p><h3>Бесплатные стартапы</h3><p>Кажется, самый простой, честный и рабочий вариант. Проблема рынка заключается в том, что без опыта людей просто так вообще не берут, поэтому логичным решением проблемы будет где-то получить этот опыт. Рабочий вариант — найти какой-нибудь стартап (скорее всего, без привлеченных инвестиций) и работать там некоторое время бесплатно, получать опыт коммерческой разработки, чтобы потом указать его в резюме и кратно увеличить шансы трудоустройства. Да, придется поработать бесплатно некоторое время, но результат не заставит себя ждать.</p><h3>Накрутка опыта</h3><p>Нынче популярный способ, весь найм о нем знает, но пофиксить не может. Поддерживать этот путь или отрицать его не буду (решайте сами), но могу описать плюсы и минусы. В качестве плюсов — самый быстрый вкат, нужно просто уметь максимально базово проходить собеседования. Из минусов — обман, дискомфорт в первые месяцы работы из-за отсутствия коммерческого опыта с высокой вероятностью увольнения (но как показывает статистика, большая часть справляется).</p><p>Желаю самого успешного роста и верю, что если следовать по плану, описанному в этой статье, у вас все получится! Главное — уделяйте большое внимание моральной составляющей. Мотивация будет не всегда, поэтому пока она есть — максимально быстро конвертируем ее в силу воли.</p><p>В следующей статье расскажу, какие навыки и знания нужны Go-разработчикам на каждом грейде.</p>]]></content:encoded>
    </item>
    <item>
      <title>5 шагов для защиты backend: чек-лист от уязвимостей</title>
      <link>https://tproger.ru/articles/5-wagov-dlya-zashhity-backend--chek-list-ot-uyazvimostej</link>
      <comments>https://tproger.ru/articles/5-wagov-dlya-zashhity-backend--chek-list-ot-uyazvimostej?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Семен Шаплыгин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/5-wagov-dlya-zashhity-backend--chek-list-ot-uyazvimostej</guid>
      <description><![CDATA[<p>Чек-лист по защите backend от уязвимостей: 5 шагов для повышения безопасности вашего кода. Эксперт Семен Шаплыгин, Senior Software Developer в Yandex и эксперт Эйч, делится практическими рекомендациями и проверенными методами для защиты серверной части от угроз.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/5-wagov-dlya-zashhity-backend--chek-list-ot-uyazvimostej">5 шагов для защиты backend: чек-лист от уязвимостей</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Практика]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Навыки]]></category>
      <category><![CDATA[Приложение]]></category>
      <category><![CDATA[Утечка данных]]></category>
      <category><![CDATA[Уязвимость]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[DevSecOps]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 12 Feb 2025 10:00:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>Защита backend — это не вопрос хорошего кода. Это вопрос выживания. Серверная часть приложения — не витрина, а сердце системы: здесь обрабатываются конфиденциальные данные и управляется бизнес-логика. Уязвимость в backend — не просто ошибка, а потенциальная утечка данных, финансовые потери, а в худших случаях — полный контроль злоумышленников над системой.</p><p>Мы живем в мире, где враг известен. Крупные компании и профильные сообщества ежегодно публикуют отчеты о найденных уязвимостях. Изучая их, можно увидеть, что атаки редко бывают новыми — чаще всего разработчики снова и снова наступают на одни и те же грабли.</p><p>Я — <a href="https://h.careers/curators/sshaplygin">Семен Шаплыгин</a>, Senior Software Developer в Yandex и экспертом <a href="https://h.careers/skills?utm_source=site_tproger&amp;utm_medium=article">Эйч Навыки</a>. В статье расскажу о пяти главных шагах для защиты backend-приложений от уязвимостей. Поделюсь инсайтами и практическими советами, которые позволят избежать распространённых ошибок и уберечь систему от возможных атак.</p><h2>Аудит безопасности: с чего начать</h2><p>Безопасность — не состояние, а процесс. И если этот процесс не встроен в работу команды, значит, в системе уже есть уязвимости, о которых вы просто не знаете.</p><p>Подход к выявлению слабых мест должен включать несколько ключевых практик (запомните их, как мантру):</p><ul><li>Ваш код может быть чистым, но уязвимость скроется в одной из библиотек. Инструменты для анализа зависимостей должны работать на каждом этапе разработки.</li><li>Никогда не доверяйте тому, что приходит от пользователя. Любой ввод — это потенциальная атака.</li><li>Чувствительные данные не должны попадать в журналы ошибок или системные логи.</li><li>Любому компоненту системы дается только тот уровень доступа, который ему необходим. Ни строчкой больше.</li><li>Критически важные функции должны периодически проверяться на уязвимости.</li><li>Используйте специализированные инструменты. Это не только статический и динамический анализ кода, но и мониторинг активности, поведенческий анализ трафика.</li><li>Если в публичном пространстве появляется информация о скомпрометированных данных — в числе первых она должна оказаться у вас.</li></ul><p>Безопасность начинается с осознания слабых мест. А теперь разберем шаги, которые помогут эти слабые места закрыть.</p><h2>Чек-лист защиты backend: 5 ключевых шагов</h2><h3>Шаг 1. Защита от XSS: экранируйте ввод и вывод</h3><p><b>Проблема:</b></p><p>XSS (межсайтовый скриптинг) — уязвимость, позволяющая злоумышленнику внедрить вредоносный код в веб-страницу, которая затем появится в браузере других пользователей.</p><p><b>Что делать:</b></p><p>Для предотвращения XSS необходимо экранировать выводимые данные, используя функции, которые преобразуют специальные символы в HTML-сущности. Например, для шаблонов Go можно использовать html/template вместо text/template, что обеспечивает автоматическое экранирование данных.</p><p><b>Пример:</b></p><p>Мы выводим пользовательский ввод (заголовок и содержание поста) напрямую в HTML без экранирования, что позволяет внедрить JavaScript-код, если он по каким-то причинам ранее попал в базу. Чтобы это исправить, достаточно использовать библиотеку "html/template" </p><h3>Шаг 2. Защита от CSRF: используйте токены</h3><p><b>Проблема:</b></p><p>Если сервер не проверяет источник запроса, злоумышленник может заставить браузер пользователя выполнить запрос от его имени.</p><p><b>Что делать:</b></p><p>Пользователь открывает форму для создания поста. Если злоумышленник заставит пользователя отправить запрос POST /post, например, через &lt;img src="http://example.com/create?title=Hacked&amp;content=Malicious" /&gt;, сервер выполнит этот запрос, не проверяя, кто его отправил.</p><p>Для защиты от CSRF необходимо использовать специальные токены, которые уникальны для каждого запроса. Они проверяются сервером, и если токен отсутствует или недействителен, сервер отклоняет запрос. Один из вариантов — привязка CSRF-токенов к пользовательской сессии, что исключает возможность использования токенов другого пользователя злоумышленником. Для вашего удобства  — библиотеки по типу <a href="https://github.com/gorilla/csrf">gorilla/csrf</a>, которые обеспечивают защиту от CSRF-атак.</p><p>Дополнительно можно повысить уровень безопасности путем проверки заголовков Referer или Origin в POST-запросах, чтобы убедиться, что запрос поступил с доверенного источника. Также полезно ограничить CORS (Cross-Origin Resource Sharing), чтобы только определенные сайты могли отправлять запросы к вашему серверу.</p><p><b>Пример:</b></p><p>Чтобы исправить проблему, нужно создать CSRF-токен и проверять его во время создания поста.</p><p>Измененный метод для страницы создания поста:</p><p>Измененный метод сохранения поста:</p><h2>Шаг 3. Контроль доступа: избегайте уязвимостей IDOR/Broken ACL</h2><p><b>Проблема:</b></p><p>Все это — недостатки контроля доступа IDOR/Broken ACL. Данная проблема возникает, когда приложение позволяет пользователю получить доступ к ресурсам или действиям без надлежащей проверки прав. Это часто происходит, если доступ к ресурсам идентифицируется по значениям ID, которые можно предсказать или изменить.</p><p><b>Что делать:</b></p><p>Чтобы избежать уязвимостей IDOR и Broken ACL, нужно проверять права пользователя перед предоставлением доступа к ресурсам. Рассмотрим пример со следующим сниппетом кода.</p><p><b>Пример:</b></p><p>На сайт добавили возможность просматривать конкретный пост, если его передать в путь запроса /post/{{post_id}}</p><p>На первый взгляд, выглядит надежно. Но на самом деле нет проверки, принадлежит ли пост текущему пользователю. Это позволяет злоумышленнику получить доступ к любому посту, зная только его post_id.</p><p>Чтобы это исправить, достаточно в запросе указать признак пользователя:</p><p>Дополнительно стоит пересмотреть использование числовых идентификаторов постов, так как целочисленные значения можно легко перебирать. Например, злоумышленник может просто увеличить post_id и попытаться получить информацию о постах с большими ID, чтобы оценить популярность вашего сервиса по сравнению с конкурентами. Чтобы избежать этой проблемы, рекомендуется использовать <b>UUID версии v7</b>. Этот тип идентификаторов спроектирован так, чтобы хорошо работать с базами данных и не поддаваться простому перебору.</p><h3>Шаг 4. Не храните конфиденциальную информацию в открытом виде</h3><p><b>Проблема:</b></p><p>Если конфиденциальная информация хранится в базе в текстовом виде, любая утечка данных становится катастрофой. Это может произойти из-за ошибок в коде, некорректной конфигурации или утечек через логирование.</p><p><b>Что делать:</b></p><p>Для того, чтобы избежать раскрытия конфиденциальных данных, нужно не включать их в ответы API. Достаточно уменьшить уровень логирования для чувствительных данных, либо применить обфускацию конфиденциальных. Также советую избегать явного хранения секретов в коде.</p><p><b>Пример:</b></p><p>Обратим внимание на схему хранения данных пользователей:</p><p>В текущем коде можно заметить, что пароли хранятся в базе данных в поле типа TEXT в открытом виде. Это крайне небезопасно, так как любой, кто имеет доступ к базе данных, может получить учетные записи. Для безопасности следует хранить не сами пароли, а их хэши.</p><p>Для этого рекомендую использовать криптографическую хэш-функцию (Argon2 или её модификацию Argon2id). Этот алгоритм обеспечит надежное и безопасное хранение паролей.</p><p>Чтобы исправить текущую проблему, необходимо внести следующие изменения в код:</p><ol><li>Для работы с алгоритмом Argon2 следует использовать эту <a href="http://github.com/alexedwards/argon2id">библиотеку</a>.</li><li>При регистрации пользователя записывать в базу данных только хэш пароля, а не сам пароль. Это выглядит следующим образом:</li></ol><p>Если вы используете нестандартные параметры хэширования, рекомендуется сохранять их в базе данных рядом с хэшем, чтобы в будущем при миграции на новый алгоритм можно было поддержать обратную совместимость для старых пользователей. При авторизации необходимо сравнивать введённый пароль с хэшем, сохранённым в базе данных. Это можно реализовать следующим образом:</p><h3>Шаг 5. Защита от SQL-инъекций: используйте подготовленные запросы</h3><p><b>Проблема:</b></p><p>SQL-инъекции возникают, когда пользовательский ввод обрабатывается напрямую в SQL-запросах без должной фильтрации или экранирования. Злоумышленник может вставить вредоносный SQL-код, чтобы получить доступ к данным, изменить их или уничтожить.</p><p><b>Что делать:</b></p><p>Для защиты от SQL-инъекций важно всегда использовать подготовленные выражения. Это гарантирует, что пользовательский ввод будет экранирован и не интерпретируется как часть SQL-запроса. Вместо того, чтобы вручную собирать запросы, всегда передавайте параметры через символы ? или $1, в зависимости от используемой базы данных. Советую никогда не добавлять данные напрямую в строку SQL-запроса, поскольку это открывает возможность для SQL-инъекций.</p><p>Кроме того, важно тщательно проверять и валидировать пользовательский ввод, чтобы он соответствовал ожидаемому формату. Например, для email-адресов или других данных используйте регулярные выражения, чтобы удостовериться, что ввод соответствует нужному шаблону. Это помогает предотвратить некорректные или потенциально опасные данные, которые могут быть использованы для атаки на вашу систему.</p><p><b>Пример:</b></p><p>Для защиты от SQL-инъекций достаточно использовать подготовленные выражения, что значительно повышает безопасность приложения. В примере выше достаточно просто заменить строку запроса на использование параметризированных запросов:</p><p>Если вы работаете с более сложными запросами в Go, то можно использовать библиотеку <a href="https://github.com/Masterminds/squirrel">squirrel</a>, которая помогает безопасно строить запросы и избегать ошибок при работе с SQL.</p><p>Как видно, большинство проблем связано с валидацией и правильной обработкой данных, поступающих от внешнего мира. Очень важно не пренебрегать проверкой краевых случаев, ведь именно они зачастую становятся источником уязвимостей и неполадок.</p><p>Кроме того, хочу обратить внимание на еще одну важную практику, которая часто упускается — использование инструмента golangci-lint. На данный момент это стандарт для разработчиков Go, хотя иногда можно встретить проекты, где инструмент не используется. Он позволяет автоматически находить уязвимости, ошибки и антипаттерны в коде на ранних стадиях разработки. В состав golangci-lint входит статический анализатор gosec, который ориентирован на поиск проблем безопасности. Использование инструмента помогает существенно снизить риски ошибок в продакшене. Для других популярных языков программирования также существуют аналогичные инструменты, которые стоит учитывать при разработке.</p><h2>Перспективные технологии и подходы в защите backend</h2><p>В области защиты backend существуют несколько перспективных технологий и подходов, которые могут значительно улучшить безопасность.</p><h3>Zero Trust Architecture (ZTA) или Zero Trust Policy (ZTP)</h3><p>Основывается на принципе «никому не доверять». В рамках этого подхода ни один запрос не считается доверенным по умолчанию, даже если он поступает из внутренней сети. Это означает, что сервисы, принадлежащие одной команде, не могут автоматически доверять друг другу. Для взаимодействия между ними необходимо запрашивать доступы, которыми можно централизованно управлять, что повышает уровень контроля и безопасности.</p><h3>Гомоморфное шифрование (Homomorphic Encryption)</h3><p>Это метод, который позволяет выполнять вычисления с зашифрованными данными, не расшифровывая их. Результаты вычислений могут быть открыты только после завершения операции. Такой подход особенно полезен в ситуациях, когда данные нужно обрабатывать сторонними системами и сохранять их конфиденциальность. Например, в законодательстве РФ существует ответственность за утечки персональных данных, что может привести к серьезным финансовым потерям или даже закрытию бизнеса. Гомоморфное шифрование помогает решить эту проблему, обеспечивая обработку данных без их раскрытия.</p><h3>DevSecOps</h3><p>Это подход, который интегрирует безопасность в процессы разработки и эксплуатации на всех этапах жизненного цикла ПО. Акцент делается на автоматизацию, сотрудничество и постоянное улучшение безопасности. Главная цель DevSecOps — сделать безопасность не отдельным этапом, который следует после завершения разработки, а неотъемлемой частью культуры и процессов проекта.</p><h2>Навыки backend-разработчика, которые защитят его от уязвимостей</h2><p>Инженер, который стремится к минимизации ошибок и безопасности продукта, должен обладать рядом ключевых навыков. Рассмотрим их подробнее.</p><p>В первую очередь — глубокое понимание принципов безопасности. Это включает в себя знание распространённых уязвимостей — SQL-инъекции, XSS, CSRF, SSRF и другие угрозы из списка <a href="https://owasp.org/Top10/">OWASP</a>. Важно также осознавать принципы минимизации привилегий и безопасного проектирования.</p><p>Неотъемлемая часть работы — практика безопасного программирования. Разработчик должен уметь работать с механизмами аутентификации и авторизации — OAuth 2.0, OpenID Connect и JWT, а также использовать защищённые соединения (TLS/HTTPS) и шифрование (AES, RSA).</p><p>Отдельного внимания заслуживает безопасность API. Инженер должен понимать, как проектировать защищённые интерфейсы, применять ограничения на частоту запросов, валидацию входных данных и проверку токенов. Кроме того, важно уметь работать с инструментами безопасности — SAST (SonarQube, Checkmarx), DAST (OWASP ZAP, Burp Suite) и SCA (Snyk, Dependabot).</p><p>Разбираясь в инфраструктуре и безопасности развертывания, разработчику необходимо уверенно управлять контейнерами (Docker, Kubernetes), работать с облачными сервисами (AWS, Azure, GCP) и использовать встроенные механизмы защиты. Также важно понимать принципы мониторинга и реагирования на инциденты: анализировать логи, настраивать системы оповещения и оперативно реагировать на угрозы.</p><p>Для повышения уровня безопасности команде пригодится не только обладать знаниями, но и регулярно их обновлять. Начать можно с изучения рейтинга <a href="https://owasp.org/Top10/">OWASP Top 10</a>, в котором собраны наиболее актуальные угрозы. Однако теория без практики бессмысленна, поэтому стоит использовать платформы для тренировки — Hack The Box, PortSwigger Academy и PentesterLab.</p><p>Внедрение DevSecOps-подходов значительно повышает защищённость системы. Автоматизированные инструменты — статический анализ кода (SAST), динамическое тестирование (DAST) и анализ зависимостей (SCA), должны быть интегрированы в процесс CI/CD.</p><p>Дополнительно можно организовать внутренние соревнования в формате Capture The Flag (CTF), чтобы вовлечь команду в процесс, и повысить уровень её осведомлённости. Если этот формат вам незнаком, можно изучить примеры, например, соревнования, проводимые Google — <a href="https://github.com/google/google-ctf">Google CTF</a>.</p><p>Периодические анонимные проверки на уязвимости — тесты на фишинг или моделирование атак через подмену точек доступа, помогут выявить слабые места и укрепить защиту.</p><p><b>На мой взгляд, самое главное </b>— создать в команде культуру безопасности. Регулярные обсуждения, обмен знаниями и поощрение сотрудников за выявленные уязвимости помогут не только снизить риски, но и сделать безопасность естественной частью рабочего процесса.</p><p>Мой главный совет для backend-разработчиков по безопасности: с самого начала разработки внедряйте инструменты и методы, направленные на снижение рисков уязвимостей на всех этапах разработки и эксплуатации. Обеспечение безопасности — сложный и многогранный процесс, который требует значительных усилий и изменения культуры внутри всей компании. Навыки кибербезопасности больше не исключительная сфера узких специалистов, а необходимость для каждого человека в современном мире.</p><h2>Полезные материалы по статье</h2><ul><li><a href="https://securelist.ru/top-10-web-app-vulnerabilities/109215/">Топ-10 уязвимостей в веб-приложениях в 2021–2023 годах в Securelist от Kaspersky</a></li><li><a href="https://www.ptsecurity.com/ru-ru/research/analytics/web-vulnerabilities-2020-2021/">Доклад от Positive Technology «Уязвимости и угрозы веб-приложений в 2020–2021 гг»</a></li><li><a href="https://t.me/yandex_bugbounty/23">Публичная статистика bug bounty от компании Яндекс за 2024 год</a></li><li><a href="https://github.com/sshaplygin/5-steps-for-protect">Репозиторий с исходным кодом проекта, где лежат примеры из статьи</a></li><li><a href="https://owasp.org/Top10/">Топ-10 уязвимостей в веб-приложениях в 2021 году от  организации OWASP</a></li><li><a href="https://golangci-lint.run">Инструмент golangci-lint</a></li><li><a href="https://github.com/google/google-ctf">Примеры проведения CTF от компании Google</a></li><li><a href="https://github.com/P-H-C/phc-winner-argon2">Исходный код хэш-функции Argon2</a></li></ul>]]></content:encoded>
    </item>
    <item>
      <title>Go Module Mirror три года распространял бэкдор — его заметили только сейчас</title>
      <link>https://tproger.ru/news/go-module-mirror-tri-goda-rasprostranyal-bekdor---ego-zametili-tolko-sejchas</link>
      <comments>https://tproger.ru/news/go-module-mirror-tri-goda-rasprostranyal-bekdor---ego-zametili-tolko-sejchas?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/go-module-mirror-tri-goda-rasprostranyal-bekdor---ego-zametili-tolko-sejchas</guid>
      <description><![CDATA[<p>Go Module Mirror три года распространял бэкдор из-за типосквоттинга. Бэкдор в boltdb-go/bolt угрожал тысячам проектов, но был удалён лишь в 2025 году</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/go-module-mirror-tri-goda-rasprostranyal-bekdor---ego-zametili-tolko-sejchas">Go Module Mirror три года распространял бэкдор — его заметили только сейчас</a>»</p>]]></description>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Google]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Хакеры]]></category>
      <category><![CDATA[Уязвимость]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 11 Feb 2025 06:57:36 GMT</pubDate>
      <content:encoded><![CDATA[<p>Исследователи обнаружили, что <b>Go Module Mirror</b> — официальный прокси-сервис от Google для загрузки Go-модулей — <b>три года распространял бэкдор</b>.</p><p>Всё это время разработчики могли случайно установить зараженный пакет вместо оригинального, даже не подозревая об угрозе.</p><p>Речь идёт о <b>поддельном модуле</b> boltdb-go/bolt, который маскировался под <b>популярную библиотеку</b> boltdb/bolt.</p><p>Этот пакет — <b>зависимость для более чем 8000 других проектов</b>, что делает атаку особенно опасной.</p><h2>Как это произошло?</h2><p>Хакеры использовали метод <b>«типосквоттинга»</b>: создали <b>почти идентичное название</b>, надеясь, что кто-то ошибётся при вводе команды. Вредоносный код появился <b>ещё в 2021 году</b> и попал в кэш Go Module Mirror.</p><p>После этого злоумышленники <b>стерли следы</b> — обновили репозиторий на GitHub, заменив бэкдор <b>чистым кодом</b>. Однако механизм Go <b>не очищает закэшированные версии</b>, поэтому прокси <b>продолжал раздавать заражённый пакет</b>.</p><h2>Что делал бэкдор?</h2><p>При установке <b>бэкдор открывал удалённый доступ</b> к устройству. Он подключался к <b>скрытому серверу</b>, позволял хакерам <b>выполнять команды</b>, а также автоматически <b>перезапускался</b> при сбоях.</p><p>Сервер для управления атакой находился в сети <b>Hetzner Online</b> — уважаемого хостинг-провайдера. Это помогло <b>обойти антивирусы</b> и затруднило обнаружение атаки.</p><h2>Почему это заметили только сейчас?</h2><p>Компания <b>Socket</b> обнаружила бэкдор только в конце января 2025 года.</p><p>Они сразу же запросили его удаление, но Google <b>не торопилась</b>. Лишь после <b>второго обращения 3 февраля</b> заражённый модуль был исключён из Go Module Mirror.</p><h2>Какие выводы?</h2><p>Этот случай успешно продемонстрировал <b>уязвимость механизмов кэширования</b>.</p><p>Разработчики зависят от Go Module Mirror, но он <b>не проверяет изменения в оригинальных репозиториях</b>. Это означает, что <b>если вредоносный код попал в кэш, он там остаётся навсегда</b>, пока его не удалят вручную.</p><h4>Что делать?</h4><ul><li><b>Внимательно проверять имена пакетов</b> перед установкой.</li><li>Использовать <b>инструменты безопасности</b>, анализирующие зависимости.</li><li>Требовать от Google и Go Team <b>улучшения защиты Go Module Mirror</b>.</li></ul><p>Хотя заражённый пакет уже удалён, <b>никто не гарантирует</b>, что подобное не повторится снова.</p>]]></content:encoded>
    </item>
    <item>
      <title>Горшочек — вари. Gift анимация в Telegram.</title>
      <link>https://tproger.ru/articles/gorwochek---vari--gift-animaciya-v-telegram--254349</link>
      <comments>https://tproger.ru/articles/gorwochek---vari--gift-animaciya-v-telegram--254349?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[apiTON]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/gorwochek---vari--gift-animaciya-v-telegram--254349</guid>
      <description><![CDATA[<p>Разбираем формат JSON файлов из блокчейна для gift NFT от Telegram и учимся отображать анимацию у себя в web приложениях и ботах.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/gorwochek---vari--gift-animaciya-v-telegram--254349">Горшочек — вари. Gift анимация в Telegram.</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[JSON]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Telegram]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[NFT]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 10 Feb 2025 15:22:57 GMT</pubDate>
      <content:encoded><![CDATA[<p>С появлением NFT-подарков (gift) в Telegram у пользователей и разработчиков возникло множество вопросов, связанных с их интеграцией и отображением. Поскольку нововведение базируется на TON, многие аспекты требуют технического понимания и навыков работы с экосистемой мессенджера. В этой статье расскажу, как отображать анимацию NFT-подарков в ваших приложениях, а также поделюсь своим опытом работы с TON Blockchain Explorer, интегрированным в Telegram.</p><h2>Как отображать анимацию NFT-подарков?</h2><p>Для начала рассмотрим контракт, который содержит данные о NFT-подарке:</p><p><a href="https://t.me/apitonBot?start=RVFBNlQxZXQ3WVctajMwV1VianAxM1NXWWdGT0NQYTgwNi12SVhYSU1ZaW4yaEcw">0:3a4f57aded85be8f7d1651b8e9d7749662014e08f6bcd3afaf2175c83188a7da</a></p><figure><img src="https://media.tproger.ru/user-uploads/111922/2025-02-06/1e041e1f-3cb6-4e61-91d9-21fa8416ab8d.png" alt="" /><figcaption>0:3a4f57aded85be8f7d1651b8e9d7749662014e08f6bcd3afaf2175c83188a7da</figcaption></figure><p>Из этого контракта можно получить всю необходимую информацию: атрибуты, описание и т.д. Эти данные можно запросить через API или вручную, нажав кнопку <b>More</b> в интерфейсе:</p><figure><img src="https://media.tproger.ru/user-uploads/111922/2025-02-06/c33d3c93-f3fe-411c-bba6-2a059cedcd17.png" alt="" /><figcaption>hexpot-10348.json</figcaption></figure><p>Там мы видим ссылочку с поясняющим ключом и именем: </p><p>Что именно мы из этого узнаём? Что анимация хранится в виде lottie.  Эта информация очень полезна, так как с помощью нее мы сможем отображать и свою анимацию. Но как это сделать?</p><h2>Как отобразить анимацию в вашем приложении?</h2><p>Lottie — библиотека, разработанная компанией Airbnb. Позволяет отображать анимации в формате JSON, созданные с помощью AdobeAfter Effects. Благодаря Lottie разработчикам можно легко интегрировать высококачественные анимации в мобильные и веб-приложения, обеспечивая плавность и масштабируемость без значительного увеличения размера.</p><p>Применим на практике. Отобразить анимацию в вашем web. или TMA приложении проще простого, через библиотеку <b>lottie-web</b>.</p><figure><img src="https://media.tproger.ru/user-uploads/111922/2025-02-06/acabbb6d-14d1-41f6-9b57-d14b70f9ea61.png" alt="" /></figure><p>В этом случае код будет выглядеть так:</p><p>Под разные языки есть также библиотеки для работы с форматом. Однако, в некоторых случаях, людям приходят странные идеи конвертировать анимацию:</p><ul><li>через ffmpg в mp4 (больший размер);</li><li>покадрово в <a href="https://github.com/ii64/go-rlottie/blob/main/_example/lottie2gif/main.go">gif</a> (потеря качества и размера);</li><li>через webview.</li></ul><p>Моя задача состоит же в отправке анимации пользователю непосредственно в Telegram. Логично, что формат хранения в Lottie выбран не просто так. Довольно много NFT хранятся в mp4, gif, webm.</p><p>Разгадка кроется не только в компактном размере данного формата, но и в устройстве Telegram стикеров.</p><p>Для решения задачи используем следующую схему:</p><ol><li>загружаем <a href="https://nft.fragment.com/gift/hexpot-10348.lottie.json">https://nft.fragment.com/gift/hexpot-10348.lottie.json</a>;</li><li>сжимаем в gzip;</li><li>отправляем в Telegram, например, в виде документа.</li></ol><p>На golang это может выглядеть так:</p><p>Как мы видим, это лишь немного сложнее, чем отправить обычную картинку.</p><p>Для разработчиков, использующих TON и интеграцию в Telegram, освоение работы с Lottie открывает новые возможности для создания интерактивных анимаций. Если вы только начинаете свой путь в этой сфере или уже имеете опыт, важно продолжать изучать документацию и экспериментировать с доступными инструментами, чтобы оставаться в тренде и предлагать пользователям лучшие решения.</p><p>P.s. Всегда готов ответить на ваши вопросы. Пишите в тг <a href="https://t.me/apitonDev">@apitonDev</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как упаковать бэкенд-код на Go для аналитики на базе Spark</title>
      <link>https://tproger.ru/articles/kak-upakovat-bekend-kod-na-go-dlya-analitiki-na-baze-spark</link>
      <comments>https://tproger.ru/articles/kak-upakovat-bekend-kod-na-go-dlya-analitiki-na-baze-spark?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Марина Орлова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-upakovat-bekend-kod-na-go-dlya-analitiki-na-baze-spark</guid>
      <description><![CDATA[<p>Всем привет! Я Ваня Ахлестин, занимаюсь поддержкой и развитием аналитической платформы кластера Search&amp;Recommendations на базе Spark и Hadoop в Авито. Сегодня расскажу, как начать использовать ваш код из Python или PySpark и не тратить много времени дорогих разработчиков.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-upakovat-bekend-kod-na-go-dlya-analitiki-na-baze-spark">Как упаковать бэкенд-код на Go для аналитики на базе Spark</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Библиотеки]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 10 Jan 2025 14:00:04 GMT</pubDate>
      <content:encoded><![CDATA[<p>Всем привет! Меня зовут Ваня Ахлестин, я занимаюсь поддержкой и развитием аналитической платформы кластера Search&amp;Recommendations на базе Spark и Hadoop.</p><p>Большинство сервисов в хайлоаде, работу которых мы логируем и исследуем, давно переписаны на Go. Из-за этого часто необходимо переиспользовать логику сервиса внутри аналитического или ML-приложения на Spark. Как примеры такого кода можно взять расчёт скоров по сложному запросу или ранжирование айтемов для выдачи.</p><p>Реимплементировать и поддерживать несколько вариантов кода дорого, заниматься обстрелом сервисов долго и больно. Поэтому сегодня я расскажу, как начать использовать ваш код из Python или PySpark и не тратить много времени дорогих разработчиков.</p><h2>Немного о нашей инфраструктуре</h2><p>Наша платформа построена на классической связке Hadoop/YARN/Spark/PySpark. Основной язык разработки — Python 3.11. Мы стараемся придерживаться баланса между зрелостью и актуальностью софта, чтобы не погрязнуть в поддержке легаси решений. Для этого мы долго обучали разработчиков и аналитиков писать тесты для их задач.</p><p>Изначально Python был выбран вместо Scala, чтобы снизить порог входа и дать возможность каждому работать с продуктовым кодом вместо выделенной команды бигдата-инженеров, реимплементирующих код от аналитиков и ML.</p><p>В типичных цикл разработки входит:</p><ul><li>Проектирование — обсуждаем и подготавливаем данные для задачи, эксперимента, проговариваем примерную реализацию.</li><li>Прототип в Jupiter ноутбуках, первое ревью, проверяем надёжность и качество исходных данных.</li><li>Упаковываем задачу в формат Airflow, настраиваем, покрываем тестами и тестовыми данными, настраиваем метрики.</li></ul><p>Для аналитики работы сервисов мы обычно используем пайплайн с логированием JSON структур в Kafka, данные из которой в HDFS поставляет задача на Flink. Реплей таких логов на кластере через PySpark UDF — об этом и написана статья.</p><h2>CGO, или собираем биндинг дешево</h2><p>Первое, о чём нужно подумать при работе с кодом сервиса — как организовать биндинг со сложными вложенными структурами вашего сервиса.</p><p>Тут есть несколько подходов:</p><ul><li>Довериться генератору биндингов, например <a href="https://github.com/go-python/gopy">GoPy</a>. Самое очевидное решение, которое мы и попробовали в первую очередь. К сожалению, результат был негативным:биндинг содержит много мусора и ненужных артефактов;требуется дополнительно его патчить, не всё работает «из коробки»;структуры биндинга уродливы, над ними нужна ещё одна обертка;код неэффективен;собранный пакет жёстко привязывается к определённой версии интерпретатора — у нас есть несколько версий и дистрибутивов Python.</li><li>биндинг содержит много мусора и ненужных артефактов;</li><li>требуется дополнительно его патчить, не всё работает «из коробки»;</li><li>структуры биндинга уродливы, над ними нужна ещё одна обертка;</li><li>код неэффективен;</li><li>собранный пакет жёстко привязывается к определённой версии интерпретатора — у нас есть несколько версий и дистрибутивов Python.</li></ul><p>Поэтому такие биндинги не очень долго прожили — требовали постоянного внимания.</p><ul><li>Написать биндинг вручную. Существует много туториалов, как это сделать, но есть сложности:поддержка однообразных структур и кода на С;есть привязка к ABI Python, нужна сборка под конкретный Python;чтобы поддерживать в актуальном виде, нужно время квалифицированного разработчика.</li><li>поддержка однообразных структур и кода на С;</li><li>есть привязка к ABI Python, нужна сборка под конкретный Python;</li><li>чтобы поддерживать в актуальном виде, нужно время квалифицированного разработчика.</li></ul><ul><li>Использовать сериализацию в промежуточный формат. Плюсы:если это JSON, то сервис его уже использует, он нативен для кода;Spark и Python уже умеют его использовать «из коробки»;можем передать в код клиента схему с описанием структур;не нужно поддерживать код самого биндинга.</li><li>если это JSON, то сервис его уже использует, он нативен для кода;</li><li>Spark и Python уже умеют его использовать «из коробки»;</li><li>можем передать в код клиента схему с описанием структур;</li><li>не нужно поддерживать код самого биндинга.</li></ul><p>Минус — есть дополнительные расходы на упаковку-распаковку, но и быстрые парсеры тоже есть. На этом варианте мы и остановились.</p><h2>Минимальный биндинг изнутри</h2><p>Чтобы было проще разобраться, я подготовил <a href="https://gitflic.ru/project/akhlestin/go_py_spark_demo">демо-проект</a> со следующей структурой:</p><figure><img src="https://media.tproger.ru/user-uploads/109956/2025-01-09/31e65bce-753b-4323-9bb0-6ffb8949bfe5.png" alt="" /></figure><p>Основная идея проекта:</p><ul><li>Собрать shared библиотеку с С-интерфейсом.</li><li>Добавить к ней Python-биндинг с использованием ctypes.</li><li>Упаковать в переносимый пакет (Wheel), готовый для установки в любое окружение для платформы.</li></ul><h2>Бекэнд-код на Go</h2><p>Демо-код бэкенд-логики содержит вложенные структуры и код, который их принимает и возвращает — это максимально типичная ситуация в реальной жизни. Структуры уже размечены для JSO- генератора — это необязательно.</p><h2>Экспортируем функции и структуры через C Call интерфейс</h2><p>Как видно, всё, что делает код — это принимает и возвращает строки с JSON. Для описания структур используется JSON Schema. Это не идеальный вариант — из-за ограниченности типов JSON больше демонстрация возможности использовать рефлекшены для создания схемы.</p><h2>Собираем всё в разделяемую библиотеку</h2><h2>Обёртка на Python</h2><p>Используем ctypes с динамической загрузкой собранной библиотеки.</p><p>И не забываем про сборку проекта в пакет:</p><p>Всё, что нужно — Python и установленный poetry. При запуске сборки poetry build собирает пакеты source и wheel. Пакет wheel как раз и предназначен для дистрибьюции бинарных зависимостей для Python.</p><h2>PEX как контейнер, и деплой кода на кластер</h2><p>Любой PySpark скрипт с python-udf перед тем, как начать выполнять план запроса на кластере, производит сериализацию функции и всех обьектов из её контекста через библиотеку <a href="https://pypi.org/project/cloudpickle/">cloudpickle</a>. То есть, для того, чтобы восстановить функцию на кластерных пайтон-воркерах нужно обеспечить действительность всех ссылок из pickle.</p><p>Существует несколько способов деплоя Python окружения на кластер:</p><ol><li>Устанавливать библиотеки в окружение системного Python.</li></ol><ul><li>Плюс: просто сделать.</li></ul><ul><li>Минусы:сложно синхронизировать и следить за всеми артефактами.невозможно работать и отлаживать несколько разных окружений, а использование venv только всё усложняет;сложно отследить, какие версии использовались в определенный момент.</li><li>сложно синхронизировать и следить за всеми артефактами.</li><li>невозможно работать и отлаживать несколько разных окружений, а использование venv только всё усложняет;</li><li>сложно отследить, какие версии использовались в определенный момент.</li></ul><ol><li>Использовать docker/kubernetes.</li></ol><ul><li>Плюс: можно сделать любое окружение.</li><li>Минус: не подходит для bare-metal инсталляций с Hadoop</li></ul><ol><li>Деплой через EGG.</li></ol><ul><li>Минус: работает только с нативным Python-кодом — не получится использовать биндитнги из-за ограничений zipimport.</li><li>Плюс: работает из коробки, не нужно паковать всё окружение, если библиотека самодостаточна</li></ul><ol><li>Использование законсервированных окружений в виде conda-pack, venv-pack, pex.</li></ol><ul><li>Плюсы:разово собирается и пакуется окружение, не получится испортить.прозрачно деплоится на кластер, но нужно оркестрировать установку на все тачки.возно версионировать синхронно с основным кодом.</li><li>разово собирается и пакуется окружение, не получится испортить.</li><li>прозрачно деплоится на кластер, но нужно оркестрировать установку на все тачки.</li><li>возно версионировать синхронно с основным кодом.</li><li>Минус: PEX-пакет весит как полноценный virtualenv.</li></ul><p>Мы используем динамическую версию из Git в виде комбинации тега, майлстоуна, хеша коммита и признака dev-ветки.</p><p>Для себя мы выбрали <a href="https://pypi.org/project/pex/">PEX</a> как наиболее зрелый вариант пакета. Если коротко, то это self-extacted virtualenv, упакованный в обычный zip и снабжённый бустстап-секцией для поиска хост-интерпретатора.</p><p>Для использования PEX как интерпретатора Python на кластере нужно модифицировать настройки Spark. У нас конфигурация контекста выглядит примерно так:</p><p>Для сборки PEX-пакета достаточно самой утилиты pex и списка всех пакетов, которые должны быть в него установлены:</p><p>Естественно, что в PEX-пакете должен находится pyspark, иначе Spark не сможет запустить Python-воркеры на кластерных машинах.</p><h2>Включаем нашу UDF в работу</h2><p>Подразумевается, что Spark-сессия запущена, настроена и используется PEX.</p><p>Чтобы дальше оперировать со структурами в привычном виде, описываем схему сообщения в формате Spark и используем коробочную функцию <a href="https://spark.apache.org/docs/latest/api/python/reference/pyspark.sql/api/pyspark.sql.functions.from_json.html?highlight=from_json#pyspark.sql.functions.from_json">from_json</a>.</p><h2>Что почитать по теме</h2><ul><li><a href="https://pkg.go.dev/cmd/cgo">Туториал по CGo</a>;</li><li><a href="https://docs.python.org/3/library/ctypes.html">документация к ctypes</a>;</li><li><a href="https://spark.apache.org/docs/latest/api/python/user_guide/python_packaging.html">PySpark Package Management</a>.</li></ul>]]></content:encoded>
    </item>
    <item>
      <title>Go: что ты знаешь о горутинах и каналах? Уровень — easy</title>
      <link>https://tproger.ru/quiz/go--chto-ty-znaew-o-gorutinah-i-kanalah--uroven---easy</link>
      <comments>https://tproger.ru/quiz/go--chto-ty-znaew-o-gorutinah-i-kanalah--uroven---easy?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Анна Ельцова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/quiz/go--chto-ty-znaew-o-gorutinah-i-kanalah--uroven---easy</guid>
      <description><![CDATA[<p>Горутины и каналы — чуть ли не самые мощные инструменты в Golang. Листайте вниз, отвечайте на вопросы — докажите, что вы знаете об этих парнях все!</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/quiz/go--chto-ty-znaew-o-gorutinah-i-kanalah--uroven---easy">Go: что ты знаешь о горутинах и каналах? Уровень — easy</a>»</p>]]></description>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Викторины]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 01 Jan 2025 09:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если вы программируете на Go, то наверняка уже сталкивались с понятием горутин и каналов — они помогают писать эффективный конкурентный код. Горутины помогают запускать задачи параллельно, а — каналы обеспечивают безопасное взаимодействие между ними.</p><p>Вот, кстати, несколько интересных материалов о Golang:</p><ul><li><a href="https://tproger.ru/articles/kak-napisat-proizvoditelnyj-i-bezopasnyj-backend-na-go">Как написать производительный и безопасный backend на Go</a></li><li><a href="https://tproger.ru/articles/operator-kubernetes-na-go-i-kubebuilder-dlya-nachinayushhih">Оператор Kubernetes на Go и Kubebuilder для начинающих</a></li><li><a href="https://tproger.ru/books/sem-glavnyh-knig-dlja-golang-razrabotchika-ot-donovana-i-kernigana-do-makdaujella">7 must-have книг для Go-разработчиков</a></li></ul>]]></content:encoded>
    </item>
    <item>
      <title>Как устроена межсервисная авторизация в Авито PaaS</title>
      <link>https://tproger.ru/articles/mezhservisnaya-avtorizaciya-v-avito-paas</link>
      <comments>https://tproger.ru/articles/mezhservisnaya-avtorizaciya-v-avito-paas?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Марина Орлова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/mezhservisnaya-avtorizaciya-v-avito-paas</guid>
      <description><![CDATA[<p>Антон Губарев, инженер в Avito PaaS, рассказал, как реализовать межсервисную авторизацию на 2500 сервисов и ничего не сломать.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/mezhservisnaya-avtorizaciya-v-avito-paas">Как устроена межсервисная авторизация в Авито PaaS</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Тестирование]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[JSON]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[GitHub]]></category>
      <category><![CDATA[Сервисы]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Kubernetes]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 26 Dec 2024 11:00:21 GMT</pubDate>
      <content:encoded><![CDATA[<p>Привет! Меня зовут Антон Губарев, я работаю инженером в Avito PaaS и веду канал о техническом лидерстве и инфраструктурной разработке на Go <a href="https://t.me/devlead">«Техлидошная»</a>. Сегодня я расскажу о том, как мы реализовывали межсервисную авторизацию в рамках платформы и с какими проблемами столкнулись. Я  — фича-лид и основной разработчик этого проекта, поэтому мне есть, чем поделиться.</p><h2>PaaS в Авито: 2500 сервисов, на которых нужно было реализовать авторизацию, и ничего не сломать</h2><p>PaaS, по сути — набор готовых решений, который помогает продуктовым разработчикам не тратить время на погружение в особенности инфраструктуры: как она работает, как устроен прод, сколько используется своих дата-центров, сколько — облачных, и так далее. Подробнее про PaaS в Авито <a href="https://habr.com/ru/companies/avito/articles/527400/">можно почитать в статье моего коллеги Александра Лукьянченко</a>.</p><p>В PaaS есть UI-интерфейс — дашборд. В нём находится всё для управления сервисами. Например:</p><ul><li>деплой в разные окружения;</li><li>информация о потреблении ресурсов;</li><li>задеплоенные манифесты в Kubernetes;</li><li>связи: в какие другие сервисы ходит этот сервис и откуда приходят запросы к нему.</li></ul><p>Ещё у нас есть собственный формат для межсервисного взаимодействия — brief. Он похож на Protobuf, но немного упрощённый и заточенный под наши требования.</p><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-24/b7753867-f9ae-47c5-a08b-69830d69ec20.png" alt="" /><figcaption>Так выглядит дашборд AvitoPaaS</figcaption></figure><p>Пример брифа:</p><p>Похоже на protobuf, но только гораздо проще. Это значит, потребуется немного времени на погружение и вход.</p><p>Вот, как команды используют Brief:</p><ol><li>Разработчики пишут brief-схемы для сервиса, описывают ручки, которые хотят сделать.</li><li>Затем они используют генератор, который на нужном языке программирования генерит код сервера и клиента</li><li>Остается только реализовать логику внутри ручек или использовать клиенты для походов в другие сервисы</li><li>При деплое brief-схемы регистрируются в отдельном реестре</li></ol><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-24/f3b841e1-4ba1-4d42-86b0-6193baba2463.png" alt="" /><figcaption>Зарегистрированные схемы также отображаются на дашборде. Можно видеть всех потребителей ручки и даже потребителей конкретных полей</figcaption></figure><p>Внутри платформы 2500 сервисов, и все они тесно связаны друг с другом форматом Brief. На этом большом живом организме нам нужно было реализовать авторизацию так, чтобы ничего не сломалось. Поговорим о том, как мы это делали.</p><h2>Наши требования к межсервисной авторизации</h2><p>Чтобы понять, каким будет наше решение для межсервисной авторизации, мы опросили команды сервисов, живущих внутри PaaS, поговорили с отделом безопасности, и выявили шесть требований:</p><ol><li>Контролировать доступ к ручкам. Часть сервисов или отдельные ручки могут содержать чувствительную информацию: данные пользователей или финансовые показатели.</li><li>Логировать изменения. Нужно знать, кто и когда вносил изменения и пользовался ручками, — это основа любой системы безопасности.</li><li>Не сломать связи 2.500 сервисов. Нарушение любой из связей могло привести к деградации продакшена.</li><li>Не менять сервисы. Сервисов много, поэтому заставлять сотни разработчиков вносить изменения в свои сервисы — неправильно.</li><li>Не повлиять на скорость работы. Для некоторых сервисов лишние 10мс — уже критично.</li><li>Сделать платформенное решение. Некоторые команды уже стали пилить свою локальную авторизацию: например, через JWT-токены. Нам нужно было централизованное и удобное решение, подходящее всем.</li></ol><p>Проанализировав требования, мы стали думать, как продуктово организовать конфигурацию политик авторизации.</p><h2>Конфигурация политик авторизации. Как это выглядит для пользователя</h2><p>У нас уже был подход конфигурации как код. В каждом сервисе есть файлик app.toml, на основании которого наша платформа катит сервис так, как это нужно разработчикам:</p><ul><li>с нужным количеством реплик;</li><li>с нужными переменными окружения;</li><li>с указанным расписанием запуска кронов;</li><li>и многое другое.</li></ul><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-24/a05c6cce-653f-4543-8e67-67864eaec78d.png" alt="" /><figcaption>Пример конфига app.toml</figcaption></figure><p>Формат при этом максимально абстрагирован от инфраструктурных деталей и прост в использовании.</p><p>Политики конфигурируются через файл auth.toml — по аналогии с app.toml. Вот почему мы решили так сделать:</p><ul><li>разработчики уже привыкли к toml;</li><li>можно логировать и апрувить изменения через git и настройки codereview;</li><li>можно использовать канареечное тестирование;</li><li>разработчикам не нужно погружаться в реализацию.</li></ul><p>Структура auth.toml состоит из двух разделов: default и policy. Они позволяют задать общие правила и конкретизировать их для отдельных ручек.</p><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-24/d2c251fd-81f2-4fbe-ae21-6770ff22a064.png" alt="" /><figcaption>Структура файла auth.toml</figcaption></figure><p>Политик может быть несколько. Главное — не повторять ручки, ни внутри политики, ни внутри всего auth.toml, чтобы избежать наложений. Это контролирует наш валидатор.</p><p>В политиках мы указываем набор ручек и перечисляем клиентов, которые имеют к ним доступ. Всем остальным на эти ручки доступ запрещен.</p><p>Какие типы клиентов существуют:</p><ul><li>сервисы — сервисы внутри PaaS.</li><li>пользователи — логин одного сотрудника (например, user:apgubarev) или целый юнит (например, user.unit:architecture).</li><li>внешние зависимости (например, ext:pass-bot).</li></ul><p>Генерация auth.toml происходит через утилиту auth init. Мы встроили её в свой внутренний CLI. Она позволяет не переписывать все ручки из брифа в auth.toml вручную и не допускать ошибок.</p><p>Утилита берёт потребителей из реестра, о котором я писал выше, и добавляет их в секцию default. Дальше разработчик может донастроить auth.toml через отдельные policy.</p><p>Также auth init добавляет в файл auth.toml мини-документацию, которая позволяет быстро вспомнить, какие разделы за что отвечают.</p><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-24/2e5df593-f3e9-43fc-b7a7-5d07b90b1a37.png" alt="" /><figcaption>Мини-документация, которая генерируется при инициализации auth.toml через утилиту</figcaption></figure><p>В итоге для пользователя вся конфигурация политик происходит в одном файле auth.toml. Всё остальное делаем мы.</p><h2>Техническая реализация</h2><p>У нас было два основных варианта, как сделать межсервисную авторизацию.</p><p>1. Запилить middleware для используемых языков. Но у такого решения есть ряд проблем:</p><p>– реализации на разных ЯП будут различаться и поддержка усложняется кратно количеству библиотек</p><p>– сложно обновлять — нужно вносить изменения в каждый сервис, а их я напомню 2500 и их количество растет.</p><p>– инфраструктурный слой протекает в сервисы — концептуально плохо.</p><p>2. Реализовать авторизацию на базе service mesh.</p><p>+ нет проблем, свойственных первому решению.</p><p>+ нагрузка только на команду PaaS, пользователям авторизации ничего делать не нужно.</p><p>В итоге мы остановились на service mesh на Istio. До Istio у нас было самописное решение, но сейчас Istio отвечает всем нашим потребностям — правда, приходится платить сложностью. Но это уже отдельная история.</p><p><a href="https://istio.io/">Подробнее про Istio →</a></p><p>Основной принцип любого service mesh — перехват входящего трафика и заруливание на сайдкар.</p><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-24/9303cb3b-6bbb-4359-b2f8-18348fd45b04.png" alt="" /><figcaption>Трафик попадает в сервис не напрямую, а через прокси</figcaption></figure><ol><li>В каждый под, где нужен service mesh, добавляется сайдкар.</li><li>Трафик приходит в сайдкар.</li><li>Из сайдкара трафик проксируется в сервис.</li></ol><p>Обратно — аналогично. Сервис шлет трафик не напрямую, а через прокси.</p><h2>Аутентификация через mTLS</h2><p>Прежде чем реализовывать авторизацию, нужно узнать имя клиента. Для аутентификации мы используем mTLS. Он уже был реализован у нас ранее для:</p><ul><li>шифрования чувствительных данных. Трафик даже внутри кластера может быть небезопасным, поскольку там работает куча сторонних библиотек.</li><li>защиты от несанкционированного доступа. Например, по IP пода. Чтобы постучаться в сервис, в mTLS нужен персональный сертификат. Сервис может управлять доступами, используя имена этих сертификатов.</li></ul><p>Подробнее про использование mTLS в Авито <a href="https://habr.com/ru/companies/avito/articles/674296/">можно почитать в статье моего коллеги</a>.</p><h2>Автоматизация выдачи сертификатов</h2><p>TLS-сертификаты для доступа к сервисам можно выдавать вручную, но лучше — генерировать их автоматически.  Для автоматизации выдачи сертификатов мы используем готовое решение — Spire.</p><p><a href="https://github.com/spiffe/spire">Spire на GitHub →</a></p><p>Spire реализует стандарт SPIFFE, который описывает подход к идентификации и управлению секретами в инфраструктуре. Spire состоит из двух частей:</p><ul><li>Сервер — отвечает за выпуск новых сертификатов.</li><li>Агент — выдает сертификаты.</li></ul><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-24/af60cf57-78f5-4f3b-a8f8-39694cfd3844.png" alt="" /><figcaption>Схема работы Spire</figcaption></figure><p>Вот, как работает автоматизация выдачи сертификатов с помощью Spire:</p><ol><li>Сервер выпускает новые сертификаты.</li><li>Агент запускается на каждой ноде.</li><li>Istio конфигурирует сайдкар так, чтобы он устанавливал соединения с другими сайдкарами по протоколу mTLS.</li><li>Istio конфигурирует envoy: где и как он может получать сертификаты.</li><li>Сайдкар приходит к указанному агенту и получает TLS-сертификат, с помощью которого шифрует трафик.</li></ol><p>Подробнее про Spire и SPIFFE <a href="https://habr.com/ru/companies/avito/articles/674296/">можно почитать в статье моего коллеги</a>.</p><h2>HTTP-фильтр</h2><p>Istio в качестве сайдкара использует envoy. Внутри envoy запрос проходит через цепочку фильтров и идет в целевой порт внутри пода, если его не заблокировал один из HTTP-фильтров. В Istio много готовых фильтров, но можно написать и свои.</p><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-24/a1662df3-81be-4378-a02f-b0c3f8c4f5eb.png" alt="" /><figcaption>Envoyproxy HTTP-фильтры</figcaption></figure><p>ext-authz спрашивает у некоего внешнего агента (можно подложить сюда что угодно, хоть самопис), можно ли запросу лететь дальше. Если запрос блокируется, envoy сразу отвечает кодом 403. До сервиса запрос даже не доходит.</p><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-24/77b16b0a-c19f-4572-914a-c6f0b7041454.png" alt="" /><figcaption>Если внешний агент заблокирует запрос, до сервиса он даже не дойдет</figcaption></figure><p>В качестве внешнего агента мы используем готовое и проверенное решение – Open Policy Agent.</p><h2>Open Policy Agent</h2><p>Open Policy Agent (OPA) — это CNCF-дипломированный проект, направленный на унификацию применения политик в различных технологиях и системах. Одно из назначений OPA — как раз service mesh. Плюс есть много готовых интеграций, в их числе — envoy.</p><p><a href="https://www.openpolicyagent.org/">Подробнее про Open Policy Agent →</a></p><p>OPA может работать в двух вариантах: как демон, или как Go-библиотека. В обоих случаях агенту можно передавать политики на языке Rego и данные в формате JSON.</p><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-24/d4e95ee8-f547-4a27-9ecb-fc3926bedea5.png" alt="" /><figcaption>Варианты использования OPA: демон или библиотека</figcaption></figure><p>Rego — это собственный декларативный язык OPA для выражения политик над сложными иерархическими структурами данных.</p><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-24/7f8cbeec-9e4b-4fbc-bfdd-ec69c7319480.png" alt="" /><figcaption>Пример кода на Rego</figcaption></figure><p>Особенность Rego в том, что он позволяет описывать сложные политики сокращённым синтаксисом — буквально в одно выражение. Для нас это было полезно, поскольку в поддержке можно очень быстро «продебажить» код глазами, даже не открывая IDE.</p><p>Другие плюсы Rego:</p><ul><li>читабельность. Например, прогон многомерного массива в Rego можно сделать так: sites[].servers[].hostname.</li><li>расширяемость. Поскольку Rego написан на Golang, в него легко добавлять свои плагины: например, для похода во внутренние API или БД.</li><li>удобное тестирование и дебаг. Например, можно сравнивать политики двух сервисов на совместимость.</li></ul><p><a href="https://www.openpolicyagent.org/docs/latest/policy-language/">Документация Rego →</a></p><h2>Перевод auth.toml в Rego</h2><p>В нашей схеме разработчики описывают политики в auth.toml. А наша задача перевести этот конфиг на Rego, чтобы его понимал Open Policy Agent.</p><p>Вот, как мы реализовали перевод auth.toml в rego всего в пару сотен строк кода.</p><p>1. Общая часть. Забираем нужные входные данные, определяем тип клиента, устанавливает значения по умолчанию (например, allow = false).</p><p>2. Проходим по политикам в auth.toml. Если хоть одна из политик разрешает запрос, открываем доступ.</p><h2>Итоговая схема</h2><p>Подытожим, как работает межсервисная авторизация.</p><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-24/ac124f45-b641-47db-aee3-00a0d147ff84.png" alt="" /><figcaption>Итоговая схема работы межсервисной авторизации</figcaption></figure><ol><li>Запрос попадает на сайдкар.</li><li>Сайдкар спрашивает у агента, можно ли пустить запрос дальше.</li><li>Агент обрабатывает rego-правила и решает, нужно ли блокировать запрос.</li><li>Если запрос блокируется, клиент получает 403. Если нет — запрос доходит до сервиса.</li></ol><h2>Проблема: latency запросов к OPA</h2><p>После реализации авторизации через запрос к сайдкару мы замерили latency. Оказалось, что envoy тратит дополнительные 10 мс для походов в OPA.</p><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-24/249f521f-ac2b-4d5b-be84-e62b74ad7284.png" alt="" /><figcaption>Latency запросов к OPA доходило до 10 мс — для части сервисов это много</figcaption></figure><p>Для нагруженных сервисов это критично — им нельзя добавлять больше 2 мс. Поэтому для них такой latency стал бы блокером для использования авторизации.</p><p>Мы выяснили, что тратили время на одинаковые запросы к OPA. Ведь для пользователя apgubarev авторизационный ответ для ручки getUser будет одним и тем же на протяжение всей жизни пода (помним — политики меняются только при новом деплое).</p><p>Решение — кешировать. Envoy позволяет писать расширения разными способами, но нам лучше всего подошел Lua. Теперь запрос один раз посылается агенту, сохраняется в памяти и больше туда не ходит, если не было изменений в auth.toml. Прибавка — не больше 1 мс.</p><h2>Валидация изменений в политиках авторизации</h2><p>Недостаточно просто включить межсервисную авторизацию, нам было важно ничего не сломать. И у нас получилось.</p><p>Представим ситуацию: у сервиса A есть ручка getUser, на которую ходит сервис B. Владелец сервиса A закрывает доступ к этой ручки через auth.toml — сервис B ломается, получаем деградацию продакшена.</p><p>Мы сделали валидатор, чтобы не допускать таких ситуаций. Вот, как мы валидируем изменения, связанные с авторизацией:</p><p>— Предотвращаем закрытие существующих связей.</p><p>— Проверяем корректность auth.toml: указанные клиенты существуют, одна ручка указана только один раз и т.д.</p><p>— Не допускаем в прод с ошибками — блочим деплой.</p><p>Ещё мы завели реестр auth.toml. У нас уже был сервис схем для Brief, с помощью которого мы проверяли, что изменения не ломают обратную совместимость ручки или не удаляют поле, которое кто-то использует.</p><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-24/9199b1c6-167d-4140-afae-6c3a572326c0.png" alt="" /><figcaption>Реестр auth.toml мы сделали по аналогии с сервисом схем — реестром brief</figcaption></figure><p>Перед деплоем сервиса мы достаём связи из реестра и тестируем rego правила: проверяем зависимости и клиентов.</p><p>Проверка зависимостей происходит следующим образом:</p><ol><li>Смотрим зависимости в brief-папке.</li><li>Берём rego зависимостей из прода.</li><li>Тестируем rego с данными текущего сервиса: передаём путь и клиента, убеждаемся, что пришёл положительный ответ.</li></ol><p>Проверка клиентов выглядит так:</p><ol><li>Смотрим зарегистрированные клиенты у сервиса.</li><li>Берём текущий rego сервиса.</li><li>Проверяем доступ у клиентов: передаём путь и клиента, убеждаемся, что доступ есть.</li></ol><p>Если билд падает, мы делаем одно из трех:</p><ol><li>Оставляем связь как есть — наткнулись на связь, которая реально нужна, разработчикам нужно договориться, что с ней делать.</li><li>Помечаем связь как deprecated — связь уже устарела, нужно поставить задачу, чтобы её выпилить.</li><li>Ничего не делаем — нашли ненужную связь.</li></ol><p>Таким образом нам удалось не допустить поломок существующих связей. До сих пор не было ни одного инцидента связанного с этим.</p><h2>Выводы</h2><p>Что у нас получилось</p><ul><li>Простое платформенное решение для межсервисной авторизации. auth.toml не требует погружения, разработчики сразу начинают писать политики.</li><li>Сервисы не затронуты. Ничего менять не нужно, достаточно добавить ещё один файлик конфигурации.</li><li>Связи не сломаны. Все валидаторы отрабатывают корректно, пока не было ни одного инцидента.</li></ul><p>Что поняли</p><p>Просто добавить авторизацию недостаточно. Как минимум нам ещё понадобилась генерация auth.toml и валидаторы для контроля изменений.</p><p>Что нам дали Open Policy Agent и rego</p><ul><li>Не надо писать и поддерживать своё решение.</li><li>Понятная и читаемая политика для платформенной команды.</li><li>Удобная работа с оргструктурой, включая все иерархические вложенности.</li><li>Возможность тестирования доступов.</li></ul><p>Полезные ссылки:</p><ul><li><a href="https://habr.com/ru/companies/avito/articles/527400/">Статья «Платформа как сервис в Авито: как это устроено» на Хабре.</a></li><li><a href="https://habr.com/ru/companies/avito/articles/674296/">Статья «Поддержка mTLS в своём Service Mesh: чему мы научилиcь» на Хабре.</a></li><li><a href="https://istio.io/">Официальный сайт Istio.</a></li><li><a href="https://github.com/spiffe/spire">GitHub-репозиторий Spire</a>.</li><li><a href="https://www.openpolicyagent.org/">Официальный сайт Open Policy Agent.</a></li><li><a href="https://www.openpolicyagent.org/docs/latest/policy-language/">Документация Rego.</a></li></ul>]]></content:encoded>
    </item>
    <item>
      <title>Сравниваем форматы сериализации на Go: скорость и удобство</title>
      <link>https://tproger.ru/articles/sravnivaem-formaty-serializacii-na-go--skorost-i-udobstvo</link>
      <comments>https://tproger.ru/articles/sravnivaem-formaty-serializacii-na-go--skorost-i-udobstvo?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Марина Орлова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/sravnivaem-formaty-serializacii-na-go--skorost-i-udobstvo</guid>
      <description><![CDATA[<p>Дмитрий Королёв, бэкенд-разработчик в Авито, разобрал на примерах, чем отличаются друг от друга форматы сериализации данных и как выбрать самый удобный.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/sravnivaem-formaty-serializacii-na-go--skorost-i-udobstvo">Сравниваем форматы сериализации на Go: скорость и удобство</a>»</p>]]></description>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Анализ данных]]></category>
      <category><![CDATA[Бэкенд]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 20 Dec 2024 14:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Привет! Меня зовут Дмитрий Королёв, я бэкенд-разработчик в Авито.</p><p>В большинстве современных приложений используется сериализация данных: для передачи данных между клиентом и сервером, для хранения сложных структур в базах данных, при передаче информации между микросервисами или отправке сообщений в очереди.</p><p>Правильный выбор формата сериализации может существенно повлиять на производительность приложения, размер передаваемых данных и читаемость кода.</p><p>В этой статье я покажу бенчмарки нескольких самых популярных форматов сериализации в языке Golang и расскажу про преимущества и недостатки каждого из них. Это поможет вам выбрать подходящий формат для вашего проекта с учетом его потребностей. Например, меньший размер сериализованных, если вы хотите сэкономить место при хранении данных или сетевые ресурсы при их передаче, время сериализации/десериализации, если для вашего приложения критична скорость и т. д.</p><h2>Какие бывают форматы сериализации</h2><p>Можно разделить существующие форматы сериализации на две большие группы — бинарные и текстовые. У каждой из них есть свои характеристики, по которым можно оценить, насколько формат подходит для ваших целей. Для начала расскажу про ключевые моменты, на которые нужно обратить внимание при выборе.</p><h2>Бинарные форматы</h2><p>Avro, Protobuf, CBOR и Msgpack относятся к бинарным форматам сериализации данных. Ключевые различия между ними:</p><ul><li>Схема данных:Avro поддерживает схемы данных, которые описывают структуру сериализованных данных. Это позволяет легко изменять схему данных и делает его подходящим для развивающихся схем данных.Protobuf также использует схемы данных и автоматически генерирует код на основе схемы. Это позволяет легко создавать и обновлять структуру данных.CBOR и Msgpack не предоставляют встроенной поддержки схем данных, поэтому данные сериализуются без дополнительной информации о структуре.</li><li>Avro поддерживает схемы данных, которые описывают структуру сериализованных данных. Это позволяет легко изменять схему данных и делает его подходящим для развивающихся схем данных.</li><li>Protobuf также использует схемы данных и автоматически генерирует код на основе схемы. Это позволяет легко создавать и обновлять структуру данных.</li><li>CBOR и Msgpack не предоставляют встроенной поддержки схем данных, поэтому данные сериализуются без дополнительной информации о структуре.</li><li>Человекочитаемость:Бинарные форматы не предназначены для чтения человеком, однако Avro и Protobuf можно сериализовать в json. Это может быть полезно в целях дебага, но мало пригодно для production среды.</li><li>Бинарные форматы не предназначены для чтения человеком, однако Avro и Protobuf можно сериализовать в json. Это может быть полезно в целях дебага, но мало пригодно для production среды.</li><li>Компактность и производительность:CBOR и Msgpack более компактны и имеют лучшую производительность при сериализации и десериализации данных, поскольку сериализованные сообщения не содержат метаданных.Avro и Protobuf также обеспечивают хорошую компактность и производительность, но процесс сериализации и десериализации может быть более сложным из-за схемы данных. Например, в случае с avro во время сериализации проводится анализ схемы, чтобы впоследствии определить каким образом обрабатывать то или иное поле.</li><li>CBOR и Msgpack более компактны и имеют лучшую производительность при сериализации и десериализации данных, поскольку сериализованные сообщения не содержат метаданных.</li><li>Avro и Protobuf также обеспечивают хорошую компактность и производительность, но процесс сериализации и десериализации может быть более сложным из-за схемы данных. Например, в случае с avro во время сериализации проводится анализ схемы, чтобы впоследствии определить каким образом обрабатывать то или иное поле.</li><li>Эволюционность:Avro и Protobuf обеспечивают поддержку обратной совместимости при изменении схем данных. Это облегчает эволюцию данных в распределенных системах.CBOR и Msgpack не предоставляют встроенной поддержки для эволюции данных и требуют дополнительных усилий при изменении структуры данных. Например, потребуется изменить поведение обрабатывающей логики при удалении полей из структуры сообщения, сериализованного в одном из этих форматов.</li><li>Avro и Protobuf обеспечивают поддержку обратной совместимости при изменении схем данных. Это облегчает эволюцию данных в распределенных системах.</li><li>CBOR и Msgpack не предоставляют встроенной поддержки для эволюции данных и требуют дополнительных усилий при изменении структуры данных. Например, потребуется изменить поведение обрабатывающей логики при удалении полей из структуры сообщения, сериализованного в одном из этих форматов.</li></ul><h2>Текстовые форматы</h2><p>JSON (JavaScript Object Notation) и XML (Extensible Markup Language) — два разных текстовых формата для сериализации и обмена данными. Вот ключевые различия между ними:</p><ul><li>Синтаксис:JSON использует более легкий и компактный синтаксис для представления данных — в виде пар «ключ:значение». Структура данных обычно более краткая и простая.XML использует размеченный синтаксис с использованием открывающих и закрывающих тегов, что делает его более развернутым и многословным.</li><li>JSON использует более легкий и компактный синтаксис для представления данных — в виде пар «ключ:значение». Структура данных обычно более краткая и простая.</li><li>XML использует размеченный синтаксис с использованием открывающих и закрывающих тегов, что делает его более развернутым и многословным.</li><li>Удобочитаемость:JSON-документы человек может легко читать и понимать благодаря простому синтаксису.XML также человекочитаем, но его сложнее интерпретировать из-за многочисленных тегов и атрибутов.</li><li>JSON-документы человек может легко читать и понимать благодаря простому синтаксису.</li><li>XML также человекочитаем, но его сложнее интерпретировать из-за многочисленных тегов и атрибутов.</li><li>Размер данных:JSON-документы обычно имеют меньший размер по сравнению с XML благодаря компактному синтаксису.XML-документы обычно более объемные и занимают больше места.</li><li>JSON-документы обычно имеют меньший размер по сравнению с XML благодаря компактному синтаксису.</li><li>XML-документы обычно более объемные и занимают больше места.</li><li>Поддержка данных:JSON поддерживает ограниченное количество данных-типов, включая строки, числа, булевы значения, массивы и объекты.XML позволяет создавать собственные структуры данных с использованием DTD или XSD и может представлять более сложные структуры.</li><li>JSON поддерживает ограниченное количество данных-типов, включая строки, числа, булевы значения, массивы и объекты.</li><li>XML позволяет создавать собственные структуры данных с использованием DTD или XSD и может представлять более сложные структуры.</li><li>Валидация:JSON обычно не имеет встроенной системы валидации, поэтому она может потребовать дополнительных инструментов.XML поддерживает валидацию данных с использованием DTD или XSD.</li><li>JSON обычно не имеет встроенной системы валидации, поэтому она может потребовать дополнительных инструментов.</li><li>XML поддерживает валидацию данных с использованием DTD или XSD.</li></ul><h2>Бенчмарки: сравниваем форматы сериализации между собой</h2><p>Для этой статьи мы выбрали самые известные форматы: Avro, Protobuf, Msgpack, XML, CBOR и несколько известных библиотек для работы с JSON</p><p>Тестирование проводилось на ПК с такими характеристиками: Apple M1 Pro 3.2 GHz 10 cores (8 performance and 2 efficiency), 32 GB LPDDR5, APPLE SSD AP0512R.</p><p>Всего проводились замеры данных трех разных объемов:</p><ul><li>1 строка</li><li>100 строк</li><li>100 000 строк</li></ul><p>Использовались только целочисленные, только строковые и смешанные (строки+числа) данные. Все поля nullable с разной степенью заполненности. Размер сериализованных данных измерялся только для 100 000 строк, поскольку на 1 или 100 строках результат мог бы получиться недостаточно репрезентативным.</p><p>Ниже на отдельных диаграммах показаны время сериализации и десериализации и объем полученных данных для каждого формата.</p><p>Исходники можно увидеть <a href="https://github.com/Jimiliani/go-serialization-benchmarks/tree/main">здесь</a>.</p><h2>1 строка</h2><p>Целые числа</p><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-19/289abc6f-34e5-4940-9f2e-e86cdcd0e8d4.png" alt="" /><figcaption>Диаграмма</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-19/b1418eda-a1b4-400a-aa0b-761dacfb7d73.png" alt="" /><figcaption>Диаграмма</figcaption></figure><p>Строковые данные</p><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-19/58cae728-56dc-4a0e-b506-5d9136fd0dc5.png" alt="" /><figcaption>Диаграмма</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-19/6612c8e2-012d-466f-8743-3b4353f79ced.png" alt="" /><figcaption>Диаграмма</figcaption></figure><p>Смешанные данные</p><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-19/b17d7dcc-cba5-4828-8e39-693b3fa74486.png" alt="" /><figcaption>Диаграмма</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-19/85f36e11-6dd6-4668-92c7-74fe20190b4c.png" alt="" /><figcaption>Диаграмма</figcaption></figure><h2>100 строк</h2><p>Целые числа</p><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-19/3b4c8048-dd47-4fcb-a8fe-455a46800150.png" alt="" /><figcaption>Диаграмма</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-19/76b84452-d28f-48d5-86e7-87a09d9437f5.png" alt="" /><figcaption>Диаграмма</figcaption></figure><p>Строковые данные</p><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-19/f95b3273-5543-4e09-9bfa-219af08947c0.png" alt="" /><figcaption>Диаграмма</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-19/89c49554-0603-405e-b35a-abb9dfd0b6cf.png" alt="" /><figcaption>Диаграмма</figcaption></figure><p>Смешанные данные</p><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-19/046f792c-a002-4f9a-a4c9-d5c477a603ca.png" alt="" /><figcaption>Диаграмма</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-19/ba278c81-a01d-419f-884a-6cafb7e81296.png" alt="" /><figcaption>Диаграмма</figcaption></figure><h2>100 000 строк</h2><p>Целые числа</p><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-19/4d4c38c2-d041-4bbb-876c-f24c3e7c1da6.png" alt="" /><figcaption>Диаграмма</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-19/49cfc662-65c0-4522-9d06-e88c28972d83.png" alt="" /><figcaption>Диаграмма</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-19/ed282660-4536-4bcf-ac90-c1525f118bd0.png" alt="" /><figcaption>Диаграмма</figcaption></figure><p>Строковые данные</p><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-19/8e56d5d9-8e40-479a-9eb6-0523e365e869.png" alt="" /><figcaption>Диаграмма</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-19/882ac883-675a-4476-9b9c-578f3288a3d6.png" alt="" /><figcaption>Диаграмма</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-19/3aa674f1-58b0-4f32-bfdf-7ed026e7b946.png" alt="" /><figcaption>Диаграмма</figcaption></figure><p>Смешанные данные</p><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-19/9aae4838-dfe5-4a6e-8bd3-f3376297cd32.png" alt="" /><figcaption>Диаграмма</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-19/e9ff18b4-ca01-45c2-92b2-7d9ac6ec706d.png" alt="" /><figcaption>Диаграмма</figcaption></figure><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-19/6261ce1b-6b89-4253-a10a-6c9d9956546c.png" alt="" /><figcaption>Диаграмма</figcaption></figure><h2>Плюсы и минусы каждого формата</h2><p>Помните, что результаты могут отличаться на вашем устройстве от тех, что я привел в статье. Если говорить о преимуществах и недостатках каждого формата, вот, что я бы выделил:</p><h2>Json</h2><p>+ в golang довольно шустро работает по сравнению с бинарными форматами сериализации, особенно это заметно на больших объемах текстовых данных;</p><p>+ человекочитаемый формат данных;</p><p>- поддержка эволюции схемы данных ложится на разработчика, поскольку для этого формата сериализации схема отсутствует;</p><p>- система типов не поддерживает из коробки decimal, datetime, enum и прочие полезные типы, имеющиеся в других форматах сериализации (например, <a href="https://protobuf.dev/programming-guides/proto3/#enum">enum в protobuf</a>);</p><p>- размер сериализованных данных значительно больше, чем в любом бинарном формате;</p><h2>XML</h2><p>+ человекочитаемый формат;</p><p>+ XSD (xml schema) позволяет парсеру не только проверить правильность синтаксиса документа, но также и его структуру, типы данных и модель содержания;</p><p>- поддержка эволюции схемы данных ложится на разработчика, поскольку для этого формата сериализации схема отсутствует;</p><p>- xml использует явные открывающие и закрывающие теги, а так же атрибуты, что добавляет дополнительные символы, в связи с этим сообщения получаются довольно многословными (исторические причины, по которым xml выглядит именно так, кратко описаны <a href="https://stackoverflow.com/a/116235">здесь</a>);</p><p>- из-за дополнительных тегов и атрибутов также увеличивается время, требуемое на сериализацию и десериализацию, и значительно вырастает размер сериализованных данных;</p><h2>Cbor</h2><p>+ быстрая (де)сериализация и маленький объем сериализованных данных в сравнении с текстовыми форматами сериализации;</p><p>- поддержка эволюции схемы данных ложится на разработчика, поскольку для этого формата сериализации схема отсутствует;</p><p>- не человекочитаемый формат;</p><h2>Msgpack</h2><p>+ быстрая (де)сериализация и маленький объем сериализованных данных в сравнении с текстовыми форматами сериализации;</p><p>- поддержка эволюции схемы данных ложится на разработчика, поскольку для этого формата сериализации схема отсутствует;</p><p>- не человекочитаемый формат;</p><h2>Avro</h2><p>+ есть поддержка как бинарного, так и в текстового форматов, что может быть полезно, например при работе в тестовой среде;</p><p>+ схема данных описывается в json-формате, за счет полей в схеме достигается backward и forward compatibility;</p><p>- avro во время сериализации проводит анализ схемы, чтобы впоследствии определить каким образом обрабатывать то или иное поле, это оказывает негативный эффект на время сериализации;</p><h2>Protobuf</h2><p>+ быстрая (де)сериализация и маленький объем сериализованных данных в сравнении с текстовыми форматами сериализации;</p><p>+ схема данных описывается в .proto файлах, на основе которых генерируются объекты в необходимом вам языке. С помощью описанных в схеме полей достигается backward и forward compatibility (с oneof есть <a href="https://yokota.blog/2021/08/26/understanding-protobuf-compatibility/">нюансы</a>);</p><p>- не человекочитаемый формат;</p><p>Выбор формата сериализации зависит от конкретных требований проекта. Например, если важна человекочитаемость данных и легкая отладка, то JSON может быть предпочтителен благодаря своей простоте и широкой поддержке во многих языках программирования.</p><p>С другой стороны, если производительность играет решающую роль и необходимо передавать большие объемы данных, то бинарные форматы, такие как Protobuf или MessagePack, могут быть более эффективными. Но важно помнить, что каждый случай — частный и выбор формата сериализации зависит от конкретных потребностей проекта, учитывая требования к производительности, размеру данных, удобству отладки и поддержке в используемых технологиях.</p><p>Предыдущая статья: <a href="https://habr.com/ru/companies/avito/articles/783534/">Повышение качества данных с использованием Zero Bug Policy</a></p>]]></content:encoded>
    </item>
    <item>
      <title>Как писать код, который не ломается: гайд по TDD от эксперта Эйч Навыки</title>
      <link>https://tproger.ru/articles/kak-pisat-kod--kotoryj-ne-lomaetsya--gajd-po-tdd-ot-eksperta-ejch-navyki</link>
      <comments>https://tproger.ru/articles/kak-pisat-kod--kotoryj-ne-lomaetsya--gajd-po-tdd-ot-eksperta-ejch-navyki?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Анна Ельцова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-pisat-kod--kotoryj-ne-lomaetsya--gajd-po-tdd-ot-eksperta-ejch-navyki</guid>
      <description><![CDATA[<p>Владислав Гайденко, эксперт Эйч Навыки и бэкенд-разработчик в Авито, рассказывает, как TDD помогает избежать ловушек нестабильного кода, сократить время на исправление багов и контролировать процесс разработки.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-pisat-kod--kotoryj-ne-lomaetsya--gajd-po-tdd-ot-eksperta-ejch-navyki">Как писать код, который не ломается: гайд по TDD от эксперта Эйч Навыки</a>»</p>]]></description>
      <category><![CDATA[Тестирование]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Бэкенд]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 16 Dec 2024 07:50:02 GMT</pubDate>
      <content:encoded><![CDATA[<p>Разработка ПО редко идет без приключений: требования меняются, ошибки всплывают в самый ненужный момент, а исправления одного бага, как смещение таблицы в Word, может сломать вообще всё. К счастью, есть подход TDD (Test-Driven Development), который минимизирует эти риски.</p><p><a href="https://h.careers/curators/vlad-gaiydenko">Влад Гайденко</a>, ментор <a href="https://h.careers/skills?utm_source=site_tproger&amp;utm_medium=article">Эйч Навыки</a> и бэкенд разработчик в Авито, где он с командой разрабатывает платформу «Гарантии запчастей» в рамках Авито Авто, расскажет, как применять TDD без стресса и писать код, который не будет ломаться.</p><h2>Что такое TDD</h2><p>TDD (Test-Driven Development) часто считается крайне сложным подходом, но на самом деле все довольно просто. Представьте, что вы строите дом: вы же сначала нарисуете план, и только потом начнете строить, верно? В TDD все работает точно так же, только с кодом: сначала мы пишем тесты, описывающие, как должен работать наш код, а потом уже пишем сам код, чтобы эти тесты проходили.</p><figure><img src="https://media.tproger.ru/user-uploads/101078/2024-12-10/c2a73c16-d1de-45d2-8271-96e9822401b9.png" alt="" /></figure><p>Другими словами, здесь полностью меняется логика разработки: обычно мы пишем код, потом тестируем и финалим баги. В TDD все идет от обратного — схема примерно такая:</p><ol><li>Определяем функциональность, которую нужно реализовать. Условно: вам нужно при запросе «300» возвращать «спартанцев».</li><li>Под эту функциональность пишем тест — в нем вы описываете, как должна работать будущая программа. Спойлер: при запуске тест провалится, потому что тестировать пока нечего.</li><li>Пишете самый простой (даже «глупый») код, после которого тест просто перестанет выдавать ошибку.</li><li>Если тесты больше не падают, поздравляем, вы великолепны. Теперь можно делать рефакторинг кода и пилить «по красоте».</li></ol><p>Да, это самый банальный пример — в реальности модулей могут быть тысячи, и под каждый из них, конечно, нужно писать тест.</p><h2>Почему TDD работает</h2><p>Давайте разберем на конкретном примере. Представьте, что мы разрабатываем функционал расчета стоимости доставки. Начав с написания тестов, мы сразу видим важные моменты:</p><ul><li>Как считать стоимость для разных типов товаров (легких, тяжелых и хрупких)</li><li>Как учитывать расстояние до адреса доставки</li><li>Как применять скидки и акции</li></ul><p>Написав тесты для этих сценариев, мы уже на старте проекта знаем, что наше решение будет учитывать все важные детали. Круто, правда?</p><h2>Что это реально дает</h2><p>Когда начинаешь работать с TDD, понимаешь, насколько это мощный инструмент. Ниже о его суперсилах.</p><h4>Надежды как швейцарские часы</h4><p>Допустим, через какое-то время нам нужно добавить новый тип доставки — курьером. Без тестов мы бы постоянно переживали: «А вдруг что-то сломалось?» С тестами же мы можем спокойно вносить изменения, зная, что если что-то пойдет не так, тесты нас предупредят.</p><h4>Актуальная документация</h4><p>Тесты становятся отличной «живой» документацией. Новый разработчик в команде? Просто покажите ему тесты, и он быстро поймет, как все работает. Это намного удобнее, чем читать многостраничные документы, которые часто устаревают.</p><h4>Экономят время на поиске багов</h4><p>Помните ситуации, когда нужно срочно исправить ошибку, а вы не знаете, где искать? С TDD все проще: написал тест, воспроизводящий проблему, исправил код, убедился, что тест проходит — и готово!</p><h3>Где TDD реально полезен</h3><p>Отлично подходит для:</p><ul><li>Бизнес-логики: все эти CRUD-операции, валидации, обработка ошибок — самое то!</li><li>Утилитных модулей: математические операции, форматирование данных, работа с коллекциями</li></ul><p>Где лучше подумать дважды:</p><ul><li>Интеграция с внешними сервисами</li><li>Работа с файлами и сетью</li><li>Настройка окружения</li></ul><h2>С чего начинать TDD</h2><p>Освоить TDD действительно несложно, но начинать нужно не с кода, а с правильной постановки задач в системе управления проектами, например, в Jira.</p><blockquote>Ключевой момент — это включение в описание задач четких критериев приемки, которые определяют, когда задача будет считаться выполненной. Эти критерии должны быть сформулированы представителями бизнеса, продакт-менеджерами или другими заинтересованными сторонами, близкими к требованиям пользователей.</blockquote><p>Например, для задачи по добавлению нового типа товара в доставку с признаком акциз:</p><ul><li>Моторные масла с типом акциз до 5 л включительно объема доступны для доставки</li><li>Тип доставки «Лошадью»</li><li>Логистическая компания «Рога и копыта»</li></ul><p>Такие четкие критерии приемки становятся основой для написания тест-кейсов, которые будут проверять, что реализованное решение действительно соответствует ожиданиям.</p><blockquote>Когда задача сформулирована с критериями приемки, разработчик вместе с QA-инженером могут начать создавать тест-кейсы прямо в Jira. Эти тест-кейсы будут отражать различные сценарии использования, которые должны быть протестированы.</blockquote><p>Например, для задачи по добавлению нового типа товара, тест-кейсы могут быть такими:</p><p>1. Проверить, что типы товара доступны для доставки в «Лошадью» в «Рога и копыта»:</p><ul><li>моторные масла</li><li>с акцизой</li><li>объем (1, 2, 5 л)</li></ul><p>2. Проверить, что типы товара недоступны для доставки «Лошадью» в «Рога и копыта»:</p><ul><li>моторные масла</li><li>без акцизы</li><li>объем (1, 2, 5 л)</li></ul><p>Эти тест-кейсы становятся основой для написания автоматизированных юнит-тестов в коде. Разработчики могут ориентироваться на них, когда пишут реализацию, и проверять, что их код действительно соответствует ожиданиям.</p><p>Очень важно, чтобы тест-кейсы, определенные в Jira, просматривались на встречах по оценки задач (PBR). Это позволяет:</p><ul><li>Убедиться, что тест-кейсы действительно отражают все важные критерии приемки задачи.</li><li>Согласовать с продакт-менеджером и другими заинтересованными сторонами, что эти тест-кейсы полностью покрывают требования.</li></ul><p>Такой подход гарантирует, что разработчики пишут код, ориентируясь на ожидания бизнеса, а не просто на свое собственное понимание задачи.</p><p>В итоге, начав с правильной постановки задач в Jira и определения тест-кейсов, разработчики получают надежный фундамент для применения TDD. Это помогает создавать качественный код, который точно соответствует требованиям пользователей.</p><h2>Как писать тесты еще лучше</h2><p>Используйте принцип «Светофора»:</p><figure><img src="https://media.tproger.ru/user-uploads/101078/2024-12-10/e2b74fd8-53fb-43e9-b485-ca082e5e6218.png" alt="" /></figure><ul><li>Красный: пишете тест, он падает</li><li>Зеленый: пишете код, тест проходит</li><li>Рефакторинг: улучшаете код, тесты все еще зеленые</li></ul><p>Делайте тесты читаемыми:</p><ul><li>Давайте понятные названия</li><li>Структурируйте код теста</li><li>Используйте вспомогательные функции для часто повторяющихся действий</li></ul><p>Вот пример плохого теста:</p><p>Здесь неясно, что конкретно проверяет тест. Название теста ничего не говорит, а использование магических чисел усложняет понимание. Это приводит к путанице, особенно если тесты придется читать или модифицировать спустя время.</p><p>А вот хороший пример:</p><p>Почему это хороший пример?</p><ul><li>Понятное название теста: TestCalculateDelivery сразу дает понять, что мы тестируем функцию расчета стоимости доставки. Т</li><li>абличный формат: использование таблицы позволяет легко добавлять новые тестовые случаи без дублирования кода.</li><li>Понятные имена переменных: каждая переменная имеет четкое назначение, что упрощает чтение и сопровождение теста.</li><li>Параметризация тестов: за счет табличного подхода мы избегаем избыточного кода, проверяя несколько сценариев в одном тесте.</li><li>Табличные тесты — это отличный способ поддерживать чистоту и масштабируемость тестов, особенно когда сценарии похожи, но параметры различаются.</li></ul><h2>Типичные сложности и как с ними справиться</h2><h4>«Это же долго!»</h4><p>Да, поначалу придется потратить больше времени. Но это как инвестиция: сейчас вложишь время, потом получишь в разы меньше багов и более быстрое внесение изменений.</p><h4>«Не знаю, с чего начать»</h4><p>Начните с простого! Возьмите небольшую задачу и попробуйте написать для нее тесты. Используйте существующие тесты как примеры. Постепенно вы найдете свой стиль и ритм.</p><h4>«У нас legacy-код»</h4><p>Начните с нового кода! Не пытайтесь сразу покрыть тестами весь старый код. Добавляйте тесты постепенно, когда прикасаетесь к старому коду для внесения изменений.</p><h2>Подготовка проекта</h2><p>Например, в Go есть отличные инструменты для тестирования. Я рекомендую:</p><ul><li>Стандартный пакет testing для базового функционала</li><li><a href="https://github.com/stretchr/testify">Testify</a> — набор полезных ассертов и мок-объектов, лично используем на проекте</li><li><a href="https://onsi.github.io/ginkgo/">Ginkgo</a> — BDD-стиль написания тестов</li><li>Встроенные инструменты для измерения покрытия кода:</li></ul><p>TDD — это не какая-то магия, а просто удобный инструмент, который помогает писать более качественный код. Начните с малого, и вы увидите, как постепенно ваш код становится надежнее, а работать над проектом — приятнее.</p><p>Удачи в практике TDD! А если у вас остались вопросы — велком в комменты.</p>]]></content:encoded>
    </item>
    <item>
      <title>Популярные ошибки в Golang и как их избежать</title>
      <link>https://tproger.ru/articles/populyarnye-owibki-v-golang-i-kak-ih-izbezhat</link>
      <comments>https://tproger.ru/articles/populyarnye-owibki-v-golang-i-kak-ih-izbezhat?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Марина Орлова]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/populyarnye-owibki-v-golang-i-kak-ih-izbezhat</guid>
      <description><![CDATA[<p>Дмитрий Королев расскажет про распространённые ошибки при работе со слайсами, каналами и другими структурами в Go. Научимся предупреждать их исправлять на примерах.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/populyarnye-owibki-v-golang-i-kak-ih-izbezhat">Популярные ошибки в Golang и как их избежать</a>»</p>]]></description>
      <category><![CDATA[Советы]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Баги и ошибки]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 10 Dec 2024 12:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Всем привет! Меня зовут Дмитрий Королёв, я бэкенд-разработчик в Авито.</p><p>Go известен своей лаконичностью и простотой синтаксиса, но даже в нём есть множество подводных камней, с которыми можно столкнуться в работе. В этой статье я сделаю разбор распространённых ошибок с примерами и расскажу, как их можно избежать.</p><h2>Массивы и слайсы</h2><p>Начнём с базовых концепций:</p><ul><li>Массив — последовательность элементов определённого типа и фиксированной длины. Это неизменяемая структура данных и его capacity всегда равна его длине.</li><li>Слайс — своеобразная надстройка поверх массива с возможностью изменения длины.</li></ul><h2>Распространённые ошибки при работе со слайсами</h2><p>Чтобы понять, как работают слайсы, нужно понимать их структуру. В коде ниже видны поля про длину и вместимость и указатель на массив, на основе которого построен слайс.</p><p>Про длину и capacity слайсов стоит помнить две вещи:</p><ol><li>Когда мы создаём новый слайс, его длина равна его capacity, если не указано другое.</li><li><a href="https://go.googlesource.com/go/+/2dda92ff6f9f07eeb110ecbf0fc2d7a0ddd27f9d">Как именно растет вместимость слайса начиная с версии go 1.20.</a></li></ol><p>Поскольку в Go все аргументы передаются в функции по значению, то при передаче слайсов в качестве аргумента передаётся значение его структуры. Иными словами, копируется только ссылка на массив, на основе которого построен слайс. Сам массив со всеми содержащимися в нём данными не копируется. Если этого не знать, можно получить неожиданный результат.</p><p>Дальше рассмотрим примеры.</p><h2>Перевыделения памяти под новый массив</h2><p>Здесь в main объявлен слайс, состоящий из одного нуля. После чего этот слайс передаётся в функцию с говорящим названием changeSliceValues. Там с ним происходят некие действия, в текущем примере в нулевой индекс записывается единица. Если в main вывести слайс на экран до и после вызова функций, то ожидаемо увидим [0] и [1] соответственно.</p><p>Теперь немного изменим пример — в changeSliceValues после записи в нулевой индекс с помощью append добавим в конец слайса 2, после чего запишем в нулевой индекс 3. И несмотря на применённые нами изменения, принты в main все так же выведут [0] и [1]. Размер слайса не изменился, несмотря на то, что мы добавили append. Вторая запись тоже не применилась.</p><p>На самом деле всё станет понятно, если вспомнить озвученные ранее факты о слайсах и структуру слайса. В самом начале мы создали слайса с длинной, которая равна его capacity, то есть единице.</p><p>В момент вызова changeSliceValues в качестве аргумента передаётся значение структуры слайса. Он указывает на тот же самый нижележащий массив, что и слайс в main. По этой причине первая запись на нулевом индексе применяется на изначальном массиве, который был создан при инициализации слайса в main.</p><p>Однако дальше, когда мы делаем append, поскольку у слайса длина равна capacity, происходит перевыделение памяти под новый массив. Туда эвакуируются все значения из старого, и дальнейшая работа с этим слайсом уже на изначальный слайс в main не оказывает никакого эффекта.</p><p>Следующая запись в нулевой индекс происходит опять же на новый массив. На изначальный массив, который был создан при объявлении слайса в main, это никак не влияет.</p><h2>Копирование слайсов</h2><p>С этой же проблемой можно столкнуться, если попытаться скопировать слайс.</p><p>В примере в переменную newSlice с помощью слайсинга копируются данные из оригинального слайса, в том числе и указатель на массив с данными. При выполнении append данные перетираются в оригинальном массиве, потому что newSlice указывает на оригинальный массив из первого слайса.</p><p>В Go есть специальная встроенная функция copy, которая позволит безопасно копировать любые слайсы.</p><p>На картинке выше видно, что, использовав copy, мы перенесли элементы из исходного слайса в новый. Теперь можно безопасно делать append, не боясь перетереть изначальные данные.</p><h2>Работа со строками и рунами</h2><p>Допустим мы хотим парсить какой-то новостной портал и для каждой новости класть в кэш первые сто символов, чтобы показывать пользователю превью.</p><p>В бесконечном цикле мы получаем новые новости, после берём первые сто рун и отдаём в некую функцию storeArticlePreview, которая заботится о том, чтобы сохранить руны в кэш.</p><p>Однако, проблема в том, что когда сервис запустится, он будет съедать намного больше оперативной памяти, чем планировалось, потому что в нём есть утечка. Операция получения первых ста рун от новости создаёт срез длиной в сто элементов, но его capacity остаётся такой же, как у изначального слайса. В итоге весь массив с текстом новости остаётся лежать в памяти, даже если в итоге мы имеем доступ только к первым ста элементам.</p><p>Кстати, почему в этом примере мы скастили строку к массиву рун, прежде чем брать от неё первые 100 символов? Покажу на примере, чем отличаются руны от байтов.</p><p>Берём стандартную строку Hello World и делаем отдельную переменную с рунами. По задумке хотим запринтить первые пять символов, то есть слово Hello.</p><p>Если посмотреть на вывод, то не в нем не будет ничего необычного. Сначала принтятся сами руны, потом, когда мы конвертируем это в строку, выводится слово Hello. Когда берём первые пять элементов от строки, снова выводится Hello.</p><p>Кажется, что разницы между рунами и байтами нет. Но вот, что будет, если поздороваться на китайском языке.</p><p>По задумке должны были вывестись первые 2 иероглифа, но обычный слайсинг строки не работает — вместо иероглифов выводится некорректный символ.</p><p>Помним, что строки в Go состоят из UTF-8 символов, каждый из которых может быть представлен более чем одним байтом. Если взять слайс по строке, то работать мы будем с байтами, а не с её символами. Поэтому когда мы пытаемся взять первые два символа от строки, мы берём первые два байта.</p><p>Большинство операций со строками работает с их байтами, но есть и исключения.. Слайсинг строки отдаёт байты, метод len также покажет длину в байтах. Цикл for range в качестве индекса берёт индекс байта, с которого начинается символ, но в значении будет лежать не байт, а руна, которая начинается в этом индексе.</p><p>Часто можно просто кастить строчку к слайсу рун и работать уже с ним. Но не стоит забывать про оверхэд, который мы можем получить в этом случае. На каждую строчку будут существовать две переменные: одна из них хранит исходную строку, а вторая — массив рун. Если строк много и они длинные, это также может иметь значение. К счастью, в Go есть процессорные оптимизации, которые в определенных ситуациях позволяют его избежать.</p><h2>Каналы</h2><p>Каналы — это примитив синхронизации, который даёт возможность одной горутине отправлять данные в другую и обеспечивает безопасный доступ к общим данным.</p><p>При работе с каналами возникают два вопроса: кто должен их закрывать и нужно ли вообще это делать. Важно знать, что может случиться при работе с каналом в разных его состояниях.</p><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-10/bd89d6c2-9dde-47bc-83ec-6c498890ee17.png" alt="" /></figure><p>На этой таблице, описано, что мы получим при совершении разных операций. Например, с каналом в закрытом состоянии, чтение из него не вызовет проблем — мы просто получим дефолтное значение и false, что сигнализирует о том, что прочитать из канала не удалось. Однако, запись в закрытый канал и закрытие уже закрытого канала вызовет панику. Вывод: закрывать канал должна та горутина, что в него пишет.</p><p>Теперь попробуем ответить на вопрос: «зачем закрывать канал?». Для этого обратимся к документации: «отправитель может закрыть канал, чтобы указать, что значения больше не будут отправляться». Если отправитель закрывает канал, значит это может понадобится кому-то, кроме него — например, читателю канала. Рассмотрим пример, когда это может быть полезно:</p><p>Здесь есть говорящая функция writeToChan, в которой происходит запись в канал и в main цикл по этому каналу — в нём мы высчитываем значения. Если не закрыть канал, цикл никогда не закончится и случится deadlock. Если закрыть — for range успешно завершается и логика программы идёт дальше.</p><p>Закрывать канал стоит только в тех ситуациях, когда читатель никак не должен реагировать. Ничего страшного, если канал не закрыт. Сборщик мусора сможет от него избавиться даже в таком состоянии.</p><h2>time.After</h2><p>Раз уж обсудили каналы, поговорим о структурах, которые используют каналы. Одна из них — time.After. Это функция возвращает канал, который закроется после заданной задержки времени. Она обычно используется для создания таймеров или установки таймаутов на выполнение определенной логики в программах.</p><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-10/c1da2a32-8fe2-4093-a405-82df24d6ab09.png" alt="" /></figure><p>Вот пример, где мы обрабатываем какие-то события, которые поступают из некой очереди. Если за 15 минут мы не встретили ни одного события в канале, то кинем warning, что что-то случилось.</p><p>Если запустить код, он будет рабочим. Но если вдруг есть какой-то дашборд, в котором мы измеряем потребление памяти и событий большое число, то мы легко обнаружим, что есть утечка памяти. При среднем потоке в миллион сообщений в 15 минут утечка составит порядка 200 Мб. Один канал Go весит около 200 байт. Получается, что на каждое событие убегает новый канал.</p><p>Почему это происходит, если сборщик мусора сможет удалить и не закрытый канал, а канал, созданный time.after, выходит из зоны видимости после каждого нового события?</p><p>Обращаемся к документации: «таймер не будет собран сборщиками мусора до тех пор, пока он не отработает». То есть time.after, который мы ставили на 15 минут, на это время остаётся висеть мертвым грузом, даже если он уже не находится в области видимости.</p><h2>Горутины</h2><p>Горутина — это лёгкий поток выполнения в userspace, пока потоки операционной системы живут в kernel space. Горутины управляются средствами Go, а потоки — средствами операционной системы.</p><p>Горутины спроектированы так, чтобы быть более эффективными, чем традиционные потоки операционной системы. Но у них тоже есть несколько ловушек, в которые можно попасть при работе.</p><p>В примере ниже мы создаём слайс из цифр от 1 до 5 и горутины в цикле, и в каждой из них прибавляем своё число из слайса к переменной sum. Можно подумать, что в выводе будет число 15, то есть сумма чисел от 1 до 5 — однако это не так.</p><p>Здесь проблема состоит в замыканиях — функциях, которые захватывают переменные из внешней области видимости. В примере анонимная функция, которая создаётся в цикле, является замыканием, потому что она захватывает переменную value из внешней области видимости.</p><p>Особенность их работы в том, как используется захваченная переменная. Горутины не захватывают значения переменных на момент их создания — они захватывают ссылку на переменную. Поэтому, когда горутины начинают выполняться, цикл зачастую уже прошёл, и переменная value имеет последнее значение из слайса. По нему мы итерируемся, хотя гарантии того, что цикл завершится раньше, чем начнёт работу одна из горутин — нет. Это приводит к тому, что в переменной sum оказывается не значение 15.</p><p>Это настолько распространённая проблема, что мейнтейнеры Go решили изменить семантику переменных цикла for, чтобы предотвратить их непреднамеренное использование в замыканиях и горутинах на каждой итерации. В версии 1.21 появился соответствующий эксперимент, а с версии 1.22 эта проблема уже полностью перестала воспроизводиться. Но, поскольку версия 1.22 свеженькая, и ещё не все успели обновиться, берите себе на заметку эту особенность работы замыканий.</p><h2>Пакеты sync и atomic</h2><p>В примерах выше мы использовали sync WaitGroup, чтобы дождаться выполнения горутин и, кстати, сделали это неправильно. Признавайтесь, кто не заметил?) Стоит обратить внимание на то, где мы делаем wg.Add, и подумать, чем это черевато.</p><p>Давайте разбираться. Посмотрим на устройство wait group:</p><p>В структуре WaitGroup из интересного мы видим семафор и некий noCopy. Сначала поговорим про семафор, а точнее про то, что по сути WaitGroup — это простенькая обёртка над семафором с тремя методами:</p><ol><li>.Add(delta int) увеличивает значение семафора на переданное значение.</li><li>.Done() уменьшает значение семафора на единицу.</li><li>.Wait() блокирует выполнение до тех пор пока значение семафора не станет равно 0.</li></ol><p>Так вот, проблема — в запущенных нами горутинах заключается в том, что нет гарантии, что они запустятся до того, как будет вызван .Wait. Это значит, .Wait может завершиться до выполнения .Add. Поскольку гарантии порядка запуска горутин нет, в итоге мы рискуем неверно решить, что все горутины завершили работу, хотя некоторые её ещё даже не начали.</p><p>Теперь вернёмся к структуре WaitGroup и присмотримся к полю noCopy, с таким же типом noCopy — что же это такое? По названию можно догадаться, что это что-то, что нельзя копировать, подобное поле есть в большинстве структур пакета sync. Давайте посмотрим, что же произойдёт, если всё же скопировать структуру с этим полем. Для примера будем использовать мьютекс, в нем также есть поле noCopy с типом noCopy.</p><p>В этой программе у нас есть структура Counter, которая хранит в себе мапу, а также мьютекс, который должен по задумке защищать мапу от параллельной записи. В мьютексе так же, как в waitGroup, присутствует noCopy.</p><p>На структуре Counter определены два метода: один увеличивает значение определенного ключа на единицу, другой — сразу на переданное значение. Есть мейн, в котором мы инициализируем структуру счётчика и запускаем две горутины для увеличения значения одного и того же ключа, делаем слип, чтобы дождаться выполнения горутин, и принтим значения, которые окажутся в мапе нашего счётчика. Но вот принт, к сожалению, мы так и не увидим, потому что упадём с паникой.</p><p>Проблема с кодом в том, что всякий раз, когда вызывается increment, в него копируется наш Counter c, поскольку increment определён на типа Counter, а не на *Counter. Другими словами, это value receiver, а не pointer receiver. Следовательно, increment не может изменять оригинальную переменную типа Counter, которую мы создали в main. Поэтому при каждом вызове increment происходило копирование счётчика со всем его содержимым, в том числе и мьютексом.</p><p>А теперь вспомним, что мьютекс — это просто обёртка над семафором, и, когда мы его копируем, мы копируем и семафор. При этом копия и оригинал могут жить своими отдельными жизнями, и ничто не помешает им конкурировать за операции с одним и тем же блоком памяти. Поэтому копирование мьютекса неправильно.</p><p>Так вот, за счет того самого noCopy есть возможность пометить любую структуру как невозможную к копированию (многие структуры из пакета sync так и отмечены). Тогда с помощью команды go vet можно будет обнаружить места, в которых отмеченная структура копируется, и найти потенциальную проблему в коде своего приложения.</p><h2>Atomic</h2><p>Теперь перейдем к ещё одному распространённому примитиву синхронизации — атомикам. Они предоставляют возможность безопасного доступа к общей памяти для операций чтения, записи и модификации переменных. Кроме того, в общем случае операции с атомиками быстрее, чем операции с мьютексом, за счёт использования специального набора процессорных инструкций. Однако, с этим преимуществом приходит и недостаток, про который периодически забывают: операции с атомиками атомарны по отдельности, но не атомарны все вместе.</p><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-10/7684743d-1132-47c2-a238-6cefd3107699.png" alt="" /></figure><p>В этой программе запускается горутина, которая постоянно в бесконечном цикле увеличивает на единицу значение переменной num. В то же время, в main находится бесконечный цикл, который проверяет, чётное ли число, и если это условие выполняется — выводит его на экран. Однако мы видим, что при запуске вывелось число 287, а оно, как ни странно, нечётное. Это происходит из-за того, что после прохождения num проверки на чётность его значение никак не защищено от изменений, и горутина, инкрементирующая num, успевает изменить его значение до того, как число выводится на экран.</p><h2>defer</h2><p>defer позволяет отложить выполнение блока кода до окончания функции, в которой он был вызван. Обычно он используется для обеспечения освобождения ресурсов, например, закрытия файла или разблокировки мьютекса, независимо от того, как функция завершает работу — из-за обычного возврата, паники или ошибки.</p><p>Здесь мы видим структуру профиля и несколько возможных типов для него, а также метод GetBalance(), в котором, в зависимости от типа профиля, выбирается тот или иной метод подсчета баланса. Допустим, теперь мы хотим добавить лог с итоговым балансом, полученным при подсчёте:</p><p>И в результате добавленного нами лога мы всегда будем видеть запись «profile balance: 0». Почему так?</p><p>Давайте внимательнее посмотрим на то, что написано про defer в документации языка: «The arguments to the deferred function (which include the receiver if the function is a method) are evaluated when the defer executes, not when the call executes». Значение аргументов для функции в defer (в том числе и ресивер метода) вычисляются в момент исполнения defer, а не в момент исполнения функции. В нашем примере на момент исполнения defer в переменной balance у нас по дефолту лежит 0 — вот с этим значением наш принт и выполняется. А для того, чтобы достичь результата, который мы и хотели получить, то есть для того, чтобы в принте фигурировала итоговая сумма расчета, можно использовать концепцию, с которой мы уже встречались — замыкания.</p><p>Анонимная функция не имеет никаких аргументов, переменная balance расположена в теле этой функции. Соответственно, будет сохранена ссылка на эту переменную, и фактическое значение будет получено при выполнении анонимной функции по сохранённой ссылке.</p><h2>Интерфейсы</h2><p>Интерфейсы в Go обеспечивают гибкость кода, позволяя писать универсальные функции, которые могут работать с разными типами данных, реализующими один и тот же интерфейс. Однако и с ними не все гладко. Посмотрим на такой пример кода:</p><p>У нас есть интерфейс реквестера, который делает какой-то запрос и в респонсе отдает int — допустим, статус-код нашего запроса. Есть конкретный тип concrete requester, который реализует интерфейс реквестера. Ещё для интерфейса реквестера есть функция, которая позволяет его инициализировать в зависимости от переданного значения value.</p><p>Если оно больше нуля, то мы возвращаем instance concret requester’а. Если оно меньше или равно нулю — просто возвращаем не проинициализированную переменную. В main есть логика, которая сначала принтит реквестер, а затем делает ещё один принт в зависимости от того, nil он или нет.</p><p>Если запустить программу, то мы увидим забавный вывод:</p><p>Мы получили реквестер nil, но при этом он не nil.</p><p>Чтобы разобраться, нам нужно внимательнее присмотреться к интерфейсам – а точнее к тому, как они устроены под капотом.</p><p>Под капотом есть две структуры для интерфейсов: eface для пустого и iface, если определён набор методов, которым должен соответствовать тип. Сейчас нас интересуют общие для них поля — а именно тип данных, которые реализует интерфейс, и ссылка на область в памяти, где находится его значение. Для того, чтобы две переменные интерфейс-типа были равны, нужно чтобы у них были равны оба этих поля.</p><p>Теперь посмотрим</p><p>что именно лежит в этих полях для нашей переменной requester:</p><p>Ага! Вот отсюда ноги и растут. Несмотря на то, что фактическое значение у переменной — это nil, тип таковым не является, что и приводит к тому, что сравнение requester == nil — это false.</p><p>Это поведение связано с так называемым value boxing и заслуживает отдельной статьи, которая уже в общем-то и так любезно написана <a href="https://go101.org/article/interface.html#boxing">здесь</a>.</p><h2>Особенности вендоринга</h2><p>Представим, что вы завели библиотеку на Go, в которой должны происходить какие-то сетевые запросы. Внутри этой библиотеки вы реализовали некий клиент, который умеет делать запросы, получать в респонсе какие-то данные и отдавать их в виде структур, описанных в папке models.</p><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-10/24bb998f-481b-4a39-aeca-1b2b4879b4d3.png" alt="" /></figure><p>Теперь попробуем использовать эту библиотеку в каком-нибудь сервисе. Добавили её в go.mod, прописали в консоли go mod tidy, go mod vendor, решили заглянуть в vendor, а там, неожиданно лежит только часть файлов и папок вашей библиотеки.</p><figure><img src="https://media.tproger.ru/user-uploads/109956/2024-12-10/5ea7d697-c283-4913-b317-79a4fc67dc75.png" alt="" /></figure><p>Для тех, кто не изучал, как работает вендоринг, это будет казаться чем-то странным. Что ж, за ответами отправляемся в документацию языка:</p><p>“The <a href="https://go.dev/ref/mod#go-mod-vendor">go mod vendor</a> command constructs a directory named vendor in the <a href="https://go.dev/ref/mod#glos-main-module">main module”s</a> root directory containing copies of all packages needed to build and test packages in the main module.”</p><p>И вновь всё встает на свои места: в вендоре оказываются только те пакеты, которые нужны для успешного билда и тестирования приложения. То есть, если мы инициализируем клиент из библиотеки где-то в сервисе, в котором мы эту библиотеку подключили, у нас подтянутся требуемые для этого пакеты.</p><p>Сама по себе эта ситуация может показаться просто неожиданной особенностью языка. На самом деле, это тонкий намек на то, что возможно заносить имплементацию логики похода во внешний сервис внутрь библиотеки — это не лучшая мысль. Ведь таким образом мы увеличиваем связность логики, а также уменьшаем возможности сервисов-потребителей в плане кастомизации взаимодействия библиотеки с внешними сервисами.</p><p>На этом все! Напишите в комментариях, есть ли ещё какие-то ошибки, о которых не рассказал в статье? Обсудим их в следующий раз!</p>]]></content:encoded>
    </item>
    <item>
      <title>Реализуем задачи на Go (и не только): самая подробная шпаргалка</title>
      <link>https://tproger.ru/articles/realizuem-zadachi-na-go--i-ne-tolko---samaya-podrobnaya-wpargalka</link>
      <comments>https://tproger.ru/articles/realizuem-zadachi-na-go--i-ne-tolko---samaya-podrobnaya-wpargalka?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Danil Dinko]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/realizuem-zadachi-na-go--i-ne-tolko---samaya-podrobnaya-wpargalka</guid>
      <description><![CDATA[<p>Даниил Динько, тимлид в компании-лидере в международном кибербезе и эксперт Эйч Навыки, рассказывает, как разработчикам эффективно планировать, анализировать и оптимизировать свои проекты.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/realizuem-zadachi-na-go--i-ne-tolko---samaya-podrobnaya-wpargalka">Реализуем задачи на Go (и не только): самая подробная шпаргалка</a>»</p>]]></description>
      <category><![CDATA[Оптимизация]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Управление проектами]]></category>
      <category><![CDATA[Разработка]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 25 Nov 2024 10:02:18 GMT</pubDate>
      <content:encoded><![CDATA[<p>В прошлом году Go попал в десятку самых популярных языков программирования, а в этом — уверенно <a href="https://www.tiobe.com/tiobe-index/">занимает</a> 7 место. Им пользуются более трех миллионов разработчиков по всему миру, и это количество будет только расти. И если в 2018 году найти работу Go-девелоперу было не так уж и просто, то сейчас количество вакансий сильно растет. Несмотря на то что у Go простой синтаксис и высокая надежность, даже опытные разработчики могут столкнуться с проблемами, когда оценивают реализацию задач.</p><p>Я — <a href="https://h.careers/curators/daniil-dinko?utm_source=tg_bot&amp;utm_medium=rassilka&amp;utm_campaign=161024">Даниил Динько</a>, веду свой личный <a href="https://t.me/thestrikemch">телеграм-канал</a>, где рассказываю о себе, об IT и о Golang, а также являюсь экспертом и спикером в компании <a href="https://h.careers/skills?utm_source=site_tproger&amp;utm_medium=article">Эйч Навыки</a>, TeamLeadом в компании-лидере в международном кибербезе, ex. старшим разработчиком в Ozon Tech. Разбираемся, как четко оценивать задачи, как использовать инструменты для повышения точности планирования и на что обращать внимание в коде и архитектуре, чтобы не допустить скрытых ошибок.</p><h2>Как подходить к оценке задач на Go (и не только)</h2><h3>1. Понимание бизнес-цели</h3><p>Первая задача — разобраться в бизнес-ценности задачи. Это критически важно. Если я понимаю, как задача влияет на бизнес и какие цели она преследует, то дальше процесс становится логичнее.</p><h3>2. Оценка масштаба и сложности</h3><p>Я анализирую, насколько сложна задача и насколько она совпадает с моей зоной ответственности:</p><ul><li><b>Если задача близка моему профилю,</b> я быстро схватываю суть.</li></ul><ul><li><b>Если в команде есть специалист</b>, который лучше разбирается в этой теме (например, коллега Вася), есть два пути: первый — передать ему задачу с вводными, второй — консультироваться, если Вася занят.</li></ul><p>У нас в команде, как и в Озоне, часто бывает, что такой «Вася» один на 10 человек. И если он ещё и не слишком общительный, то тут не остаётся ничего, кроме как искать альтернативы: спрашивать на созвонах, разбираться в коде, погружаться в дебаг и изучать продукт самостоятельно. Это дольше, но работает, а Вася потом на ревью укажет на потенциальные минусы.</p><h3>3. Классификация задачи</h3><p>После бизнес-анализа и погружения в зону ответственности важно понять, насколько масштабна задача:</p><ul><li><b>Мелкие задачи:</b> фиксы багов или незначительные фичи, которые редко трогают пользователи, не требуют глубокого обсуждения.</li><li><b>Крупные задачи: </b>если задача касается хайлоад-флоу или имеет высокий бизнес-вэлью, стоит провести груминг с командой, чтобы избежать багов и дебагов на проде.</li></ul><p>Производительность и масштабируемость — еще одни важные аспекты, но с ними на старте всё не так просто.</p><p>На практике даже в бигтехе редко можно на старте увидеть крутые производительные и масштабируемые решения. Поэтому обычно делается так: разработка идет к бизнесу, чтобы узнать нефункциональные требования.</p><h3>4. Нефункциональные требования</h3><ul><li>RPS (Requests Per Second) — сколько запросов в секунду выдерживает система?</li><li>Latency — какая допустимая задержка?</li><li>Uptime — уровень доступности в процентах (например, 99.9%).</li></ul><p>Часто бизнес не понимает технические термины, поэтому уточняю показатели через DAU (ежедневные активные пользователи), MAU (ежемесячные активные пользователи) и специфику продукта.</p><p>На основе этих данных принимается решение:</p><ul><li>Сделать MVP и быстро запустить, чтобы протестировать гипотезу.</li><li>Проработать масштабируемое решение, если проект требует высокой стабильности.</li></ul><p>В 98% случаев мы выбираем MVP. Это нормально. Глубокое продумывание архитектуры — редкость на старте, если только проект не требует стабильности с первых дней.</p><p>О масштабируемости, отказоустойчивости и производительности, конечно, идут размышления, но в основном в свободное от работы время. Я не считаю это неправильным, потому что в первую очередь мы  трудимся во благо бизнеса.</p><h2>Какие библиотеки и инструменты использовать</h2><p>Для задач с хайлоадом выбор технологий и подходов критически важен. На рынке много готовых решений, но в реальных проектах, особенно в таких компаниях, как Ozon, часто создаются кастомные библиотеки и прослойки для решения конкретных задач. Причина проста: стандартные инструменты не всегда выдерживают требуемые нагрузки.</p><h2>Популярные инструменты для хайлоад-систем:</h2><p>Базы данных:</p><ul><li><b>PostgreSQL</b> — классика для реляционных данных</li><li><b>Redis/Memcached</b> — быстрые key-value хранилищ</li><li><b>ClickHouse</b> — аналитическая база для больших объёмов данных</li><li><b>ScyllaDB, CockroachDB</b> — новые решения, которые набирают популярность благодаря своей производительности и масштабируемости.</li></ul><p><b>Микросервисные архитектуры: </b></p><p>Используется <b>Transactional Outbox</b> — паттерн, позволяющий сохранять атомарность между базой данных и очередью сообщений.</p><p>Выбор инструмента всегда зависит от специфики задачи. Если речь идёт о BigData или финтехе, то ключевые критерии выглядят так:</p><ul><li>Отказоустойчивость: чтобы система не падала.</li><li>Атомарность: операции либо выполняются полностью, либо откатываются.</li><li>Консистентность: все узлы системы видят одно и то же состояние данных, без рассинхрона.</li></ul><p>Чтобы сделать атомарность и консистентность, используют две таблицы в PostgreSQL: <b>основная таблица с данными </b>и<b> outbox</b> для задач, которые нужно передать в следующий этап.</p><p>Как это работает:</p><ul><li>В таблице outbox собираются записи для отправки в топик.</li><li>Воркер обрабатывает данные из таблицы и передаёт их в топик.</li><li>Это гарантирует, что состояние базы и очереди сообщений синхронизированы.</li></ul><h3>Монолит против микросервисов:</h3><p>Конечно, в распределённых системах могут возникать специфические проблемы, но это уже частные случаи, требующие индивидуального подхода.</p><ul><li><b>Если система монолитная: </b>достаточно транзакций в реляционных базах данных, что упрощает работу.</li></ul><ul><li>Если BigData: переход на микросервисы становится необходимым, но вызывает сложности с консистентностью и отказоустойчивостью.</li></ul><p>Распределённые системы требуют дополнительного внимания к проблемам, которые могут возникнуть из-за сетевых задержек, расхождений данных и отказов узлов.</p><h2>О производительности и оптимизации</h2><p>Первое, на что нужно обращать внимание при оптимизации  — узкие места. Здесь важно понять, действительно ли проблема связана с вашей частью системы или можно спокойно отложить клавиатуру и пойти пить кофе.</p><p>Если у вас микросервисная архитектура, начните с анализа трейсов:</p><ul><li>Смотрите, сколько времени занимает обработка запроса конкретным микросервисом.</li><li>Определите, какой из них обрабатывает запрос дольше всего, и начинайте копать в этом направлении.</li></ul><p>У вас нет трейсов в большой микросервисной архитектуре? Тут могу выразить только одно — мои искренние соболезнования, поскольку в вашем случае предстоит знатно пострадать, чтобы определить, в чём проблема.</p><p>Когда нашли корень проблемы (конкретный микросервис), воспроизведите флоу и пройдитесь дебагером по коду, чтобы разобраться, что происходит. После этого переходим к следующему этапу — профилированию кода.</p><p>Материалов по профилированию на Go — миллион. Если вкратце:</p><ul><li>Используйте встроенные инструменты профилирования Go (pprof, trace).</li><li>Обратите внимание на сборщик мусора (GC) — он может отнимать слишком много времени.</li><li>Проверьте наличие утечек горутин.</li></ul><p>Что касается трендовых инструментов, Redis Streams обретает все большую популярность. Redis Streams — это основа для построения своего быстрого in-memory брокера сообщений с кастомными алгоритмами ретраев, крутой интеграцией с key/value Redis, а это возможность сделать пуш в стрим и изменение значения по ключу атомарными. Если говорить более глобально, сейчас постоянно растет количество решений в DevOps, облаках, MlOps. Да и Go постепенно набирает обороты — каждая новая версия языка обычно приносит улучшения в производительности компилятора и стандартной библиотеки.</p><h2>Какие есть риски при оценки задач</h2><p>На мой взгляд, риски — глобальная история, которая не завязана на одном языке, поэтому самый распространенный риск, который уже стал классикой, — это не уложиться в дедлайны.</p><p>Часто оценки разработчиков позитивные, причём чем меньше грейд, тем позитивнее сроки. К примеру, из сеньоров в моей команде приходится выдавливать сроки, просто так они не скажут. Если удалось получить сроки, то они будут на всякий случай умножены в 2.5-3 раза — и это отчасти правильно.</p><p>Почему так происходит? Ответ — подводные камни. Предугадать их заранее сложно, даже теоретически. Это объясняет, почему сеньоры завышают сроки, а мидлы, напротив, обещают сделать всё «завтра», а потом либо перерабатывают, либо просят перенести сроки.</p><h4>Как минимизировать риски</h4><p><b>1. Будьте реалистом, а не оптимистом:</b> излишний оптимизм часто приводит к несоблюдению сроков или сбоям на проде. Пессимизм помогает предусмотреть возможные проблемы и снижает вероятность критических ошибок.</p><p><b>2. Тестируйте новые технологии: </b>не доверяйте только хорошим отзывам — ваш кейс может оказаться нестандартным. Всегда проводите локальные тесты перед внедрением.</p><p><b>3. Проводите нагрузочные тесты:</b> без них невозможно предсказать, как система поведёт себя под реальной нагрузкой. Это особенно важно для фич, которые затрагивают основные пользовательские потоки.</p><p><b>4. Будьте готовы к изменениям: </b>изменения бизнес-требований — частое явление. Знания команды о продукте могут не совпадать с реальной спецификой.</p><p>Если фича новая и затрагивает ключевые процессы, проведите груминг с командой, чтобы собрать мнения и минимизировать ошибки.</p><p><b>5. Грамотно ставьте задачи в таск-трекере: </b>для опытных разработчиков: достаточно описать, чего хочет бизнес. Для новичков или незнакомых областей: добавьте пошаговую инструкцию.</p><p><b>6. Что важно описать для багов:</b></p><ol><li>Проблему и путь её воспроизведения.</li><li>Текущее поведение системы.</li><li>Ожидаемое поведение.</li><li>Идеи для решения (если они есть).</li></ol><h2>Как выстраивать командную работу</h2><p>Из интересных моментов, которые я взял из разных команд и интегрировал в свою — груминги, кураторство через звонки. Груминги — это про сохранение вовлечённости в продукт каждого члена команды. Если разработчики будут решать задачи сами по себе, без обсуждений, команда легко окажется рассинхронизированной. В итоге каждый станет экспертом только в своей зоне ответственности, а в других частях проекта разбираться не будет, но это не всегда хорошо.</p><p>А что если один из разработчиков уйдёт, сколько нам времени понадобится, чтобы обрести экспертизу в его зоне ответственности? Кажется, это сильно замедляет процесс.</p><p>Чтобы избежать такого, важно:</p><ul><li>Давать каждому возможность работать в своей зоне ответственности. Это прокачивает навыки и уверенность.</li><li>Периодически поручать задачи вне их основной зоны, чтобы снизить бас-фактор (критическая зависимость от конкретного человека).</li></ul><p>Это помогает и в случае перегрузки: если один разработчик зашивается с задачами, а другие — отдыхают, можно обратиться к тем, кто уже выполнял задачи в этой части системы.</p><h3>Об изменениях в управлении Go-проектами</h3><p>Да, изменений много. Go растёт и хайпует невероятными темпами. Go идеально подходит для бэкенда. Он прост, эффективен для многоядерных процессоров благодаря встроенному планировщику, поддерживает высоконагруженные сценарии и хорошо сочетается с микросервисной архитектурой.</p><p>Что изменилось в последние пару лет:</p><ol><li>Проектов на Go становится всё больше. Это касается и хайлоад-компаний, и стартапов.</li><li>Растёт популярность языка среди разработчиков. Конкуренция за рабочие места увеличивается, зарплаты немного снижаются, хотя они всё ещё остаются одними из самых высоких на рынке бэкенда.</li><li>Сложность найма. Найти хорошего мидла стало чуть проще, но с сеньорами всё по-прежнему сложно.</li></ol><p>Если ты сеньор, то, несмотря на то, что у тебя вакансия абсолютно везде скрыта, тебе всё равно будут стабильно писать раз в неделю, находя твои контакты через слитые базы.</p><h3>Советы тимлидам, которые начинают с Go</h3><ol><li>Примите, что найм будет сложным. Если вы не в бигтехе, без хорошего нетворка тяжело быстро нанять нужных специалистов.</li><li>Балансируйте задачи и созвоны. У разработчиков должно оставаться достаточно времени на фокусную работу. В среднем, это 4 часа в день. Старайтесь не перегружать команду митингами.</li><li>Снижайте бас-фактор. Следите, чтобы каждый разработчик периодически выполнял задачи вне своей основной зоны ответственности.</li><li>Не будьте диктатором. Обсуждайте задачи на грумингах, вовлекайте команду в процесс принятия решений. Это повышает их вовлечённость и улучшает качество решений.</li><li>Давайте ответственность, а не только задачи. Если пытаться тащить всё на себе, можно выгореть.</li><li>Заставляйте тестировать код локально. Даже если это сложно, практика локального тестирования сильно снижает вероятность багов.</li><li>Используйте бюджеты на обучение. Развивайте хардовые навыки команды, чтобы повысить их эффективность.</li></ol><h2>Для новичков в Go</h2><p>Если возникают трудности, самое очевидное решение — спрашивать у коллег. Но что делать, если боишься надоесть вопросами?</p><ol><li>Найди ментора. Это платный, но удобный вариант для вопросов, не связанных с продуктом.</li><li>Если вопрос связан с продуктом, обращайся к разработчику, который в нем разбирается.</li><li>Если он отвечает «ну посмотри в код», используй дебаггер и локальные тесты, чтобы собрать информацию.</li></ol><p>Дебаггер — это must-have. Если его нет, тестируй на тестовом или staging-окружении. Если нет и их — проблема не в тебе, а в процессе CI/CD.</p><p>Стоит пойти и мягко намекнуть или спросить, а вот как тестировать? Потому что в таком кейсе только на проде тестить, но это совсем ненормально.</p><h2>Что еще поможет?</h2><ul><li>Читай статьи и смотри доклады вечером. Это ускоряет рост.</li><li>Изучай дебаггер и локальные тесты — это твои главные инструменты.</li><li>Участвуй в технических конференциях, чтобы лучше понимать хайлоад и новые подходы.</li></ul><h2>Несколько полезных ресурсов</h2><p>YouTube-каналы:</p><p><a href="https://www.youtube.com/@HighLoadChannel">HighLoad Channel</a></p><p><a href="https://www.youtube.com/@GolangChannel">Golang Channel</a></p><p>Курсы и ресурсы — жестко актуальная тема, главное не слететь с дороги. А еще в своем <a href="https://t.me/thestrikemch">телеграм-канале</a> я недавно сделал ультимативные бесплатные минимальные роадмапы по Go для разных грейдов — для начинающих, для джунов, для свитчеров с других языков, для мидлов и многих других.</p><p>Go — это невероятно мощный инструмент, который подходит как для стартапов, так и для хайлоад-проектов. Но успех зависит не только от технологий, а от команды и выстроенных процессов. Делайте упор на вовлеченность, снижайте бас-фактор, прокачивайте людей и внедряйте культуру обмена знаниями.</p>]]></content:encoded>
    </item>
    <item>
      <title>ТОП-25 курсов Golang-разработчиков: бесплатное и платное онлайн-обучение программированию на языке GO</title>
      <link>https://tproger.ru/articles/top-25-kursov-golang-razrabotchikov--besplatnoe-i-platnoe-onlajn-obuchenie-programmirovaniyu-na-yazyke-go</link>
      <comments>https://tproger.ru/articles/top-25-kursov-golang-razrabotchikov--besplatnoe-i-platnoe-onlajn-obuchenie-programmirovaniyu-na-yazyke-go?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Анастасия Шишкина]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/top-25-kursov-golang-razrabotchikov--besplatnoe-i-platnoe-onlajn-obuchenie-programmirovaniyu-na-yazyke-go</guid>
      <description><![CDATA[<p>Лучшие онлайн-курсы для Golang-разработчиков. Список школ, осуществляющих обучение на бесплатной или платной основе, а так же цены на курсы программистов на языке GO</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/top-25-kursov-golang-razrabotchikov--besplatnoe-i-platnoe-onlajn-obuchenie-programmirovaniyu-na-yazyke-go">ТОП-25 курсов Golang-разработчиков: бесплатное и платное онлайн-обучение программированию на языке GO</a>»</p>]]></description>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Обучение программированию]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Обучающие курсы]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 10 Nov 2024 17:00:03 GMT</pubDate>
      <content:encoded><![CDATA[<p>Освоить современный и востребованный язык программирования в короткие сроки вы можете на курсах Golang. Go, или Golang, — язык, разработанный Google в 2009 году, который облегчает решение задач программной инженерии и способствует эффективному управлению памятью устройства. Разработчики считают, что этот язык в скором времени станет одним из самых востребованных. Это связано с его упрощенным синтаксисом и высокой стабильностью. Поэтому изучение Go как новичкам без опыта в программировании, так и опытным специалистам поможет получить работу с хорошими перспективами.</p><p>Вместе с экспертами <a href="https://kursfinder.ru/">Kursfinder</a> я рассмотрела более 50 программ обучения и отобрала для вас 25 лучших курсов по Golang, бесплатных и платных. Еще больше вариантов вы можете найти в каталоге <a href="https://kursfinder.ru/golang/">курсов по Go</a>.</p><h2>ТОП-10 лучших курсов по Golang в 2026 году</h2><ol><li><a href="https://experts2.ru/TmzAbk?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=1">Go-разработчик с нуля</a> от «Яндекс Практикума» — онлайн-курс с большими объемами практических заданий для новичков.</li><li><a href="https://experts2.ru/eKbhHw?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=2">Golang Developer. Professional</a> от OTUS — продвинутая программа для карьерного роста.</li><li><a href="https://experts2.ru/psGeXl?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=3">Продвинутый Go‑разработчик</a> от «Яндекс Практикума» — обучение с персональными консультациями от ментора.</li><li><a href="https://experts2.ru/ufPCaz?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=4">Онлайн-курс Go-разработчик</a> от «Брунояма» — экспресс-курс с проектной работой для быстрого освоения базы.</li><li><a href="https://experts2.ru/irzYKx?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=5">Backend-разработчик на Go</a> от Skillfactory — углубленный курс обучения для новичков с тремя разными тарифами.</li><li><a href="https://experts2.ru/sEvVth?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=6">Golang Developer. Basic</a> от OTUS — базовая программа для быстрого входа в профессию.</li><li><a href="https://experts2.ru/heYVva?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=7">Golang-разработчик</a> от «Слёрма» — углубленный онлайн-курс со сквозным проектом для опытных.</li><li><a href="https://experts2.ru/sLaifX?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=8">Уроки Golang</a> от itProger — недорогая программа для освоения основ.</li><li><a href="https://experts2.ru/KcovTy?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=9">Golang для инженеров</a> от «Слёрма» — интенсивная программа по созданию микросервисов на Go для инженеров.</li><li><a href="https://experts2.ru/SyxkaD?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=10">Онлайн-практикум Golang-разработчик. Basic</a> от Rebrain — большой набор практики в асинхронном формате.</li></ol><p>Курсы по Go подойдут новичкам без опыта в программировании, разработчикам с опытом, которые хотят освоить перспективный язык и повысить свою ценность на рынке труда. Есть основания полагать, что Google и дальше будет продвигать использование своего языка, работать над его поддержкой, поэтому его востребованность будет только расти. Поэтому не стоит упускать свой шанс.</p><h2>Онлайн-курсы по Golang</h2><p><b>1. </b><a href="https://experts2.ru/TmzAbk?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=1">Go-разработчик с нуля</a><b> | Яндекс Практикум</b></p><p>Онлайн-курс Golang-разработчика от Яндекса. В ходе обучения вы создадите портфолио, поработаете с настоящими заказчиками, познакомитесь с реальными рабочими задачами, разовьете софт-скилы. После прохождения курса вас ждет диплом о профессиональной переподготовке (при наличии среднего или высшего профессионального образования) или сертификат, а также помощь в трудоустройстве.</p><figure><img src="https://media.tproger.ru/user-uploads/108137/2024-11-02/ad8a9a18-ab3f-4838-8ca5-b58232e70dcc.png" alt="" /></figure><ul><li>Стоимость: от 19 500 рублей в месяц в рассрочку на 8 месяцев.</li><li>Длительность: 8 месяцев.</li><li>Формат обучения: теоретические материалы, практика, работа над проектом, тренажеры, фидбэк от опытных разработчиков.</li><li>Сертификат: диплом о профессиональной переподготовке или сертификат.</li></ul><p><b>Кому подойдет:</b> людям без опыта в программировании, которые хотят освоить востребованный язык разработки.</p><p><b>Преимущества:</b></p><ul><li>практика с первого дня;</li><li>поддержка со стороны опытных разработчиков;</li><li>работа с реальными заказчиками;</li><li>проекты для портфолио;</li><li>активное комьюнити;</li><li>помощь с поиском работы.</li></ul><p><b>Недостатки:</b></p><ul><li>короткие сроки рассрочки с высокими платежами;</li><li>вся теория предоставляется в текстовом виде.</li></ul><p><b>Программа обучения:</b></p><ul><li>Основы Go.</li><li>HTTP в Go и REST API.</li><li>SQL и базы данных.</li><li>Многопоточность.</li><li>Linux.</li><li>CI/CD и Docker.</li><li>Подготовка к трудоустройству.</li></ul><p><a href="https://experts2.ru/TmzAbk?sub1=kursfinder-twb&amp;sub2=golang-kursy&amp;sub4=1">Ознакомиться с полной программой &gt;&gt;&gt;</a></p><p><b>2. </b><a href="https://experts2.ru/eKbhHw?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=2">Golang Developer. Professional</a> <b>| OTUS </b></p><p>Углубленная программа от Otus, рассчитанная на опытных разработчиков, которые хотят дорасти до уровня middle и senior. Вы освоите не только синтаксис языка, но и важнейшие внутренние механизмы, узнаете переводить проекты с других стеков на язык Go. Большое внимание уделяется решению практических задач, углублению знаний языка и сопутствующих технологии.</p><figure><img src="https://media.tproger.ru/user-uploads/108137/2024-11-02/81faf113-b86b-4cb8-bb81-dcfe739add6f.png" alt="" /></figure><ul><li>Стоимость: от 12 100 рублей в месяц в рассрочку на 10 месяцев.</li><li>Длительность: 5 месяцев.</li><li>Формат обучения: лекции с преподавателями, теоретические материалы, работа над проектом, самостоятельные работы.</li><li>Сертификат: сертификат о прохождении курса.</li></ul><p><b>Кому подойдет: </b>для разработчиков с опытом, которые хотят повысить свой уровень профессионализма.</p><p><b>Преимущества:</b></p><ul><li>проектная работа;</li><li>«живое» общение с экспертами;</li><li>возможность посетить бесплатные вебинары и оценить особенности обучения на платформе;</li><li>размещение резюме в базе OTUS;</li><li>прохождение собеседований у партнеров;</li></ul><p><b>Недостатки:</b></p><ul><li>для поступления требуется пройти вступительное тестирование;</li><li>время проведения вебинаров — вторник и четверг в 20:00 по Москве (может быть неудобным для жителей некоторых регионов России).</li></ul><p><b>Программа обучения:</b></p><ul><li>Начало работы.</li><li>Concurrency.</li><li>Стандартные библиотеки и практики.</li><li>Сеть и базы данных.</li><li>Микросервисы.</li><li>Проекты.</li></ul><p><a href="https://experts2.ru/eKbhHw?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=2">Ознакомиться с полной программой &gt;&gt;&gt;</a></p><p><b>3. </b><a href="https://experts2.ru/psGeXl?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=3">Продвинутый Go‑разработчик</a><b> | Яндекс Практикум</b></p><p>Курс обучения Golang с трудоустройством от Яндекса, рассчитанные на специалистов с опытом в бэкенде. Он позволит вам получить необходимые навыки для роста до уровня middle-специалиста. В программу курса включено углубленное изучение языка, решение задач и встречи 1-на-1 с ментором. В ходе обучения вы пройдете прикладные темы, создадите 3 учебных проекта для портфолио. После окончания курса слушателям выдается диплом о профессиональной переподготовке или сертификат (в зависимости от имеющегося уровня образования).</p><figure><img src="https://media.tproger.ru/user-uploads/108137/2024-11-02/d43ea7b5-768b-428f-9b69-7fc144881458.png" alt="" /></figure><ul><li>Стоимость: от 26 000 рублей в месяц в рассрочку на 6 месяцев.</li><li>Длительность: 6 месяцев.</li><li>Формат обучения: теоретические материалы, практика, проект, тренажеры, поддержка от команды.</li><li>Сертификат: диплом о профессиональной переподготовке или сертификат.</li></ul><p>Кому подойдет: специалистам с базовыми знаниями Go и бэкенд-разработки, которые хотят карьерного роста или трудоустроиться на более высокую должность.</p><p>Преимущества:</p><ul><li>возможно обучение с дедлайнами или без;</li><li>12 персональных консультаций с ментором;</li><li>помощь в обучении от YandexGPT;</li><li>три проекта для портфолио;</li><li>возврат денег за обучение, если устроитесь разработчиком в «Яндекс» в течение шести месяцев после выпуска;</li><li>помощь с поиском работы и развитием на текущем месте;</li><li>вебинары для разбора сложных тем, сессии Q&amp;A;</li><li>программа разработана на основе требований работодателей.</li></ul><p>Недостатки:</p><ul><li>высокие платежи по рассрочке или кредит;</li><li>много уроков в текстовом формате.</li></ul><p>Программа обучения:</p><ul><li>Пакеты стандартной библиотеки.</li><li>Конкурентность.</li><li>Промежуточный проект.</li><li>Паттерны проектирования.</li><li>Тулинг.</li><li>Расширенная стандартная библиотека.</li><li>Алгоритмы и структуры данных.</li></ul><p><a href="https://experts2.ru/psGeXl?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=3">Ознакомиться с полной программой &gt;&gt;&gt;</a></p><p><b>4.</b> <a href="https://experts2.ru/ufPCaz?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=4">Онлайн-курс Go-разработчик</a><b> | Бруноям</b></p><p><b><i>🎁Используйте эксклюзивный промокод «kursfinder», чтобы получить скидку 15% на любой курс школы.</i></b></p><p>Интенсивный онлайн-курс Golang для начинающих, который позволит изучить особенности языка программирования в короткие сроки. Вы научитесь решать все задачи, которые возникают перед Junior-разработчиком, погрузитесь в паттерны проектирования. В курсе предусмотрены 2 дополнительных модуля по Linux и Agile, которые пригодятся в работе. В конце обучения вас ждет работа над финальным проектом с защитой и презентацией.</p><figure><img src="https://media.tproger.ru/user-uploads/108137/2024-11-02/7da18dad-c2cf-4f0f-9d0f-a928e5fe14d5.png" alt="" /></figure><ul><li>Стоимость: от 4 158 рублей в месяц в рассрочку на 12 месяцев.</li><li>Длительность: 3 месяца.</li><li>Формат обучения: видеоматериалы, воркшопы, практика, вебинары.</li><li>Сертификат: сертификат о прохождении курса.</li></ul><p><b>Кому подойдет: </b>новичкам, которые хотят получить уверенную базу для начала разработки на Go.</p><p><b>Преимущества:</b></p><ul><li>мини-группы по 10-12 человек;</li><li>преподаватели с опытом в сфере от 3-х лет;</li><li>72 часа практической работы;</li><li>скидка за раннюю оплату;</li><li>помощь центра карьеры;</li><li>2 дополнительных модуля: Linux и Agile;</li><li>возврат суммы в течение месяца после оплаты, если курс не понравился.</li></ul><p><b>Недостатки:</b></p><ul><li>только 1 проектная работа;</li><li>достаточно короткий курс.</li></ul><p><b>Программа обучения:</b></p><ul><li>Основы языка.</li><li>REST API.</li><li>Git.</li><li>Работа с базами данных.</li><li>Многопоточность.</li><li>Архитектура приложения.</li></ul><p><a href="https://experts2.ru/ufPCaz?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=4">Ознакомиться с полной программой &gt;&gt;&gt;</a></p><p><b>5.</b><a href="https://experts2.ru/irzYKx?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=5"> Backend-разработчик на Go</a> <b>| Skillfactory</b></p><p>Программа этого курса программирования Go делится на три варианта обучения: базовый, оптимальный и VIP. В зависимости от выбранной опции вы получите разные объемы индивидуальных консультаций, а также дополнительные курсы. Например, в оптимальном доступен курс «Английский для IT», а в VIP — «Английский для IT» и «Алгоритмы и структуры данных». 80% обучения состоит из практических задач.</p><figure><img src="https://media.tproger.ru/user-uploads/108137/2024-11-02/15fdd4d5-46e0-4862-9249-8451b091a6d2.png" alt="" /></figure><ul><li>Стоимость: от 3 959 рублей в месяц в рассрочку на 36 месяцев.</li><li>Длительность: 12 месяцев.</li><li>Формат обучения: лекции в формате видео, живые вебинары, практика.</li><li>Сертификат: диплом о профессиональной переподготовке или сертификат.</li></ul><p><b>Кому подойдет: </b>программистам, которые хотят выйти на новый уровень в карьере. Тем, кто хочет работать в IT с нуля и освоить один из самых высокооплачиваемых и быстрорастущих языков программирования.</p><p><b>Преимущества:</b></p><ul><li>фокус на подготовке к трудоустройству;</li><li>оперативная помощь от менторов и координаторов;</li><li>3 проекта для портфолио;</li><li>большой набор дополнительных материалов;</li><li>доступ к курсу и обновлениям навсегда;</li><li>помощь с трудоустройством;</li><li>дополнительная скидка при единовременной оплате;</li><li>3 тарифа на выбор.</li></ul><p><b>Недостатки:</b></p><ul><li>редкий старт программы;</li><li>высокая стоимость VIP тарифа.</li></ul><p><b>Программа обучения:</b></p><ul><li>Программирование на Go.</li><li>Алгоритмы и структуры данных.</li><li>Многопоточность.</li><li>Инструменты разработчика.</li><li>Работа с базами данных.</li><li>Продвинутый Go.</li><li>Архитектура и основы DevOps.</li></ul><p><a href="https://experts2.ru/irzYKx?sub1=kursfinder-twb&amp;sub2=golang-kursy&amp;sub4=5"> Ознакомиться с полной программой &gt;&gt;&gt;</a></p><p><b>6. </b><a href="https://experts2.ru/sEvVth?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=6">Golang Developer. Basic</a><b> | OTUS </b></p><p>Базовая программа курса Go-разработчика от Otus, которая позволит быстро войти в IT или сменить основной рабочий язык разработки. Обучение проходит в онлайн-формате при непрерывном взаимодействии с преподавателями. Большие объемы практических заданий и работа над выпускным проектом позволят не только освоить все необходимые материалы, но и хорошо закрепить полученные знания.</p><figure><img src="https://media.tproger.ru/user-uploads/108137/2024-11-02/0f899ab0-d5af-4287-a11b-c45d56805668.png" alt="" /></figure><ul><li>Стоимость: от 6 800 рублей в месяц в рассрочку на 10 месяцев.</li><li>Длительность: 5 месяцев.</li><li>Формат обучения: вебинары, практика и проектная деятельность.</li><li>Сертификат: сертификат о прохождении курса.</li></ul><p><b>Кому подойдет:</b> людям без опыта в программировании, выпускникам технических вузов, разработчикам на других языках программирования.</p><p><b>Преимущества:</b></p><ul><li>недорогой курс;</li><li>«живое» общение с экспертами;</li><li>можно 1 раз бесплатно перейти в другую группу;</li><li>доступна оплата за счет работодателя;</li><li>удобный личный кабинет;</li><li>можно посетить бесплатные вебинары и оценить особенности обучения на платформе;</li><li>активное комьюнити.</li></ul><p><b>Недостатки:</b></p><ul><li>короткий срок рассрочки — всего 10 месяцев.</li><li>время проведения вебинаров — понедельник и среда в 20:00 по Москве (может быть неудобным для жителей некоторых регионов России).</li></ul><p><b>Программа обучения:</b></p><ul><li>Знакомство с Go.</li><li>Синтаксис языка.</li><li>Алгоритмы и структуры данных.</li><li>Concurrency.</li><li>Решение типовых задач.</li><li>Промышленная разработка.</li></ul><p><a href="https://experts2.ru/sEvVth?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=6">Ознакомиться с полной программой &gt;&gt;&gt;</a></p><p><b>7. </b><a href="https://experts2.ru/heYVva?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=7">Golang-разработчик</a> <b>| Слёрм </b></p><p>Программа этого курса рассчитана на людей с опытом коммерческой разработки или с базовыми знаниями языка Go. Вы научитесь работать с микросервисной архитектурой, использовать асинхронный подход. В ходе обучения вам предложат один из 4 проектов на выбор: онлайн-банк, файловое хранилище, мессенджер или работу над собственным проектом.</p><figure><img src="https://media.tproger.ru/user-uploads/108137/2024-11-02/c400bde9-a883-4f5b-b495-989a5673c4d3.png" alt="" /></figure><ul><li>Стоимость: от 15 000 рублей в месяц в рассрочку на 4 месяца.</li><li>Длительность: 3,5 месяца.</li><li>Формат обучения: набор источников с теорией, онлайн-встречи с экспертом, практика, проектная деятельность.</li><li>Сертификат: сертификат о прохождении курса.</li></ul><p><b>Кому подойдет:</b> специалистам уровня Junior, которые пишут на Go, а также программистам middle-уровня, которые работают с другими языками не менее двух лет. Кроме того, курс пригодится разработчикам, которые хотят переписать сервисы на Golang.</p><p><b>Преимущества:</b></p><ul><li>можно получить демодоступ на три дня;</li><li>работа над итоговым проектом на выбор;</li><li>онлайн-встречи с экспертами;</li><li>доступ на два года;</li><li>можно просмотреть запись прошедших встреч;</li><li>бонусный модуль по нагрузочным тестам.</li></ul><p><b>Недостатки:</b></p><ul><li>редкий старт программы;</li><li>небольшие объемы курса — 52 часа практики и 11 часов теории.</li></ul><p><b>Программа обучения:</b></p><ul><li>Вводный курс в Go.</li><li>Основные концепции.</li><li>Конкурентная обработка данных.</li><li>Интерфейсы и работа с ошибками.</li><li>Тесты.</li><li>Context.</li><li>Проектная работа.</li></ul><p><a href="https://experts2.ru/heYVva?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=7">Ознакомиться с полной программой &gt;&gt;&gt;</a></p><p><b>8.</b> <a href="https://experts2.ru/sLaifX?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=8">Уроки Golang</a><b> | itProger </b></p><p>Серия текстовых видеоуроков и заданий, которая содержится в этом курсе, позволит освоить базовые навыки работы с Go. В ходе обучения вы научитесь писать код на Golang, создадите на его основе полноценный веб-сайт. Теорию по курсу можно смотреть бесплатно, а для доступа к практическим заданиям требуется недорогая подписка на проект.</p><figure><img src="https://media.tproger.ru/user-uploads/108137/2024-11-02/1a6a26a0-e0b6-46f8-b8ac-bef06aa5850f.png" alt="" /></figure><ul><li>Стоимость: от 700 рублей в месяц — стоимость подписки на 1 месяц.</li><li>Длительность: 9 уроков и 30 заданий.</li><li>Формат обучения: видеоуроки, текстовые материалы, домашние задания с проверкой и комментариями.</li><li>Сертификат: нет.</li></ul><p><b>Кому подойдет: </b>новичкам без опыта работы с Go, которые хотят создать свой первый проект.</p><p><b>Преимущества:</b></p><ul><li>недорогой курс с возможностью проходить обучения на других программах по подписке;</li><li>задания к каждому уроку;</li><li>доступны консультации с экспертом (не во всех тарифах);</li><li>оперативная работа службы поддержки.</li></ul><p><b>Недостатки:</b></p><ul><li>узкоспециализированный курс;</li><li>мало практики.</li></ul><p><b>Программа обучения:</b></p><ul><li>Внедрение в язык Go.</li><li>Отслеживание URL.</li><li>Создание структур.</li><li>Работа с HTML.</li><li>Подключение SQL.</li><li>Новостной сайт.</li><li>Добавление данных через сайт.</li><li>Динамические страницы.</li><li>Публикация проекта на сервер.</li></ul><p><a href="https://experts2.ru/sLaifX?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=8">Ознакомиться с полной программой &gt;&gt;&gt;</a></p><p><b>9. </b><a href="https://experts2.ru/KcovTy?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=9">Golang для инженеров</a><b> | Слёрм </b></p><p>Программа этого курса доступна как в формате видеоуроков, так и в потоковом. Он рассчитан на инженеров с опытом, которые хотят научиться создавать собственный API на Go, запускать контейнеры, взаимодействовать с Docker. Курс постоянно обновляется, добавляются теоретические материалы и практика. В ходе обучения вы поработаете над проектом и создадите свой первый микросервис.</p><figure><img src="https://media.tproger.ru/user-uploads/108137/2024-11-02/8abba22b-1f7c-4333-ae28-2af3c5d6a8d2.png" alt="" /></figure><ul><li>Стоимость: от 12 500 рублей в месяц в рассрочку на 4 месяца.</li><li>Длительность: 11 недель.</li><li>Формат обучения: видеоуроки, онлайн-встречи, практика, проектная деятельность.</li><li>Сертификат: сертификат о прохождении курса.</li></ul><p><b>Кому подойдет:</b> DevOps-инженерам, которые хотят автоматизировать разработку. Системным администраторам, которые хотят стать DevOps-инженерами. Разработчикам, желающим научиться работать с микросервисной архитектурой.</p><p><b>Преимущества:</b></p><ul><li>три формата обучения: видеокурс, поток или корпоративный;</li><li>доступ к курсу на два года;</li><li>возможность купить курс в комплекте с другим с дополнительной скидкой;</li><li>итоговый проект для портфолио;</li><li>встречи со спикерами и ревью практики;</li><li>можно получить демодоступ на три дня.</li></ul><p><b>Недостатки:</b></p><ul><li>жесткие дедлайны;</li><li>редкий набор студентов на потоковое обучение.</li></ul><p><b>Программа обучения:</b></p><ul><li>Основы Golang.</li><li>Concurrency.</li><li>Практика.</li><li>Docker.</li><li>Kubernetes.</li><li>Финальный проект.</li></ul><p><a href="https://experts2.ru/KcovTy?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=9">Ознакомиться с полной программой &gt;&gt;&gt;</a></p><p><b>10.</b> <a href="https://experts2.ru/SyxkaD?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=10">Онлайн-практикум Golang-разработчик. Basic</a> <b>| Rebrain </b></p><p>Программа обучения на этом курсе строится на основе решения прикладных практических задач. Для успешного обучения требуются базовые знания Linux, сетевых протоколов и работы с системами контроля версий. В ходе обучения вы познакомитесь с краткой теорией и приступите к решению практических задач, которые будут проверять опытные инженеры.</p><figure><img src="https://media.tproger.ru/user-uploads/108137/2024-11-02/0e56c993-bd82-41ef-9b11-31b2af8a63cb.png" alt="" /></figure><ul><li>Стоимость: 60 000 рублей или рассрочка от банка.</li><li>Длительность: 30+ заданий.</li><li>Формат обучения: теоретические материалы, практика, поддержка команды в закрытом чате.</li><li>Сертификат: нет.</li></ul><p><b>Кому подойдет:</b> разработчикам, специалистам по тестированию, системным архитекторам, DevOps-инженерам и системным аналитикам.</p><p><b>Преимущества:</b></p><ul><li>доступ навсегда;</li><li>регулярное обновление программы;</li><li>90% практики;</li><li>асинхронное обучение.</li></ul><p><b>Недостатки:</b></p><ul><li>рассрочка только через банк;</li><li>не выдается сертификат.</li></ul><p><b>Программа обучения:</b></p><ul><li>Основы языка.</li><li>Модули и пакеты.</li><li>Структуры и интерфейсы.</li><li>Асинхронность.</li><li>Тестирование.</li><li>Кодогенерация.</li></ul><p><a href="https://experts2.ru/SyxkaD?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=10">Ознакомиться с полной программой &gt;&gt;&gt;</a></p><h2>Бесплатные курсы по Go/Golang</h2><p>Бесплатные курсы по Golang дают оптимальные решения как для начинающих, так и для опытных разработчиков. В данной подборке представлены бесплатные образовательные программы.</p><p><b>1. </b><a href="https://experts2.ru/LehKfj?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=netop">Основы Go</a> — <b>Яндекс Практикум</b></p><p>Курс создан для слушателей, знакомых с основами разработки. Эксперты расскажут, как читать код на Go, проверять качество кода, применяя юнит-код, переводить с Go на другой язык и т.д. Программа доступная и структурированная.</p><p><b>Главное о курсе: </b></p><ul><li>материалы можно изучать в комфортном темпе;</li><li>подходит для развития в Go-разработке.</li></ul><p><b>2.</b> <a href="https://experts2.ru/gkbrXB?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=netop">Разработка веб-сервисов на Golang (Go)</a> — <b>Stepik</b></p><p>Образовательная программа, созданная для практикующих программистов, новичкам это направление не подходит. Преподаватель углубится в основы, особенности асинхронной работы, JSON и бенчмарки и т.д.</p><p><b>Главное о курсе: </b></p><ul><li>актуальная программа;</li><li>плавное погружение в тему.</li></ul><p><b>3</b><a href="https://experts2.ru/SvBonu?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=netop">. Введение в Go-разработку</a> —<b> Skillbox</b></p><p>Программа представляет собой вебинар в записи. Лекции от ведущих экспертов школы длительные и насыщенные, материал преподается без «воды». Авторы рассматривают перспективы и сферу применения Golang, рынок труда разработчиков и особенности создания различных ПО.</p><p><b>Главное о курсе: </b></p><ul><li>для изучения не требуется регистрация;</li><li>насыщенная программа.</li></ul><p><b>4.</b> <a href="https://experts2.ru/GlRcre?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=netop">Программирование на Golang</a> — <b>Stepik</b></p><p>Программа для слушателей, имеющих опыт в программировании на любом из доступных языков. Преподаватели углубятся в вопросы функций, структур, файлов, сетей и т.д. Все изученные темы подкрепляются тестами и интерактивными задачами.</p><p><b>Главное о курсе: </b></p><ul><li>предусмотрена выдача сертификата;</li><li>есть обратная связь от экспертов.</li></ul><p><b>5. </b><a href="https://experts2.ru/sceUpH?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=netop">Курс Go: онлайн обучение с нуля, бесплатно</a> — <b>Code Basics</b></p><p>Бесплатный курс, который становится доступен после процесса регистрации. Помимо теоретического материала, для слушателей подготовлена практика в браузере. Эксперты познакомят слушателей с коллекциями, строками, функциями и методами начиная с основ.</p><p><b>Главное о курсе:  </b></p><ul><li>большой упор на практику;</li><li>для изучения материалов требуется минимум времени.</li></ul><p><b>6.</b><a href="https://experts2.ru/fxygSH?sub1=tproger-kf&amp;sub2=golang-kursy&amp;sub4=netop"> Go (Golang) — первое знакомство</a> — <b>Stepik</b></p><p>Бесплатный курс по Golang, предназначенные для самых юных программистов и новичков в разработке. Эксперт познакомит с азами язык программирования, изложение краткое и доступное. В программе есть тесты и задачи для закрепления изученного материала.</p><p><b>Главное о курсе: </b></p><ul><li>предусмотрена выдача сертификата;</li><li>доступная подача для новичков.</li></ul><h2>Видеоуроки по Golang</h2><ul><li><a href="https://www.youtube.com/playlist?list=PLfnFOImnyWRV7LPogMDFH5jPkCAHNL_uU">Golang Developer. Professional</a> от OTUS — уроки в формате видеолекций от экспертов крупнейшей IT-школы России. Слушателям предлагаются подробные разборы проектов, возможных подводных камней и «ловушек» на собеседованиях. Программа ориентирована на опытных разработчиков.</li><li><a href="https://www.youtube.com/playlist?list=PLbTTxxr-hMmxZMXsvaE-PozXxktdJ5zLR">Разработка &amp; Язык Go</a> от Максима Жашкевича — подборка видеоуроков для новичков. Лекции обучения Golang с нуля небольшие и в то же время насыщенные.</li><li><a href="https://youtu.be/gi6gAhzUhUg?si=Q8YZjDniJC9Q15Vs">Курс разработчика Golang</a> от Uproger — на канале автора представлено большое количество уроков, связанных с программированием на Go. Эксперты расскажут, как установить Golang и решать с его помощью различные задачи.</li><li><a href="https://www.youtube.com/playlist?list=PLc2Vkg57qmuRNHp6NNvYRVgg3OP-b5E_v">Изучаем Golang</a> от ThisIsIT — небольшие и доступные видеоуроки по Golang. Для лучшего понимания автор транслирует запись с экрана и подробно описывает каждое действие. Эксперт познакомит учеников с функциями, циклами, указателями, методами и др.</li><li><a href="https://www.youtube.com/playlist?list=PLrCZzMib1e9q-X5V9pTM6J0AemRWseM7I">Программирование на Go</a> от VK Team — подборка насыщенных лекций, подготовленная российским IT-сообществом. Насыщенная программа подходит для опытных программистов, желающих освоить Go. Слушатели смогут познакомиться с функциями, структурами, моделями и др.</li><li><a href="https://www.youtube.com/watch?reload=9&amp;v=G6eZaX_lgbQ&amp;list=PLP19RjSHH4aE9pB77yT1PbXzftGsXFiGl">Уроки по Golang</a> от The Art of Development — подборка представляет собой полноценный курс Go разработки. В уроках есть не только теоретическая составляющая, но и практическая: эксперт расскажет, как решать задачи, связанные с написанием и запуском веб-сервера на разных типах ОС.</li><li><a href="https://youtu.be/wabcXNZClnA?si=FQJxNfqo_LUQkrKl">Программист из 80х / История появления интернета и программирования в СССР / Всё о Go</a> — от «АйТиБороды» — видеоурок в формате интервью с экспертом, который расскажет не только о кодировании на Go, но и об истории развития интернета. Урок можно считать введением в Golang, эксперты рассказывают об особенностях, преимуществах и недостатках языка программирования.</li><li><a href="https://youtu.be/tISaO428aow?si=QcCt9nz3GgRu6cQ2">Podlodka #240 — Golang</a> от Podlodka — видеоурок представляет собой длительную лекцию по Golang. Эксперты расскажут об истории языка программирования, углубятся в область применения, а также поделятся рекомендациями для написания чистого кода.</li><li><a href="https://youtu.be/hDwqFRUuykQ?si=A1sgKKpsHdiYDX6O">Архитектура Go проекта на практике</a> от Evrone Development — обучение Golang в понятной и наглядной лекции. Эксперт расскажет, как подбирать практики для построения архитектуры и написания кода. Кроме того, уделяется внимание основным моментам, связанным с написанием кода на Go. Для удобства изучения материала лекция разделена на тайминги.</li></ul><h2>Полезные ресурсы</h2><ul><li><a href="https://www.w3schools.com/sql/sql_quickref.asp">SQL Tutorial</a> от W3Schools — на площадке размещено подробное руководство по SQL. Пособие будет полезно в самостоятельном изучении любого языка программирования, в том числе и Golang.</li><li><a href="https://go.dev/tour/welcome/1">Официальный тур по Go</a> от Go.dev — на платформе представлены небольшие уроки для обучения языку Golang. В правом окне есть небольшой тренажер для отработки полученных навыков. Энциклопедия доступна на нескольких языках, однако русского в перечне нет, что может вызвать определенные затруднения с изучением материала.</li></ul><h2>Бесплатные тренажеры и задачи по Golang/GO-разработке</h2><ul><li><a href="https://acm.timus.ru/">Timus Online Judge</a> — на сайте размещены задачи в разделе «архив». Также желающие могут поучаствовать в онлайн-соревнованиях, приводящиеся на базе УрФУ.</li><li><a href="https://www.codewars.com/">Codewars</a> — на платформе представлен функциональный тренажер, а также есть сообщество программистов, которые помогут в освоении новых языков программирования.  Упражнения для отработки представлены в формате «ката», с ними можно освоить более профессиональные техники кодирования или научиться одному из 55 доступных языков программирования.</li><li><a href="https://exercism.org/">Exercism</a> — онлайн-тренажер, ориентированный на работу более, чем с 70 языками программирования, в том числе и Golang. Для работы не требуется загрузка языка: тренажер поддерживает его, поэтому учиться можно прямо в браузерной версии. Функция автоматического анализа решений укажет на возможные ошибки в коде. Кроме того, ученики могут получать обратную связь от наставников.</li></ul><h2>Заключение</h2><p>На hh.ru представлено почти <a href="https://hh.ru/search/vacancy?search_field=name&amp;search_field=company_name&amp;search_field=description&amp;enable_snippets=false&amp;L_save_area=true&amp;text=Golang-%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%87%D0%B8%D0%BA&amp;customDomain=1">500 вакансий Go-разработчика</a> с зарплатой от 55 000 рублей. При этом большая часть вакансий — около 400 — предлагает более высокий уровень дохода — от 145 000 до 325 000 рублей и выше. Язык программирования Go, или Golang, является одним из самых перспективных и высокооплачиваемых, поэтому он будет интересен как новичкам в IT, так и опытным разработчикам, которые хотят увеличить свой доход. Освоить этот язык можно в короткие сроки на курсах Go, представленных в нашей подборке. Мы рассмотрели платные и бесплатные онлайн-программы, а также полезные видеоуроки для повторения теории и тренажеры, которые пригодятся для отработки знаний на практике.</p><p><i>В случае обнаружения неточностей, ошибок или неактуальной информации, пожалуйста, сообщите нам об этом в комментариях. Также дайте знать, если хотите, чтобы мы добавили проверенный вами курс в подборку.</i></p>]]></content:encoded>
    </item>
    <item>
      <title>Go и Rust заменят Java и Python: на чём писать в 2026 году</title>
      <link>https://tproger.ru/articles/go-i-rust-zamenyat-java-i-python-na-chem-pisat-v-2025-godu-i-dalwe-252602</link>
      <comments>https://tproger.ru/articles/go-i-rust-zamenyat-java-i-python-na-chem-pisat-v-2025-godu-i-dalwe-252602?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Владислав Устинов]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/go-i-rust-zamenyat-java-i-python-na-chem-pisat-v-2025-godu-i-dalwe-252602</guid>
      <description><![CDATA[<p>Сравнение Go, Rust, Java и Python в 2026 году. Рейтинги TIOBE и GitHub Octoverse, зарплаты по данным Хабр Карьеры. Узнайте, какой язык выбрать для карьеры и проектов.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/go-i-rust-zamenyat-java-i-python-na-chem-pisat-v-2025-godu-i-dalwe-252602">Go и Rust заменят Java и Python: на чём писать в 2026 году</a>»</p>]]></description>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Rust]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 01 Nov 2024 10:00:02 GMT</pubDate>
      <content:encoded><![CDATA[<p><i>Это обновлённая версия статьи. Все данные актуализированы по состоянию на март 2026: рейтинги TIOBE и GitHub Octoverse 2025, зарплаты по данным Хабр Карьеры за H2 2025.</i></p><p>Цифровизация экономики и импортозамещение — два тренда, которые были с нами в 2023–2025 годах и останутся в 2026. Особенно это касается ниш, связанных с разработкой ПО, автоматизацией и работой облачных инфраструктур.</p><p>Java, Python, Go и Rust активно применяются в этих нишах. Но рынок в 2026 году преподнёс сюрпризы: Go неожиданно упал в рейтинге TIOBE, оставшись при этом самым высокооплачиваемым языком в России. Разберём, что происходит с каждым языком и на чём стоит писать. В этой статье сравниваем Go, Rust, Java и Python по рейтингам TIOBE и GitHub, зарплатам и реальному применению — чтобы вы точно знали, на чём стоит писать в 2026 году.</p><p><b>Go</b> упал с 7-го на 16-е место в TIOBE, но остаётся самым высокооплачиваемым языком в РФ (320 000 руб.)</p><p><b>Python</b> — первый по TIOBE (21,25%), второй на GitHub</p><p><b>Java</b> опустился на 4-е место в TIOBE, но стабильно растёт на GitHub (+20,73%)</p><p><b>Rust</b> за пределами топ-10 TIOBE, но занял прочные позиции в системном программировании</p><p><b>TypeScript</b> впервые обогнал Python на GitHub Octoverse 2025</p><h2>Java: преимущества и недостатки для разработки в 2026 году</h2><p>Java за почти 30 лет своего существования прошёл большой путь, оброс огромной экосистемой и стал стандартом индустрии в области автоматизации. В 2026 году Java опустился на 4-е место в рейтинге TIOBE (7,99%, минус 2,37 п.п.), уступив C и C++. Но на GitHub Octoverse 2025 он показал рост +20,73%, оставшись четвёртым по количеству активных репозиториев. Рассмотрим этот язык подробнее.</p><p><i>Кстати, если вам интересно обучение этому языку программирования, то рекомендуем <a href="https://tproger.ru/courses/onlajn-kurs--java-razrabotchik--ot-edme-pro-2?erid=LjN8KQszj">онлайн-курс «JAVA-разработчик» от EdMe.pro</a>.</i></p><h3>Краткая история Java и его популярность в корпоративной среде</h3><p>Java разработала и выпустила в 1995 году компания Sun Microsystems для программирования бытовой электроники. В итоге получился производительный язык с понятным синтаксисом и революционной фишкой в виде портативности. Java можно запустить на любом устройстве. Благодаря этому он хорошо зарекомендовал себя в сервисах автоматизации и прочно укрепился в корпоративной среде.</p><p>В 2010 году Oracle приобрела Sun Microsystems и продолжила развитие Java. Язык используется для разработки серверных программ, веб и android-приложений, а также в системах с высокими нагрузками.</p><p>Сейчас на нём работают Яндекс Маркет, Ozon, сервисы Google, Netflix, Amazon и другие крупные инфраструктуры.</p><h3>Сильные стороны: обширная экосистема, поддержка многопоточных приложений, JVM</h3><h4>Обширная экосистема</h4><p>Согласно <a href="https://www.tiobe.com/tiobe-index/">рейтингу</a> TIOBE за март 2026 года, Java занимает 4-е место с долей 7,99%. Хотя это ниже, чем годом ранее, Java остаётся одним из самых используемых языков в мире.</p><p>На GitHub Octoverse 2025 Java занял 4-е место и показал рост +20,73% по количеству активных репозиториев. Это подтверждает, что корпоративная экосистема Java продолжает развиваться.</p><p>Такая популярность соизмерима и с его экосистемой. У Java за годы разработки скопилось более сотни фреймворков под разные задачи. А ещё это один из немногих языков, у которого есть стеки фреймворков — несколько фреймворков, которые объединены в одну экосистему.</p><p>Здесь есть решения под работу с вебом, разработку приложений, обучение нейросетей и много чего ещё.</p><h4>Поддержка многопоточных приложений</h4><p>Java поддерживает многопоточность. Это значит, что программа выделяет под каждую задачу отдельный поток, который её решает. Допустим, у нас есть сервер, к которому обращается несколько пользователей. Он может обрабатывать их запросы по одному в порядке очереди, а может выделить под каждого по отдельному потоку и обрабатывать сразу все запросы.</p><p>В некоторых языках многопоточность иногда приводит к конфликтам и ошибкам, но не в Java. В нём потоки независимы друг от друга. Если в одном потоке произойдёт ошибка, то она никак не отразится на других.</p><p>Благодаря стабильной многопоточности в Java можно параллельно решать задачи в коде, делая его тем самым более производительным.</p><h4>JVM — виртуальная машина</h4><p>Разработчики языка Java старались придерживаться принципа: «Написал один раз, запускай везде». Для этого они создали виртуальную машину — программу, которая имитирует работу компьютера. Она компилирует Java в байт-код, который может запускаться на разных устройствах.</p><p>У этого подхода следующие преимущества:</p><ul><li>Не надо заморачиваться со сборкой мусора, JVM сделает всё сама;</li><li>Java код не нужно переписывать под каждую платформу;</li><li>Быстрое выполнение часто используемых методов, так как они компилируются в машинный код и кешируются;</li><li>Безопасность. Весь код выполняется на изолированной от основной среды виртуальной машине.</li></ul><h3>Почему Java медленно развивается и требует много ресурсов</h3><h4>Сравнительно медленное развитие</h4><p>Медленное развитие Java связано в первую очередь с его огромным наследием. Java 23 — последняя стабильная версия языка, но многие компании работают на Java 11 и Java 8, которым уже много лет. При обновлении языка разработчики вынуждены сохранять высокий уровень совместимости со старыми версиями, что тормозит процесс развития.</p><p>Но он всё же развивается. Компания Oracle выпускает новые промежуточные версии Java каждые полгода и каждые 3 года готовит долгосрочные версии, поддерживаемые до 3 лет.</p><h4>Высокая ресурсоёмкость</h4><p>Виртуальная машина Java, с одной стороны, спасает разработчиков от лишней головной боли, а с другой, требует больше ресурсов:</p><ul><li>Java использует сборщик мусора, который иногда останавливает выполнение программы для освобождения неиспользуемой памяти. Это может приводить к задержкам и большему потреблению ресурсов.</li><li>Виртуальная машина является посредником между реальным устройством и кодом. Как итог, этот «посредник» нуждается в дополнительных ресурсах.</li><li>Необходимость совместимости между различными версиями языка усложняет оптимизацию приложений, что также влияет на их производительность.</li></ul><h2>Преимущества и недостатки Python: почему он такой удобный и медленный</h2><p>Python известен как один из самых дружелюбных языков программирования, особенно для начинающих разработчиков. В марте 2026 года он занимает 1-е место в рейтинге TIOBE (21,25%), хотя и потерял 2,59 п.п. за год. На GitHub Octoverse 2025 Python стал вторым, уступив TypeScript, но показав рост +48,78%. За этой простотой скрываются как значительные преимущества, так и ограничения в производительности.</p><h3>Почему Python такой простой и гибкий</h3><p>У Python <a href="https://tproger.ru/articles/python--polnyj-putevoditel-ot-pervoj-strochki-do-prodvinutyh-tem">лаконичный и читаемый синтаксис</a>. Вот так выглядит вывод «Hello world!» в Python:</p><p>А так в Java:</p><p>В Python код проще читать и писать, здесь не надо заканчивать каждую строку точкой с запятой, указывать типы данных и ставить фигурные скобки для функций, циклов, условий.</p><p>При разработке на Python не надо заморачиваться с низкоуровневыми задачами, его можно запускать на разных платформах. У Python за годы сформировалось большое комьюнити, много сторонних библиотек, и он подходит для решения разных задач — от веб-разработки до создания Android-приложений и обучения ИИ.</p><h3>Почему Python доминирует в области науки о данных, искусственного интеллекта и веб-разработки</h3><p>Согласно <a href="https://lp.jetbrains.com/python-developers-survey-2023/">опросу</a> Python Software Foundation и JetBrains, Python чаще всего применяют в аналитике данных, веб-разработке и машинном обучении.</p><p>Благодаря простому синтаксису он хорошо подходит для командной работы, имеет низкий порог входа для новичков и позволяет сосредоточиться на работе с данными, вместо лишних копаний в коде.</p><p>Другое преимущество языка кроется в большом комьюнити и множестве библиотек. NumPy, Pandas, Matplotlib и многие другие библиотеки стали стандартами для работы с данными.</p><p>За более чем 30 лет существования Python написаны популярные фреймворки для веб-разработки Django и Flask. Это в совокупности с его кроссплатформенностью, обширной экосистемой библиотек и простотой делает Python удобным инструментом для анализа данных, веб-разработки и машинного обучения.</p><h3>Проблемы с производительностью и ограниченная пригодность для многопоточных систем</h3><p>Языки программирования бывают компилируемые и интерпретируемые. В компилируемых языках весь код сразу переводится в машинный, благодаря чему он быстрее. В интерпретируемых языках код читается построчно и сразу выполняется в среде разработки при помощи интерпретатора. Это удобно, но малоэффективно с точки зрения производительности.</p><p>Python относится ко второй категории языков, в связи с чем уступает в производительности Go, Rust и Java.</p><p>Другая причина низкой производительности — динамическая типизация данных. Это значит, что разработчику не нужно указывать типы переменных, что упрощает код, но требует дополнительных вычислений при его запуске.</p><p>Ещё одно «узкое» место Python — работа с многопоточностью. Чтобы избежать ошибки при работе с памятью сразу нескольких потоков есть механизм GIL. Он даёт доступ к одному участку памяти только одному потоку. С одной стороны, это помогает избежать ошибок, но с другой, затрудняет выполнение одинаковых параллельных задач.</p><h2>Преимущества Go: удобный как Python, производительный как C++</h2><p>Язык Go был создан в Google для решения сложных задач, требующих масштабирования и производительности, сохраняя при этом простоту разработки. В 2026 году Go преподнёс неожиданность: он упал с 7-го на 16-е место в рейтинге TIOBE (минус 1,49 п.п.) — это стало самым большим падением среди популярных языков. При этом Go остаётся самым высокооплачиваемым языком в России: медианная зарплата — 320 000 руб. по данным Хабр Карьеры за 2-е полугодие 2025 года.</p><h3>Простота синтаксиса и высокопроизводительное выполнение</h3><p>Go совмещает в себе производительность низкоуровневых языков как C++, простоту и удобство кода высокоуровневых, как Python.</p><p>Пример кода для вывода в консоли на Go:</p><p>Язык Go избегает сложных синтаксических конструкций и наследования, здесь нет перегрузки функций или операторов, неявных преобразований типов. Он прост и лаконичен.</p><p>Производительность Go на уровне С и C++. Достигается это благодаря следующим причинам:</p><ul><li>Он компилируемый со строгой типизацией данных;</li><li>Современный сборщик мусора, который требует меньше ресурсов;</li><li>Нет сложных конструкций по типу наследования;</li><li>Адаптирован под работу с параллельными задачами.</li></ul><h3>Параллелизм в Go: почему он остаётся лучшим выбором для облачных инфраструктур в 2026 году</h3><p>В Go хорошо реализован параллелизм — одновременное выполнение задач. Это достигается за счёт горутин и каналов.</p><p>Горутины — потоки, которые выполняются в среде Go. Они небольшие и начинаются от 2 кб, поэтому их создание и удаление не требует большого количества ресурсов. Go может одновременно выполнять тысячи горутин.</p><p>Каналы — специальные участки в памяти, которые позволяют синхронизировать информацию между разными горутинами. Они связывают логику работы горутин между собой.</p><p>Помимо параллелизма в языке Go есть конкурентность — быстрое переключение между разными задачами в рамках одного потока или процессора. Например:</p><ul><li>Мы выполняем задачу 1, но не до конца, замораживаем её.</li><li>Выполняем до конца задачу 2.</li><li>Выполняем, но не полностью задачу 3.</li><li>Заканчиваем выполнение задачи 1 и возвращаемся к задаче 3.</li></ul><p>В некоторых случаях такое «жонглирование» задачами повышает производительность.</p><p>Параллелизм языка Go позволяет более плавно распределять нагрузку и параллельно выполнять задачи. Это качество критически важно для облачных инфраструктур, и именно в этой нише Go по-прежнему безусловный лидер в 2026 году.</p><h2>Преимущества Rust: быстрый и безопасный</h2><p>Rust выделяется среди других языков программирования своим уникальным подходом к управлению памятью и безопасности кода без ущерба для производительности. В рейтинге TIOBE на март 2026 года Rust находится за пределами топ-10, но он продолжает завоёвывать ниши, где критичны производительность и безопасность. Разберём по порядку.</p><h3>Главная особенность Rust: безопасность памяти без сборщика мусора</h3><p>Когда мы запускаем код, то под наши переменные и другие типы данных среда резервирует и заполняет участки памяти устройства. Если переменная вдруг на каком-то этапе выполнения кода стала ненужной, то эти участки необходимо чистить. В противном случае мы получим память забитую мусором. Это плохо сказывается на производительности.</p><p>В таких языках, как Java, Python, Go предусмотрены автоматические сборщики мусора. Это специальные программы, которые находят неиспользуемые забитые участки памяти и освобождают их.</p><p>В языках C и C++ таких сборщиков нет, и программист должен сам прописывать в коде когда и что вычищать из памяти.</p><p>Оба этих подхода имеют свои плюсы и минусы. Автоматическая очистка мусора упрощает код и позволяет избежать некоторых ошибок с памятью, но снижает производительность.</p><p>Языки без очистки мусора более производительные, но страдают нагромождением кода и требуют от разработчика быть более внимательным.</p><p>Rust использует другой подход. У него нет сборщика мусора, но есть владение. Когда мы добавляем значение к переменной в Rust, то не просто записываем под неё участок памяти, но и указываем, что она этим участком «владеет».</p><p>Например:</p><p>В этом примере мы создали переменную s1 со значением «Привет, Rust!», она является владельцем этой строки.</p><p>Далее мы передали значение s1 в s2. Теперь s2 владеет строкой «Привет, Rust!», а не s1.</p><p>Если мы хотим использовать данные одной переменной в другой, но без передачи владения, то можем применять заимствования. Заимствования — это ссылки на значения других переменных. Они бывают изменяемыми и неизменяемыми. Первые позволяют создавать только одно заимствование, вторые сколько угодно.</p><p>Мы можем создавать изменяемые и неизменяемые заимствования при помощи знаков «&amp;» и «&amp;mut», причём это работает не только с переменными, но и с массивами.</p><p>Пример заимствований:</p><p>Другая особенность Rust — область видимости. Область видимости — это блок кода, который выполняется в данный момент времени. Обычно это функции, циклы и выражения. Как только блок кода выполнен, он исчезает из области видимости, и Rust очищает память от типов данных, которые были в этом блоке кода. Так мы получаем возможность безопасно работать с памятью без использования сборщика мусора.</p><h3>Высокая производительность на уровне C++ при минимальных рисках ошибок</h3><p>Производительность Rust сопоставима с С, С++ и Go, но при этом он более безопасный и удобный с точки зрения отладки.</p><p>Высокая производительность достигается за счёт компиляции в машинный код, строгой типизации данных, поддержки многопоточности и отсутствия сборщика мусора.</p><p>Поддержка каналов, специфика работы с памятью и инициализации переменных делают код на Rust более защищённым от ошибок, что упрощает отладку.</p><h3>Rust в системном программировании и низкоуровневых приложениях</h3><p>Из-за своей производительности и надёжности Rust — отличный язык для системного программирования, где необходимо писать операционные системы, драйверы, компиляторы и виртуальные машины.</p><p>Rust позволяет запускать код, написанный на C, что важно для поддержки некоторых старых программ.</p><p>Другая особенность Rust заключается в работе с памятью. Мы уже разобрали как устроены владение, зависимости и область видимости. При желании в Rust можно управлять памятью вручную, как в C и C++. Это повышает вероятность ошибок, но придаёт гибкости коду.</p><p>Ещё он поддерживает кроссплатформенную разработку. Программу на Rust под Windows будет потом проще адаптировать под Android.</p><p>По этим же причинам Rust хорошо подходит для разработки низкоуровневых приложений. Его применяют в таких проектах, как VK, Twitter, Coursera, Dropbox и Mozilla Firefox.</p><h2>Сравнение языков по ключевым критериям: производительность, зарплаты и область применения</h2><p>Каждый из рассматриваемых языков имеет свои сильные стороны и области применения. Сравним Go, Rust, Java и Python по ключевым характеристикам, чтобы лучше понять, где и когда использование каждого из них наиболее оправдано.</p><h3>Производительность: сравнение Go, Rust, Java и Python</h3><p>Rust и Go более производительные, чем Python и Java, это следует из результатов <a href="https://blog.scanner.dev/serverless-speed-rust-vs-go-java-python-in-aws-lambda-functions/">тестов</a>.</p><figure><img src="https://media.tproger.ru/user-uploads/105039/2024-10-29/5f29224b-4979-46a9-80eb-075c9fdf556c.jpg" alt="На чём писать в 2026 году и дальше" /><figcaption>Сравнение производительности Python, Java, Go и Rust</figcaption></figure><p>График сравнивает время выполнения задач для функций Lambda при различных объёмах выделенной памяти (в мегабайтах). Ось Y показывает продолжительность выполнения задач в секундах, а ось X — объём выделенной памяти для функции.</p><p>Python — самый медленный. Чем меньше мы предоставляем памяти, тем дольше он справляется с задачей, но при больших объёмах памяти он хоть и уступает Java, но близко к нему приближается.</p><p>Второй по медлительности язык — Java. Go и Rust находятся примерно на одном уровне производительности и сильно опережают Java и Python.</p><h3>Зарплаты разработчиков в России: Go, Java, Python в 2025–2026 году</h3><p>По данным Хабр Карьеры за второе полугодие 2025 года, медианные зарплаты разработчиков в России распределились так:</p><ul><li>Go — 320 000 руб. (самая высокая среди всех языков, +4% за полгода);</li><li>Python — 229 000 руб. (+8%);</li><li>Java — 226 000 руб. (+1%).</li></ul><p>Парадокс: Go упал в рейтинге TIOBE, но остаётся самым дорогим языком на российском рынке. Это объясняется дефицитом специалистов: компании активно используют Go в продакшене, но найти опытного Go-разработчика по-прежнему сложно.</p><h3>Простота изучения и развитие экосистемы</h3><p>Python и Go — самые дружелюбные для новичков языки программирования. У них простой, читаемый лаконичный синтаксис, а многие низкоуровневые задачи по типу сборки мусора автоматизированы, под них не нужно писать код.</p><p>Python проще в изучении, чем Go, благодаря динамической типизации, однако уступает ему в производительности. Go, в свою очередь, имеет специфическую реализацию объектно-ориентированного программирования.</p><p>С точки зрения экосистемы, Java и Python — явные лидеры. Они присутствуют на рынке с 1990-х годов. За это время они обросли большим комьюнити, накопили обширную базу библиотек, фреймворков, готовых проектов и учебных материалов. У Go и Rust тоже всё это есть, но куда в меньших масштабах.</p><h3>Применимость в разных областях: от облачных сервисов до высоконагруженных систем и микросервисов</h3><p>Go отлично подходит для облачных сервисов, микросервисов и высоконагруженных систем благодаря простоте синтаксиса, быстрой компиляции и хорошей работе с многопоточностью. Но есть ложка дёгтя для программистов, которые работают в парадигме ООП, связанная с отсутствием наследования и классов.</p><p>Rust — производительный язык с очень строгой структурой и управлением памятью. На нём не так просто писать код как на Go и Python, но зато он получается более безопасным и оптимизированным. Поэтому Rust тоже хороший выбор для облачных сервисов, микросервисов и высоконагруженных систем.</p><p>Java уступает Go и Rust в производительности, но хорошо работает с многопоточностью и обладает большим количеством фреймворков и библиотек. Он стандарт индустрии.</p><p>Python подходит для некоторых облачных сервисов, но не рекомендуется для высоконагруженных систем и микросервисов. Это интерпретируемый язык, и он плохо работает с параллельными задачами, что может негативно сказаться на производительности под нагрузкой.</p><h2>На чём писать в 2026 году</h2><p>Данные 2026 года показывают, что ситуация сложнее, чем казалось в 2024 году. Go неожиданно упал в рейтингах, Java продолжает терять позиции в TIOBE, но оба языка растут на GitHub и остаются востребованными работодателями.</p><h3>Прогнозы развития: куда движутся Java и Python</h3><p>Java и Python останутся востребованными языками в 2026 году. На российском рынке Java-разработчики получают медианные 226 000 руб., Python-разработчики — 229 000 руб. Оба языка стабильно представлены в вакансиях на hh.ru.</p><p>Java и Python обладают развитой экосистемой с большим комьюнити. На них написано уже очень много кода, и в 2026 году эти языки никуда не денутся. Глобально они будут развиваться медленнее, чем более новые языки, как Go и Rust, но из этого не следует, что они станут невостребованными.</p><h3>Какие отрасли могут полностью перейти на Go или Rust</h3><p>Нельзя сказать, что какая-то из отраслей возьмёт и полностью откажется от Java или Python в 2026 году, уж очень это ресурсозатратно. Падение Go в рейтинге TIOBE показывает, что даже быстрорастущие языки могут замедляться. Тем не менее Go и Rust продолжают укреплять позиции в области микросервисов, высокопроизводительных систем, DevOps и автоматизации.</p><p>Отдельно стоит выделить Rust и сферу системного программирования. Благодаря высокой производительности и безопасности он продолжает набирать обороты.</p><p>Java и Python останутся актуальными в области облачных технологий. Слишком много инфраструктур написано на этих языках, которые требуют поддержки. Плюс у них есть много фреймворков с готовыми решениями для разработки.</p><h3>Ожидаемые изменения в экосистемах и возможные сценарии развития</h3><p>Одно из возможных направлений развития Java — это ИИ и машинное обучение. Да, сейчас в этой области доминирует Python, но у него есть ограничения в производительности и проблемы с работой в многопоточном режиме. У Java тоже есть свои библиотеки для работы с ИИ, при этом он производительнее и хорошо справляется с многопоточностью.</p><p>Python и дальше будет развиваться, особенно в сфере аналитики данных, ИИ, машинного обучения. Что касается самого языка, то ждём решений по улучшению работы с многопоточностью. Продолжится увеличение комьюнити и рост числа образовательных материалов.</p><p>Go будет увеличивать своё влияние в области облачных решений и микросервисов, несмотря на падение в рейтинге TIOBE. Рейтинг измеряет популярность в поисковиках, а не реальное использование. Kubernetes, Docker, Terraform, Prometheus — вся облачная инфраструктура написана на Go, и это не изменится.</p><p>То же касается и языка Rust. Он будет активнее применяться в системном программировании и высоконагруженных системах, особенно в таких сферах, как криптовалюты, блокчейн и интернет вещей. Там очень важна производительность и безопасность.</p><p>Go и Rust однозначно <a href="https://tproger.ru/articles/kakie-yazyki-programmirovaniya-uchit-v-2025-godu">стоит учить</a>, эти языки продолжают расти в реальном применении. Но новичкам лучше сфокусироваться на Java и Python — с ними будет проще найти первую работу.</p>]]></content:encoded>
    </item>
    <item>
      <title>Python, Go, Ruby — сайты создателей популярнейших языков собрали в одном месте</title>
      <link>https://tproger.ru/news/python--go--ruby---sajty-sozdatelej-populyarnejwih-yazykov-sobrali-v-odnom-meste</link>
      <comments>https://tproger.ru/news/python--go--ruby---sajty-sozdatelej-populyarnejwih-yazykov-sobrali-v-odnom-meste?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/python--go--ruby---sajty-sozdatelej-populyarnejwih-yazykov-sobrali-v-odnom-meste</guid>
      <description><![CDATA[<p>Свежий проект собрал личные сайты создателей популярных языков программирования Python, Go и Ruby в одном месте, но столкнулся с техническими трудностями, такими как высокая загрузка процессора</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/python--go--ruby---sajty-sozdatelej-populyarnejwih-yazykov-sobrali-v-odnom-meste">Python, Go, Ruby — сайты создателей популярнейших языков собрали в одном месте</a>»</p>]]></description>
      <category><![CDATA[Производительность]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Ruby]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 28 Oct 2024 05:41:19 GMT</pubDate>
      <content:encoded><![CDATA[<p>В сети появился интересный проект, в котором собрали все личные сайты создателей популярных языков программирования.</p><p>Проект представляет собой коллекцию скриншотов страниц, которые служат личными блогами и веб-ресурсами таких известных специалистов, как Джон Маккарти, Дональд Кнут, Роб Пайк и другие.</p><p>Рядом с изображениями сайтов есть ссылки на эти страницы.</p><h2>Технические трудности и идеи для улучшения</h2><p>Изначально проект начал набирать популярность благодаря посту на Reddit.</p><p>Правда, пользователи платформы заметили, что текущая версия сайта сталкивается с рядом проблем. Основные жалобы включают низкую производительность и перегрузку ресурсов браузера.</p><p>Например, пользователи сообщали, что сайт вызывает высокую загрузку процессора, особенно на мобильных устройствах, что делает его практически невозможным для использования.</p><p>Были предложены варианты решения — такие как внедрение ссылок и скриншотов вместо фреймов, чтобы снизить нагрузку на страницу.</p><figure><img src="https://media.tproger.ru/user-uploads/98945/2024-10-28/5c00a11a-d863-4b34-a853-593ba014f5c3.jpg" alt="" /></figure><h2>Идеи для оптимизации сайта</h2><p>Кроме того, обсуждались способы улучшения сайта, чтобы сделать его более удобным.</p><p>Например, был предложен вариант с «ленивой» загрузкой, при котором фреймы подгружаются только тогда, когда пользователь прокручивает страницу до нужного участка.</p><p>Это могло бы значительно уменьшить потребление ресурсов и улучшить пользовательский опыт, особенно на мобильных устройствах.</p><h2>Вдохновение для будущих разработок</h2><p>Отметим, что хоть у проекта и есть проблемы, он явно показывает, насколько интересной может быть идея коллекционирования информации о тех, кто стоит за самыми популярными языками программирования.</p><p>Посмотреть на проект своими глазами можно по <a href="https://homepages.pldb.io/">ссылке</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как написать производительный и безопасный backend на Go</title>
      <link>https://tproger.ru/articles/kak-napisat-proizvoditelnyj-i-bezopasnyj-backend-na-go</link>
      <comments>https://tproger.ru/articles/kak-napisat-proizvoditelnyj-i-bezopasnyj-backend-na-go?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Сергей Лалетин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/articles/kak-napisat-proizvoditelnyj-i-bezopasnyj-backend-na-go</guid>
      <description><![CDATA[<p>Backend на Go. Показываем, как написать бекенд на Го. Рассматриваем реальные примеры и кейсы ✔ Tproger
</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/articles/kak-napisat-proizvoditelnyj-i-bezopasnyj-backend-na-go">Как написать производительный и безопасный backend на Go</a>»</p>]]></description>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Бэкенд]]></category>
      <category><![CDATA[Статьи]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 03 Oct 2024 10:00:00 GMT</pubDate>
      <content:encoded><![CDATA[<h2>Простота равно эффективность</h2><p>Первое, что бросается в глаза при работе с Go — его синтаксис. Он лаконичен и понятен, что делает разработку быстрой и приятной. Это одно из главных преимуществ Go — не нужно тратить кучу времени на изучение сложных конструкций и абстракций. Вот, например, как выглядит типичный сервер на Go:</p><p>Этот небольшой фрагмент кода запускает веб-сервер, который отвечает "Hello, Go!" на каждый запрос. Вы удивитесь, но именно такой минимализм делает Go невероятно удобным и мощным инструментом для создания backend'ов.</p><h2>Параллелизм на Go: быстрые и лёгкие горутины</h2><p>Одной из самых крутых фишек Go является горутины. В отличие от тяжеловесных потоков, горутины — это легковесные потоки, которые занимают минимум памяти и быстро переключаются между задачами. Допустим, нам нужно обрабатывать несколько запросов одновременно:</p><p>Всё, что нужно для запуска задачи в параллели, — это ключевое слово go. При этом Go автоматически управляет конкурентностью, распределяя задачи по системным потокам, что значительно улучшает производительность. Даже при тысячах запросов одновременно сервер на Go не захлебнётся благодаря эффективной работе с ресурсами.</p><h2>Безопасность: защищаем наш backend</h2><p>Производительность — это важно, но безопасность не менее критична. Go предлагает множество инструментов для создания защищённых приложений. Например, чтобы избежать SQL-инъекций, используйте подготовленные запросы:</p><p>Это не только снижает риск инъекций, но и упрощает работу с базой данных. А для управления сессиями и безопасной авторизации на Go можно использовать токены JWT:</p><p>Использование токенов в приложении позволяет легко управлять аутентификацией и поддерживать безопасность на высоком уровне. Встроенные библиотеки вроде gorilla/csrf помогают защититься от CSRF-атак, а такие инструменты как go-playground/validator помогают валидировать данные.</p><h2>Кэширование и масштабирование</h2><p>Как обеспечить высокую скорость ответа даже при большой нагрузке? Один из простых способов — <b>кэширование</b>. Вы можете, например, сохранять результаты частых запросов в память, чтобы избежать лишней нагрузки на базу данных:</p><p>Простой подход с использованием карты (словаря) для хранения данных кэша может сильно ускорить время ответа.</p><h2>Инструменты мониторинга и тестирования</h2><p>Производительность приложения — это не только быстрая обработка запросов, но и умение находить узкие места. Go поставляется с встроенными инструментами для профилирования и тестирования. Например, с помощью библиотеки net/http/pprof можно отслеживать, сколько памяти занимает ваше приложение, и где возникают задержки.</p><p>Пример интеграции с инструментом мониторинга Prometheus для сбора метрик:</p><p>Этот код не только отслеживает количество запросов, но и предоставляет возможность анализа метрик через Prometheus, что помогает поддерживать и улучшать производительность.</p><h2>Заключение</h2><p>Go — это не просто язык, это целая философия, которая сосредоточена на простоте, производительности и безопасности. Использование горутин позволяет эффективно обрабатывать большое количество запросов одновременно, а встроенные средства безопасности помогают защитить ваше приложение от атак. Не стоит забывать и о мощных инструментах для профилирования и мониторинга, которые делают процесс разработки и поддержки приложений на Go ещё более приятным.</p><p>Этот язык идеально подходит для создания современных высоконагруженных сервисов. С ним легко работать, масштабировать и поддерживать приложения на должном уровне безопасности.</p>]]></content:encoded>
    </item>
    <item>
      <title>Релиз «убийцы» Node.js — Deno 2.0 RC: улучшенная совместимость с npm и новая система разрешений</title>
      <link>https://tproger.ru/news/reliz--ubijcy--node-js---deno-2-0-rc--uluchwennaya-sovmestimost-s-npm-i-novaya-sistema-razrewenij</link>
      <comments>https://tproger.ru/news/reliz--ubijcy--node-js---deno-2-0-rc--uluchwennaya-sovmestimost-s-npm-i-novaya-sistema-razrewenij?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/reliz--ubijcy--node-js---deno-2-0-rc--uluchwennaya-sovmestimost-s-npm-i-novaya-sistema-razrewenij</guid>
      <description><![CDATA[<p>Релиз-кандидат Deno 2.0 предлагает полную совместимость с npm-модулями и новую систему разрешений, упрощающую разработку и повышающую безопасность</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/reliz--ubijcy--node-js---deno-2-0-rc--uluchwennaya-sovmestimost-s-npm-i-novaya-sistema-razrewenij">Релиз «убийцы» Node.js — Deno 2.0 RC: улучшенная совместимость с npm и новая система разрешений</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Node.js]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 24 Sep 2024 19:23:39 GMT</pubDate>
      <content:encoded><![CDATA[<p><a href="https://deno.com/blog/v2.0-release-candidate">Вышел</a> релиз-кандидат Deno 2.0, который вызывает интерес за счет улучшенной поддержке npm и обновленной системы разрешений.</p><p>Одним из главных нововведений стало то, что Deno теперь практически полностью совместим с пакетами npm. Это значит, что разработчики могут легко интегрировать модули пакета в свои Deno-проекты.</p><p>Таким образом, прямо сейчас более 2 млн npm-модулей доступны для использования без необходимости перехода на Node.js.</p><h2>Новая система разрешений</h2><p>Система разрешений, которая всегда была одной из главных фишек Deno, получила значительное обновление.</p><p>Теперь ошибки прав доступа стали более понятными. Например, вместо старого Deno.errors.PermissionDenied, при проблемах с правами на доступ, Deno выдаст новый тип ошибки Deno.errors.NotCapable, что облегчает различение между ошибками ОС и самого инструмента.</p><p>Кроме того, Deno упростил работу с разрешениями для некоторых API. Например, доступ к основному модулю через Deno.mainModule больше не требует использования флага --allow-read.</p><p>Обновления также коснулись команд для запуска процессов: теперь использование флага --allow-run без списка разрешенных бинарных файлов сопровождается предупреждением, направленным на повышение безопасности кода.</p><h2>Примеры использования и новые возможности</h2><p>Помимо изменений в разрешениях, Deno теперь поддерживает высокоточное время без необходимости использования флага --allow-hrtime. Это упростит работу с такими задачами, как мониторинг производительности.</p><p>Deno 2.0 продолжает стабилизацию API, таких как WebGPU и FFI (интерфейс для взаимодействия с библиотеками на C). Эти функции больше не требуют использования флагов для работы, что значительно упрощает их использование.</p><p>Ознакомиться с полным списком улучшение и нововведений можно по <a href="https://deno.com/blog/v2.0-release-candidate">ссылке</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Создатели «тамагочи для хакеров» Flipper Zero представили новое устройство</title>
      <link>https://tproger.ru/news/--sozdateli--tamagochi-dlya-hakerov--flipper-zero-predstavili-novoe-ustrojstvo</link>
      <comments>https://tproger.ru/news/--sozdateli--tamagochi-dlya-hakerov--flipper-zero-predstavili-novoe-ustrojstvo?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Булат Яббаров]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/news/--sozdateli--tamagochi-dlya-hakerov--flipper-zero-predstavili-novoe-ustrojstvo</guid>
      <description><![CDATA[<p>Команда Flipper Devices, создатели Flipper Zero, представила новое устройство — Busy Status Bar, LED-дисплей для отображения статуса занятости. Гаджет показывает, когда вы будете свободны, управляется через кнопки, мобильное приложение или USB. Отлично подходит для созвонов и стримов. Цена — $189.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/news/--sozdateli--tamagochi-dlya-hakerov--flipper-zero-predstavili-novoe-ustrojstvo">Создатели «тамагочи для хакеров» Flipper Zero представили новое устройство</a>»</p>]]></description>
      <category><![CDATA[API]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Golang]]></category>
      <category><![CDATA[Node.js]]></category>
      <category><![CDATA[Новости]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 09 Aug 2024 08:13:19 GMT</pubDate>
      <content:encoded><![CDATA[<p>Команда Flipper Devices, известная по «хакерскому» гаджету Flipper Zero, представила новое устройство — Busy Status Bar.</p><p>Это небольшой LED-дисплей, который помогает показать окружающим, что вы заняты, а также оповестить их, когда освободитесь.</p><h2>Как это работает?</h2><p>Busy Status Bar показывает на экране, например, сколько времени осталось до конца вашего созвона или когда вы снова будете доступны.</p><p>Управлять устройством можно кнопками, через мобильное приложение или подключив его к компьютеру по USB.</p><p>Кроме того, есть возможность автоматизации через открытое API — это находка для тех, кто любит настраивать всё под себя.</p><p>Точной информации об источнике питания устройства нет, но предполагается, что работает оно от аккумулятора.</p><figure><img src="https://media.tproger.ru/user-uploads/98945/2024-08-09/2ecdfce4-c9e1-4862-8546-c47dd3ee05d3.jpg" alt="" /></figure><h2>Схожесть с другим проектом</h2><p>Интересно, что новинка от Flipper Devices во многом напоминает <a href="https://www.reddit.com/r/hwstartups/comments/148dnkm/busy_statusbar_choosing_leds_and_updating_design/">другой проект</a>, созданный для решения проблемы отвлекающих факторов на работе.</p><p>Автор этого проекта также задумался о том, как быстро и ненавязчиво сообщить окружающим о своей занятости, и собрал прототип устройства с аналогичным функционалом. Судя по всему, именно из него и вырос Busy Status Bar.</p><figure><img src="https://media.tproger.ru/user-uploads/98945/2024-08-09/d0f9eed4-e2ef-4eb0-938b-c9a2d46d0677.jpg" alt="" /><figcaption>Другой проект с таким же названием подозрительно напоминает новинку от Flipper Devices</figcaption></figure><h2>Кому это пригодится?</h2><p>Гаджет отлично подходит для тех, кто часто проводит созвоны или стримит. Например, он может автоматически показывать сообщение «On Call», когда включается микрофон на компьютере.</p><p>А еще есть встроенный таймер для работы по методу «Помидора» для сохранения продуктивности и для того, чтобы не забывать про перерывы.</p><h2>Где купить и сколько стоит?</h2><p>Уже сейчас Busy Status Bar можно заказать на сайте Flipper Devices за $189. Также доступна бета-версия приложения для iOS и Android, чтобы управлять гаджетом прямо со смартфона.</p><p>В будущем планируется появления библиотек для популярных языков программирования: Python, Go, Node.js.</p>]]></content:encoded>
    </item>
  </channel>
</rss>