ru
Feedback
Библиотека Go-разработчика | Golang

Библиотека Go-разработчика | Golang

Открыть в Telegram

Все самое полезное для Go-разработчика в одном канале. По рекламе: @proglib_adv Учиться у нас: https://proglib.io/w/32d20779 Для обратной связи: @proglibrary_feeedback_bot РКН: https://gosuslugi.ru/snet/67a4a8c24689c2151c752af0 #WXSSA

Больше

📈 Аналитический обзор Telegram-канала Библиотека Go-разработчика | Golang

Канал Библиотека Go-разработчика | Golang (@goproglib) языкового сегмента Русский является активным участником. Сейчас сообщество объединяет 24 020 подписчиков, занимая 5 674 место в категории Технологии и приложения и 27 915 место в регионе Россия.

📊 Показатели аудитории и динамика

С момента создания невідомо проект демонстрирует стремительный рост, собрав аудиторию из 24 020 подписчиков.

Согласно последним данным от 05 июня, 2026, канал показывает стабильную активность. За последние 30 дней изменение числа участников составило 51, а за последние 24 часа — 6, при этом общий охват остаётся высоким.

  • Статус верификации: Не верифицирован
  • Уровень вовлечённости (ER): Средний показатель вовлечённости аудитории составляет 10.51%. В первые 24 часа после публикации контент обычно набирает 7.82% реакций от общего числа подписчиков.
  • Охват публикаций: В среднем каждый пост получает 2 524 просмотров. В течение первых суток публикация набирает 1 879 просмотров.
  • Реакции и взаимодействия: Аудитория активно поддерживает контент: среднее количество реакций на один пост — 9.
  • Тематические интересы: Контент сосредоточен на ключевых темах, таких как навигация, лучшее_из_библиотеки_2025, git, string, golive.

📝 Описание и контентная политика

Автор описывает ресурс как площадку для выражения субъективного мнения:
Все самое полезное для Go-разработчика в одном канале. По рекламе: @proglib_adv Учиться у нас: https://proglib.io/w/32d20779 Для обратной связи: @proglibrary_feeedback_bot РКН: https://gosuslugi.ru/snet/67a4a8c24689c2151c752af0 #WXSSA

Благодаря высокой частоте обновлений (последние данные получены 07 июня, 2026) канал поддерживает актуальность и высокий уровень охвата публикаций. Аналитика показывает, что аудитория активно взаимодействует с контентом, что делает его важной точкой влияния в категории Технологии и приложения.

24 020
Подписчики
+624 часа
-107 дней
+5130 день
Архив постов
🧑‍💻 Конструктор, из которого собран Docker Когда вы запускаете контейнер, под капотом работает движок. Писать такой движок
🧑‍💻 Конструктор, из которого собран Docker Когда вы запускаете контейнер, под капотом работает движок. Писать такой движок с нуля никто не хочет, там слишком много низкоуровневой возни с неймспейсами, cgroups, образами и сетью. Moby — это открытый проект, который Docker вынес в апстрим, набор готовых компонентов для сборки систем на контейнерах. Из этих кубиков собран сам Docker, и из них же вы можете собрать что-то своё. ➡️ Что внутри. Moby это не одна программа, а коллекция компонентов с понятными API, среди них движок выполнения контейнеров, инструменты сборки образов, работа с реестром и оркестрация. Идея в том, чтобы каждый кусок имел чёткую функцию и при желании заменялся на другой. ➡️ Как с ним работать. Чаще всего вы общаетесь с движком через Docker CLI, но из Go можно дёргать тот же Engine API напрямую. Вот аналог docker ps, который читает настройки из переменных окружения вроде DOCKER_HOST и сам согласует версию API с демоном:
package main

import (
  "context"
  "fmt"
  "log"

  "github.com/moby/moby/client"
)

func main() {
  apiClient, err := client.New(client.FromEnv)
  if err != nil {
    log.Fatal(err)
  }
  defer apiClient.Close()

  result, err := apiClient.ContainerList(context.Background(), client.ContainerListOptions{
    All: true,
  })
  if err != nil {
    log.Fatal(err)
  }

  for _, ctr := range result.Items {
    fmt.Printf("%s  %s  %s\n", ctr.ID, ctr.Status, ctr.Image)
  }
}
Этого хватает, чтобы из своего сервиса запускать контейнеры, тянуть образы, читать логи и управлять сетью, то есть делать всё то же, что умеет команда docker. ➡️ Кому это нужно. Moby рассчитан на инженеров и энтузиастов, которым интересно ковыряться в открытом коде, чинить баги и строить системы на контейнерах. Если коротко, Moby это фундамент Docker, открытый и модульный. Брать его стоит тогда, когда вам мало готового движка и хочется собрать или допилить свой. ➡️ Репозиторий 📍 Навигация: ВакансииЗадачиСобесыКанал в Max 🐸 Библиотека Go-разработчика #GoToProduction

Попросил нейронку написать счётчик сотрудников.. 📍 Навигация: Вакансии • Задачи • Собесы • Канал в Max 🐸 Библиотека Go-разр
Попросил нейронку написать счётчик сотрудников.. 📍 Навигация: ВакансииЗадачиСобесыКанал в Max 🐸 Библиотека Go-разработчика #GoGiggle

📎 Чего не дают логи, метрики и трейсы Идея «три столпа наблюдаемости» звучит убедительно. Соберите логи, метрики и трейсы, отправьте в одну платформу, и поймёте систему. На практике у команды есть все три, а баг в проде она всё равно не находит. Ниже главные мысли статьи о том, почему так выходит, с примерами на Go. 🖇 Данные есть, понимания нет Три столпа дают сигналы, но не объяснение. На инциденте вы коррелируете то, что собрали заранее, часто в спешке, и этого набора не хватает под конкретный сбой. 🖇 Высокая кардинальность бьёт первой Как только вам нужен разрез по user_id, арендатору или связке эндпоинт плюс регион, метрики ломаются. Так делать не стоит, потому что число рядов взрывается:
// Плохо. user_id и tenant дают почти неограниченное число комбинаций.
httpRequests := prometheus.NewCounterVec(
    prometheus.CounterOpts{Name: "http_requests_total"},
    []string{"endpoint", "region", "user_id", "tenant"},
)
httpRequests.WithLabelValues(endpoint, region, userID, tenant).Inc()
Безопаснее держать в метках только ограниченный набор значений, а детали уносить в трейс или лог:
// Лучше. В метках только то, у чего мало возможных значений.
httpRequests := prometheus.NewCounterVec(
    prometheus.CounterOpts{Name: "http_requests_total"},
    []string{"endpoint", "region", "status"},
)
httpRequests.WithLabelValues(endpoint, region, status).Inc()
🖇 Инструментация видит только ожидаемое Вы измеряете то, что предусмотрели заранее. Новый тип сбоя не попадает ни в один график, и в этот момент вы слепы. 🖇 Худшие баги живут между сервисами Два микросервиса по своим метрикам здоровы, задержки в трейсах нормальные, логи чистые. А вместе они выдают неверный ответ. Проблема в связи между ними, и ни одна отдельная метрика её не ловит. 🖇 Зелёные метрики не значат правильный результат Три столпа описывают инфраструктуру, а не бизнес. Сервис может держать отличную задержку и нулевые ошибки, при этом считать цену неверно. Поэтому полезно мерить сам бизнес-результат, а не только технику:
// Считаем не задержку, а расхождение цены. Это и есть семантическая наблюдаемость.
span.SetAttributes(
    attribute.String("order.id", order.ID),
    attribute.Int64("order.expected_cents", expected),
    attribute.Int64("order.charged_cents", charged),
)
if charged != expected {
    priceMismatchTotal.Inc()
}
🖇 Лучшее улучшение делается после инцидента Самый сильный приём звучит скучно. После разбора спросите, какой информации не хватило, и добавьте её. Часто это пара полей в структурном логе через slog, которых раньше не было:
// После разбора добавили request_id и tenant. Без них инцидент искали вслепую.
slog.Error("payment declined",
    "request_id", reqID,
    "tenant", tenant,
    "provider", provider,
    "code", declineCode,
)
Эффект накапливается, и через год полтора команда отлаживает прод заметно быстрее. Вывод простой. Три столпа это стартовая точка, а не финал. Современные системы грязнее и сильнее завязаны на деньги, поэтому и наблюдаемость нужна с высокой кардинальностью, ориентированная на события и привязанная к бизнес-результату. Наша рассылка даёт максимум за минимум. 📍 Навигация: ВакансииЗадачиСобесыКанал в Max 🐸 Библиотека Go-разработчика #GoDeep

😎 Знакомьтесь с экспертом Proglib.academy: Senior Software Engineer и Team Lead в Yandex Cloud Роман Барлос Роман — консульт
😎 Знакомьтесь с экспертом Proglib.academy: Senior Software Engineer и Team Lead в Yandex Cloud Роман Барлос Роман — консультант нашего курса «Разработка ИИ-агентов». Он работает на стыке cloud-native архитектуры и AI, активно внедряя современные ИИ-подходы в реальные процессы разработки. За что его ценит IT-комьюнити? 🟣 Team Lead и AI-евангелист в команде UX Yandex Cloud
14-лет в разработке. Занимается AI-адопшеном в команде Yandex Cloud, проводит мастер-классы и продвигает лучшие практики для повышения эффективности разработчиков.
🟣 Техлид Sourcecraft Code Assistant
С сильным практическим бэкграундом принимал участие как технический лид в создании мощного AI-расширения для VS Code.
🟣 Создатель полезного Open Source
Разрабатывает утилиты, которые позволяют быстро начать эксперименты с инференсом и агентами в локальном окружении: например, набор скриптов vllm-setup для быстрого запуска окружения и mini-proxy — минималистичный прокси для OpenAI API провайдеров.
🟣 Автор интерактивных ML-визуализаций
Объясняет сложные концепции наглядно. Создал серию залипательных обучающих материалов, где можно вживую пощупать работу сетей Хопфилда, машин Больцмана и VC-размерности.
Роман регулярно делится инженерными наработками, инсайтами и экспертизой в своем авторском Telegram-канале На курсе Роман выступает консультантом программы: он помогает формировать содержание уроков с опорой на актуальные инженерные практики и жесткие требования индустрии. Узнать больше о программе и разработке автономных систем: 👉 Курс «Разработка ИИ-агентов» Так, продолжаем знакомить вас с командой? 👍 — Да, ждем новых лиц 🔥 — Жду полезные материалы от Романа

Можно ли использовать слайс как ключ в мапе Вопрос на первый взгляд простой, но именно такие мелочи отделяют тех, кто Go использует, от тех, кто Go понимает. Прежде чем лезть в документацию — подумайте сами. Вот что стоит вспомнить: 🔹 В Go ключ мапы должен быть comparable — то есть поддерживать операции == и != 🔹 Спросите себя: можно ли сравнить два слайса через ==? Что вообще значит «два слайса равны»? ➡️ Ответ 📍 Навигация: ВакансииЗадачиСобесыКанал в Max 🐸 Библиотека Go-разработчика #ReadySetGo

📎 Обёртывание ошибок через %w В Go 1.13 появился %w, который сохраняет исходную ошибку внутри обёртки и позволяет проверять её дальше по коду через errors.Is и errors.As. Когда ошибка проходит через несколько слоёв приложения, на каждом уровне к ней добавляют контекст. Если при этом теряется исходный тип, наверху остаётся только текст, и проверить причину можно лишь по подстроке. Любая правка формулировки ломает такую проверку. Старый способ:
fmt.Errorf("failed to fetch user: %v", err)
%v подставляет текст ошибки и выбрасывает сам объект. Узнать, что под капотом лежала sql.ErrNoRows, после этого уже нельзя. Современный способ:
fmt.Errorf("failed to fetch user: %w", err)
%w оборачивает ошибку и сохраняет ссылку на оригинал, поэтому цепочку потом можно размотать. Как проверять причину errors.Is идёт по всей цепочке обёрток и сравнивает каждое звено с конкретным значением:
if errors.Is(err, sql.ErrNoRows) {
    // пользователь не найден
}
Не важно, сколько слоёв обёрток сверху, проверка доберётся до нужной ошибки. Когда нужен сам объект Если требуется не просто факт совпадения, а доступ к полям ошибки, помогает errors.As. Он находит в цепочке ошибку нужного типа и записывает её в переменную:
var pathErr *os.PathError
if errors.As(err, &pathErr) {
    slog.Error("ошибка пути", "path", pathErr.Path)
}
Своя ошибка в цепочке Чтобы ваш тип распознавался через errors.Is и errors.As, достаточно реализовать метод Unwrap:
type AppError struct {
    Code int
    Err  error
}

func (e *AppError) Unwrap() error { return e.Err }
%w заменил хрупкое сравнение строк на надёжную проверку по значению и по типу. Оборачивайте ошибки этим глаголом везде, где добавляете контекст, и используйте errors.Is вместо сравнения текста. 📍 Навигация: ВакансииЗадачиСобесыКанал в Max 🐸 Библиотека Go-разработчика #GoToProduction

🫳 Типичная микросервисная архитектура 🫳 Постоянно слышу, что монолит - это прошлое, а микросервисы, типа единственный путь
🫳 Типичная микросервисная архитектура 🫳 Постоянно слышу, что монолит - это прошлое, а микросервисы, типа единственный путь к успеху. Все ищут ту самую структуру, которая позволит масштабироваться до бесконечности. На схеме классический скелет современной системы. Выглядит разумно, но без четкого понимания каждый блок может стать точкой отказа:API Gateway Единая точка входа для всех клиентов. Итог: если гейтвей "прилег" или перегружен, твои крутые микросервисы внизу превращаются в бесполезный набор кода, до которого никто не может достучаться. • Load Balancer Раскидывает трафик, чтобы один сервер не закипел. Итог: всё работает плавно, пока балансировщик правильно настроен. Ошибка в конфиге и весь трафик летит в один сервис, убивая его за секунды. • Service Registry & Discovery Сервисы должны как-то находить друг друга. Итог: если эта штука заглючит, сервис А просто не узнает, где искать сервис Б. Система развалится на куски, которые не умеют общаться. • Разделение по доменам (Domain A / Domain B) У каждого сервиса своя база. Итог: ты получаешь независимость, но платишь за это адом при попытке собрать общую аналитику или сделать сложный транзакционный запрос между доменами. Уже переезжали на микросервисы? ❤️ — да, это было больно, но оно того стоило 🔥 — сидим на монолите и в ус не дуем 🔹 Практический интенсив «Архитектуры и шаблоны проектирования» 🔹 Получить консультацию менеджера 🔹 Сайт Академии 🔹 Сайт Proglib 🏃‍♀️ Азбука айтишника #ликбез

💰 Деньги в Go без потери копеек Как работать с деньгами в Go Дробные типы в Go хранят значения в двоичном виде, и многие дес
💰 Деньги в Go без потери копеек Как работать с деньгами в Go Дробные типы в Go хранят значения в двоичном виде, и многие десятичные дроби в нём не представимы точно. Из-за этого простые суммы дают неожиданный результат, а ошибки копятся с каждой операцией. Ниже разберём, как считать деньги без потери копеек. ℹ️ Почему float64 не подходит Классический пример:
fmt.Println(0.1 + 0.2) // 0.30000000000000004
На одной операции это незаметно, но в отчёте на тысячи позиций расхождение в копейки превращается в расхождение в рубли. Сравнивать такие суммы через == тоже нельзя, потому что равные на бумаге значения в памяти отличаются. 📎 Способ первый. Целые числа в минимальных единицах Самый надёжный приём хранить сумму в наименьшей единице валюты, то есть в копейках или центах, как int64. Целочисленная арифметика точна, сложение и вычитание не теряют ничего:
type Money int64 // сумма в копейках

func (m Money) String() string {
    sign := ""
    if m < 0 {
        sign = "-"
        m = -m
    }
    return fmt.Sprintf("%s%d.%02d", sign, m/100, m%100)
}
Цену 199 рублей 99 копеек вы храните как Money(19999), а метод String собирает её обратно в читаемый вид. Этого подхода хватает для подавляющего большинства задач с фиксированной валютой. 📎 Способ второй. Библиотека shopspring/decimal Целые числа неудобны там, где много делений и процентов, например при расчёте НДС или распределении суммы между участниками. Тут помогает пакет decimal, который хранит число как набор цифр с десятичной точкой и считает в десятичной системе:
import "github.com/shopspring/decimal"

price := decimal.RequireFromString("199.99")
tax := price.Mul(decimal.RequireFromString("0.20"))
total := price.Add(tax).Round(2)

fmt.Println(total.StringFixed(2)) // 239.99
Обратите внимание, что значение задаётся строкой через RequireFromString, а не из float64. Так в число не попадёт двоичная погрешность ещё на входе. 📎 Округление и деление При делении суммы остаток никуда не девается, и его нужно осознанно куда-то отнести. decimal позволяет задать правило округления явно:
total := decimal.RequireFromString("100.00")
share := total.Div(decimal.NewFromInt(3)).Round(2)
fmt.Println(share.StringFixed(2)) // 33.33
Сумма трёх таких долей даст 99.99, и одну копейку придётся добавить к одной из частей вручную. Это не баг библиотеки, а свойство самих денег, и решать его нужно по правилам вашей предметной области. Для денег в Go не используйте float64 и точка. 📍 Навигация: ВакансииЗадачиСобесыКанал в Max 🐸 Библиотека Go-разработчика #GoDeep

🌐 Пакет из стандартной библиотеки Go, про который почти никто не знает Он даёт хуки внутрь исходящего HTTP-запроса — туда, к
🌐 Пакет из стандартной библиотеки Go, про который почти никто не знает Он даёт хуки внутрь исходящего HTTP-запроса — туда, куда снаружи не заглянуть: • DNS lookup: начало и конец • TCP connect • TLS handshake • Момент получения первого байта ответа • Факт переиспользования соединения Вся магия через контекст: трейс кладётся в ctx, транспорт сам его достаёт. Никаких интерфейсов, никакого middleware. Что можно собрать за пару строк: 1. curl-like тайминги
fmt.Printf("DNS: %v\n", dnsDone.Sub(dnsStart))
fmt.Printf("TLS: %v\n", tlsDone.Sub(tlsStart))
fmt.Printf("TTFB: %v\n", firstByte.Sub(gotConn))
2. Логирующий RoundTripper Оборачиваете транспорт, в каждом запросе автоматически пишутся тайминги. Одна инициализация и всё. Лайфхак: GotConnInfo.Reused = false на каждом запросе к одному хосту = где-то не закрывается тело ответа. 📍 Навигация: ВакансииЗадачиСобесыКанал в Max 🐸 Библиотека Go-разработчика #GoToProduction

❔Готовишься к собеседованию по Go — или просто хочешь понимать тонкости языка? 🙂Тогда этот канал для тебя. Задачи с реальных
Готовишься к собеседованию по Go — или просто хочешь понимать тонкости языка? 🙂Тогда этот канал для тебя. Задачи с реальных собеседований, разбор подводных камней языка и честно про рынок. Как выглядит твоё резюме глазами нанимателя и что спрашивают прямо сейчас в топовых компаниях 👍 Подписывайся, если хочешь расти в Golang! ПОДПИСАТЬСЯ ПОДПИСАТЬСЯ Реклама. Урин Дмитрий Алексеевич, ИНН 760404084194. Erid 2Vtzqvb278C

👨‍💻Структурное логирование в Go через slog До версии 1.21 в Go не было единого подхода к логированию. Команды выбирали между сторонними библиотеками вроде zap, logrus и zerolog, поэтому кодовая база разных проектов выглядела неодинаково. Стандартный пакет log умел писать только обычные текстовые строки, которые тяжело парсить и собирать в системах вроде Loki или ELK. В Go 1.21 появился slog, который принёс структурное логирование прямо в стандартную библиотеку. Если из всего списка новинок вы захотите взять только одну, берите эту. Какую боль решает Структурные логи это пары ключ значение, а не склеенная строка. Их легко фильтровать, искать по конкретным полям и отдавать в JSON прямо в систему сбора. Раньше ради этого приходилось тянуть внешнюю зависимость, теперь хватает стандартной библиотеки. Старый способ выглядел так:
log.Printf("[ERROR] User %d login failed from IP %s", userID, ip)
Здесь данные смешаны с текстом, и чтобы вытащить userID, нужно писать регулярки. Современный способ:
import "log/slog"

slog.Error("Login failed", "userID", userID, "ip", ip)
Сообщение остаётся читаемым, а данные лежат в отдельных полях. Что он делает slog строится вокруг трёх частей. Logger принимает вызовы вроде Info и Error. Handler решает, куда и в каком формате писать. Attr это пара ключ значение. В комплекте идут два обработчика, TextHandler для человекочитаемого вывода и JSONHandler для машинного. Как настроить JSON вывод Чтобы получать логи в JSON, достаточно подменить обработчик у глобального логгера:
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
slog.SetDefault(logger)

slog.Info("server started", "port", 8080)
На выходе получится строка JSON с полями time, level, msg и port. Её сразу можно отправлять в сборщик логов без дополнительной обработки. Группировка и контекст Часто к каждому запросу удобно прикреплять одни и те же поля. Метод With создаёт логгер с заранее заданными атрибутами:
reqLogger := slog.With("requestID", reqID, "userID", userID)
reqLogger.Info("processing request")
reqLogger.Warn("slow response", "ms", 320)
Теперь requestID и userID попадут в каждую запись без повторного перечисления. Переводить проект можно постепенно, начав с замены log на slog в новых модулях. Старый код при этом продолжит работать, а новые записи сразу станут пригодными для машинного разбора. 📍 Навигация: ВакансииЗадачиСобесыКанал в Max 🐸 Библиотека Go-разработчика #GoToProduction

Главное не отменить подписку на нашу рассылку 📍 Навигация: Вакансии • Задачи • Собесы • Канал в Max 🐸 Библиотека Go-разрабо
Главное не отменить подписку на нашу рассылку 📍 Навигация: ВакансииЗадачиСобесыКанал в Max 🐸 Библиотека Go-разработчика #GoGiggle

🤭 Топ-вакансий для Go-разработчиков за неделю Team Lead Go — до 600 000 ₽, удаленно (Москва) Senior Golang Developer — до 400 000 ₽, удаленно (Москва) Middle Golang Developer — Remote (udalyonka) ➡️ Еще больше топовых вакансий — в нашем канале Go jobs 🐸 Библиотека Go-разработчика #GoWork

🔄 Вышли Go 1.26.4 и 1.25.11 с исправлениями безопасности Команда Go выпустила минорные версии 1.26.4 и 1.25.11. Это патч-рел
🔄 Вышли Go 1.26.4 и 1.25.11 с исправлениями безопасности Команда Go выпустила минорные версии 1.26.4 и 1.25.11. Это патч-релизы, которые закрывают три уязвимости в стандартной библиотеке. Если вы используете одну из этих веток, обновиться стоит сразу. ➡️ Проблема в пакете mime. Метод WordDecoder.DecodeHeader имел квадратичную сложность, поэтому специально собранный заголовок с множеством некорректных encoded-word мог съесть процессор. Это CVE-2026-42504. ➡️ Уязвимость в net/textproto. Функции пакета подставляли входные данные в текст ошибки без экранирования, а вход часто приходит от внешней стороны, например когда net/http разбирает заголовки ответа сервера. Через это можно было протащить в чужие логи управляющие байты терминала и вводящий в заблуждение текст. Это CVE-2026-42507. ➡️ Фикс в crypto/x509. Метод VerifyHostname вызывал strings.Split по точке в цикле для каждой записи DNS SAN, и при длинном списке имён проверка росла квадратично, причём даже для недоверенных сертификатов. Это CVE-2026-27145. ➡️ Источник 📍 Навигация: ВакансииЗадачиСобесыКанал в Max 🐸 Библиотека Go-разработчика #GoLive

⚡️ Продолжаем знакомить вас с экспертами курса AgentOps! — Сергей Нотевский расскажет, как выстроить FinOps для AI-продуктов:
⚡️ Продолжаем знакомить вас с экспертами курса AgentOps!Сергей Нотевский расскажет, как выстроить FinOps для AI-продуктов: оптимизировать затраты на разработку и продакшен, внедрить model routing, semantic cache и систему алертов для контроля расходов — Эмиль Сатаев разберет Context Engineering: управление контекстом, защиту от prompt injection, работу с длинными контекстами и построение безопасного пайплайна входа для AI-систем — Михаил Бондаревский покажет, как подготовить инфраструктуру для AI-агентов: Docker, sandboxing, streaming, docker-compose и воспроизводимое окружение для разработки и продакшена — Мурат Хажгериев расскажет про Enterprise Integrations & MCP: когда MCP действительно нужен, как подключать внешние сервисы и реализовывать интеграции с OAuth2 delegation — Герман Сабиров разберет Governance & Compliance для AI-систем: data flow, audit logs, требования 152-ФЗ, локализацию данных и построение compliance-подхода на уровне архитектуры Курс для backend-разработчиков, тимлидов и LLM инженеров о том, как внедрять AI-логику в бэкенд IT-продуктов и сохранять стабильность сервиса. 👉 Изучить обновленную программу AgentOps и занять место.

🧑‍💻 Один middleware режет ответ в десять раз Большой JSON без сжатия это лишние мегабайты по сети. На быстром канале незаметно, а пользователь на мобильном интернете ждёт лишние секунды. Лечится одним middleware, который сжимает ответ перед отправкой. Как это работает GZIP хорошо жмёт текст с повторяющимися структурами, а JSON именно такой. Клиент говорит, что умеет принимать сжатое, через заголовок Accept-Encoding: gzip. Сервер сжимает тело, ставит Content-Encoding: gzip и отдаёт. Клиент распаковывает сам, его код менять не нужно. Middleware Проверяем заголовок клиента, оборачиваем ResponseWriter в gzip.Writer и пропускаем через него ответ хендлера:
func gzipMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
            next.ServeHTTP(w, r)
            return
        }

        w.Header().Set("Content-Encoding", "gzip")
        gz := gzip.NewWriter(w)
        defer gz.Close()

        gzr := gzipResponseWriter{Writer: gz, ResponseWriter: w}
        next.ServeHTTP(gzr, r)
    })
}

type gzipResponseWriter struct {
    http.ResponseWriter
    Writer *gzip.Writer
}

func (g gzipResponseWriter) Write(b []byte) (int, error) {
    return g.Writer.Write(b)
}
Подключаем к нужному эндпоинту:
mux.Handle("/data", gzipMiddleware(http.HandlerFunc(dataHandler)))
Проверяем размер ответа:
curl http://localhost:8080/data --output raw.json
curl -H "Accept-Encoding: gzip" http://localhost:8080/data --output gz.json
ls -lh raw.json gz.json
Когда не стоит Уже сжатые форматы вроде JPEG, PNG или ZIP жать заново смысла нет, размер почти не упадёт, а CPU потратите. Совсем мелкие ответы тоже лучше не трогать, накладные расходы перевесят. GZIP в Go это одно middleware и пара заголовков. Клиент менять не надо, а текстовый ответ ужимается в разы. В продакшене удобно взять готовый gziphandler или включить сжатие на reverse proxy, но понимать, как оно устроено, полезно в любом случае. 📍 Навигация: ВакансииЗадачиСобесыКанал в Max 🐸 Библиотека Go-разработчика #GoDeep

❤️‍🔥 Причина полюбить Go В командах время уходит не только на логику, но и на споры о стиле. Табы или пробелы, где ставить с
❤️‍🔥 Причина полюбить Go В командах время уходит не только на логику, но и на споры о стиле. Табы или пробелы, где ставить скобку, чей конфиг линтера правильнее. Ценности это не приносит, а силы на ревью отнимает. Go закрывает вопрос на уровне инструментов. Один стиль на всех В Go есть стандартный форматтер gofmt. Он не настраивается, опций про отступы и скобки у него нет, потому что стиль уже определён за вас. Любой код после gofmt выглядит одинаково в любом проекте. Обсуждать нечего. Неаккуратный, но рабочий код:
func main(){
x:=10
if x>5{
fmt.Println("big")
}
}
После gofmt:
func main() {
  x := 10
  if x > 5 {
    fmt.Println("big")
  }
}
Запуск по всему проекту:
gofmt -w .
Импорты делает goimports Рядом есть goimports. Он форматирует так же, но ещё правит импорты. Убирает то, что вы перестали использовать, и добавляет нужное. В Go это важно, потому что неиспользуемый импорт не предупреждение, а ошибка компиляции. То есть инструмент реально помогает коду собраться.
goimports -w .
Хороший опыт в редакторе В VSCode и других редакторах это работает на сохранение файла. Вы пишете, жмёте сохранить, код уже отформатирован, импорты подчищены. Отдельный шаг не нужен. Похожие форматтеры есть и в других языках, тот же Prettier или Black. Разница в том, что в Go это часть стандартного подхода, а не выбор команды среди десятка настроек. Один инструмент, один стиль, ноль споров. 💬 За что вы любите Go? Подписаны на нашу рассылку? 📍 Навигация: ВакансииЗадачиСобесыКанал в Max 🐸 Библиотека Go-разработчика #GoTalk

💡 Go может разрешить превращать функции в интерфейсы с одним методом В трекере Go обсуждают предложение #47487. Оно разрешает приводить значение функции к интерфейсу с ровно одним методом, если сигнатура функции совпадает с сигнатурой этого метода. На момент обсуждения предложение помечено как likely accept. Это значит, что склонны принять, но сначала хотят прототип и эксперименты. Сейчас, чтобы замыкание реализовало интерфейс, приходится заводить отдельный тип с методом. Классический пример из стандартной библиотеки это http.HandlerFunc. Шаблон выглядит так:
type FooerFunc func(A, B) (C, D)

func (f FooerFunc) Foo(a A, b B) (C, D) {
    return f(a, b)
}
Когда нужен, например, io.Writer, который считает записанные байты, обычно пишут структуру с полем и методом Write. Кода становится больше, чем сути, а единственная важная строка теряется среди обвязки. Что предлагают Предложение даёт писать то же самое через приведение функции к интерфейсу напрямую:
var N int64
cw := io.Writer(func(p []byte) (n int, err error) {
    n, err = os.Stdout.Write(p)
    N += int64(n)
    return n, err
})
Важная деталь в том, что это именно явное приведение, а не неявное присваивание. У io.Reader и io.Writer одинаковая сигнатура метода, поэтому неявное превращение было бы опасным. Явное приведение снимает двусмысленность, ведь вы сами указываете, чем должна стать функция. По задумке компилятор сам сгенерирует скрытый именованный тип с неэкспортируемым именем, который и несёт метод. Менять reflect, инструменты или работу с type assertion при этом не нужно. Более того, функцию можно положить прямо в таблицу методов, и тогда лишних накладных расходов на обёртку не будет. Альтернатива В обсуждении всплыл и более общий вариант. Это интерфейсные литералы из #25860, где интерфейс собирают из нескольких замыканий, по одному на каждый метод:
cw := io.Writer{
    Write: func(p []byte) (n int, err error) {
        // ...
    },
}
Такой вариант не ограничен одним методом, но его заметно сложнее встроить в текущий язык. Часть участников переживает, что появится ещё один способ писать одно и то же, и это размывает консистентность Go, за которую язык и ценят. Решение пока не финальное, но направление выбрано. Если предложение примут, обвязочных типов вроде http.HandlerFunc в коде станет заметно меньше. 📍 Навигация: ВакансииЗадачиСобесыКанал в Max 🐸 Библиотека Go-разработчика #GoLive

👀 9 правил микросервисной архитектуры На схеме 9 "золотых" правил. А вот про некоторые: Separate data store — У каждого серв
👀 9 правил микросервисной архитектуры На схеме 9 "золотых" правил. А вот про некоторые: Separate data store — У каждого сервиса своя база. Итог: независимость, но ад при попытке сделать общую аналитику. Single responsibility — Один сервис, одна задача. Итог: чистая логика, но если переборщить, получишь сотни мелких скриптов, которые невозможно отследить. Treat servers as stateless — Сервер не должен ничего помнить о прошлых запросах. Итог: легкое масштабирование, но всю логику сессий приходится выносить во внешние хранилища. Domain-driven design (DDD) — Строим архитектуру вокруг бизнес-задач. Итог: код понятен бизнесу, но проектирование занимает в разы больше времени. Orchestrating microservices — Используем Kubernetes для управления. Итог: автоматизация деплоя, но порог входа в инфраструктуру улетает в космос. Проблема в том, что красивые чек-листы не учат дебажить распределенные системы. Нужно понимать, когда стоит внедрять эти правила, а когда они просто сожрут твой бюджет. Соблюдаете все 9 правил в своих проектах? ❤️ — стараемся следовать базе 🔥 — пилим как быстрее, а не "по книжке" 🔹 Практический интенсив «Архитектуры и шаблоны проектирования» 🔹 Получить консультацию менеджера 🔹 Сайт Академии 🔹 Сайт Proglib 🏃‍♀️ Азбука айтишника #ликбез

🤩 Краулер для разведки по веб приложениям Обычный краулер видит сырой HTML и пропускает всё, что появляется уже в DOM. Katan
🤩 Краулер для разведки по веб приложениям Обычный краулер видит сырой HTML и пропускает всё, что появляется уже в DOM. Katana от команды ProjectDiscovery решает эту задачу. Это краулер на Go, который собирает ссылки и эндпоинты, в том числе из JS, и умеет ходить по сайту через настоящий браузер. Katana принимает на вход один URL, список из файла или поток через stdin, обходит цель и отдаёт найденные эндпоинты в текст, файл или JSON. У него два режима работы: • Стандартный использует обычный HTTP клиент Go и работает быстро, но видит только сырой ответ. • Режим headless поднимает Chrome, выполняет JavaScript и находит эндпоинты, которые появляются после рендера или асинхронных запросов. Дополнительно инструмент парсит ссылки внутри JS файлов, умеет автоматически заполнять формы, контролирует область обхода через scope и regex, фильтрует вывод по расширениям и условиям. Есть встроенное определение технологий и обход с авторизацией через свои заголовки или куки. Как это работает Базовый запуск по одной цели:
katana -u https://example.com
Список целей из файла:
katana -list urls.txt
Поток через pipe, например из httpx:
echo https://example.com | katana
Режим headless с разбором JavaScript находит больше эндпоинтов на динамических сайтах:
katana -u https://example.com -headless -jc
Контроль области обхода. Флаг -fs dn держит краулер в пределах домена по ключевому слову:
katana -u https://example.com -fs dn
Вывод в JSON с записью в файл удобен для дальнейшей обработки в пайплайне:
katana -u https://example.com -jsonl -o endpoints.jsonl
Запускать Katana можно и как библиотеку Go. Создаёте структуру Options, передаёте те же параметры, что и в CLI, и вызываете метод Crawl. Колбэк OnResult получает каждый найденный результат:
options := &types.Options{
    MaxDepth:    3,
    FieldScope:  "rdn",
    Concurrency: 10,
    Strategy:    "depth-first",
    OnResult: func(result output.Result) {
        gologger.Info().Msg(result.Request.URL)
    },
}
crawlerOptions, _ := types.NewCrawlerOptions(options)
crawler, _ := standard.New(crawlerOptions)
crawler.Crawl("https://example.com")
Кому пригодится Katana пригодится пентестерам, специалистам по bug bounty и инженерам по безопасности для сбора поверхности атаки. Инструмент собирает пути, параметры и файлы, из которых потом строят словари и списки целей для других сканеров. Важно помнить, что краулер шлёт реальные запросы к цели. Запускайте его только по тем доменам, на тестирование которых у вас есть разрешение. Если работаете с разведкой по вебу и сидите на стеке ProjectDiscovery, Katana встаёт в пайплайн рядом с subfinder и httpx. Быстрый стандартный режим закрывает простые сайты, headless вытягивает динамику. ➡️ Репозиторий 📍 Навигация: ВакансииЗадачиСобесыКанал в Max 🐸 Библиотека Go-разработчика #GoToProduction