Библиотека Go-разработчика | Golang
Все самое полезное для Go-разработчика в одном канале. По рекламе: @proglib_adv Учиться у нас: https://proglib.io/w/32d20779 Для обратной связи: @proglibrary_feeedback_bot РКН: https://gosuslugi.ru/snet/67a4a8c24689c2151c752af0 #WXSSA
Больше📈 Аналитический обзор Telegram-канала Библиотека Go-разработчика | Golang
Канал Библиотека Go-разработчика | Golang (@goproglib) языкового сегмента Русский является активным участником. Сейчас сообщество объединяет 24 000 подписчиков, занимая 5 685 место в категории Технологии и приложения и 27 924 место в регионе Россия.
📊 Показатели аудитории и динамика
С момента создания невідомо проект демонстрирует стремительный рост, собрав аудиторию из 24 000 подписчиков.
Согласно последним данным от 10 июня, 2026, канал показывает стабильную активность. За последние 30 дней изменение числа участников составило 55, а за последние 24 часа — -4, при этом общий охват остаётся высоким.
- Статус верификации: Не верифицирован
- Уровень вовлечённости (ER): Средний показатель вовлечённости аудитории составляет 10.61%. В первые 24 часа после публикации контент обычно набирает 7.66% реакций от общего числа подписчиков.
- Охват публикаций: В среднем каждый пост получает 2 547 просмотров. В течение первых суток публикация набирает 1 839 просмотров.
- Реакции и взаимодействия: Аудитория активно поддерживает контент: среднее количество реакций на один пост — 8.
- Тематические интересы: Контент сосредоточен на ключевых темах, таких как навигация, лучшее_из_библиотеки_2025, git, string, golive.
📝 Описание и контентная политика
Автор описывает ресурс как площадку для выражения субъективного мнения:
“Все самое полезное для Go-разработчика в одном канале.
По рекламе: @proglib_adv
Учиться у нас: https://proglib.io/w/32d20779
Для обратной связи: @proglibrary_feeedback_bot
РКН: https://gosuslugi.ru/snet/67a4a8c24689c2151c752af0
#WXSSA”
Благодаря высокой частоте обновлений (последние данные получены 11 июня, 2026) канал поддерживает актуальность и высокий уровень охвата публикаций. Аналитика показывает, что аудитория активно взаимодействует с контентом, что делает его важной точкой влияния в категории Технологии и приложения.
Загрузка данных...
| Дата | Привлечение подписчиков | Упоминания | Каналы | |
| 11 июня | +4 | |||
| 10 июня | +3 | |||
| 09 июня | +8 | |||
| 08 июня | +1 | |||
| 07 июня | +7 | |||
| 06 июня | +2 | |||
| 05 июня | +10 | |||
| 04 июня | +4 | |||
| 03 июня | +7 | |||
| 02 июня | +8 | |||
| 01 июня | +5 |
| 2 | 🔄 pgCenter 0.10.0, поддержка Postgres 15–18 и переход на pgx/v5
Вышел релиз v0.10.0 консольной утилиты pgcenter для наблюдения за Postgres. Это в основном обновление совместимости и безопасности, новых экранов в интерфейсе не добавили.
Главное изменение это поддержка Postgres от 15 до 18. Запросы статистики обновили под формат версии 17, прогон тестов идёт на ветках с 14 по 18. Под капотом утилита перешла на драйвер pgx/v5, обновилась до Go 1.25.10 и закрыла накопившиеся уязвимости в зависимостях.
Часть правок касается устойчивости и вывода:
• Теперь pgcenter проверяет, включён ли pg_stat_statements в shared_preload_libraries, и больше не зависает, если расширение установлено в базе, но не активировано в конфигурации.
• Длинные значения application_name из pg_stat_activity перестали обрезаться.
• Адрес клиента в pg_stat_activity и pg_stat_replication теперь оборачивается в функцию host(), поэтому в выводе нет лишней маски подсети.
Если вы уже пользуетесь pgcenter на свежих версиях Postgres, обновление снимает проблемы совместимости и убирает известные CVE.
➡️ Репозиторий
📍 Навигация: Вакансии • Задачи • Собесы • Канал в Max
🐸 Библиотека Go-разработчика
#GoLive | 1 678 |
| 3 | 🥺 Big money вакансии для Go-разработчиков за неделю
Middle / Senior Бэкенд разработчик — до 405 000 $ (в год) — удаленно по Сан-Франциско
Golang-разработчик — до 400 000 ₽ в офис или удаленно (Москва)
➡️ Еще больше топовых вакансий — в нашем канале Go jobs
🐸 Библиотека Go-разработчика
#GoWork | 2 086 |
| 4 | 📎 Почему цепочка middleware ломает безопасность, даже когда каждый обработчик корректен
Стек middleware разрастается до десятка с лишним обработчиков. Каждый написан осознанно и протестирован, а ревью всё равно находит обход аутентификации. Дыра не внутри обработчика, а в порядке их выполнения.
👉 Почему так происходит
Порядок обычно складывается стихийно. Обработчики добавляют по мере задач, и очерёдность повторяет хронологию, а не смысл. Кто добавлен раньше, тот снаружи. При этом влияние нового обработчика на безопасность всей цепочки никто не проверяет.
В итоге порядок принимает решения, которые никто явно не принимал. Когда срабатывает аутентификация, может ли запрос получить ответ до неё, кто видит личность в контексте. Эта политика нигде не записана и меняется при каждой перестановке.
👉 Как этого избежать
Разбейте цепочку на слои доверия и зафиксируйте, что внутри блока безопасности порядок обязателен:
// Слой безопасности, порядок обязателен
// авторизации нужна личность из контекста
// аутентификации нужен резолв тенанта из контекста
handler = authorizationMiddleware(handler)
handler = authenticationMiddleware(handler)
handler = tenantMiddleware(handler)
Запретите ранний выход до аутентификации. Ни один обработчик выше блока безопасности не должен сам возвращать неошибочный ответ. Быстрый ответ на health check выносите на отдельный неаутентифицированный маршрут.
Сделайте порядок проверяемым в CI. Пусть пайплайн отклоняет PR, который переставляет обработчики внутри блока безопасности без явного ревью. Тогда комментарии о порядке работают как ограничение, а не пожелание.
Тестируйте цепочку целиком. Юнит тесты не ловят такие дыры, потому что баг живёт во взаимодействии. Нужны сквозные тесты на враждебные комбинации заголовков, путей и параметров.
Полезнее спрашивать не про то, корректен ли каждый middleware, а про то, что цепочка считает истинным к моменту запуска каждого обработчика. Держите порядок явным, проверяемым и покрытым тестами на всю цепочку сразу.
📍 Навигация: Вакансии • Задачи • Собесы • Канал в Max
🐸 Библиотека Go-разработчика
#GoDeep | 2 027 |
| 5 | 💻 top для Postgres прямо в терминале
Postgres отдаёт массу статистики о своей работе. Активные сессии, запросы, репликация, блокировки, обращения к таблицам и индексам, прогресс вакуума. Всё это лежит в системных представлениях вроде pg_stat_activity и pg_stat_statements.
Беда в том, что родного инструмента для удобной работы с этой статистикой у Postgres нет. Приходится держать в голове десятки запросов и руками дёргать представления через psql. Написанный на Go, pgCenter показывает статистику в живом интерфейсе, похожем на top.
🖇 Что он умеет
Основная команда pgcenter top обновляет метрики в реальном времени и переключается между экранами по горячим клавишам.
Видно сводку по базе, активность клиентов из pg_stat_activity, тяжёлые запросы из pg_stat_statements, состояние репликации, обращения к таблицам и индексам, прогресс операций вроде VACUUM, CREATE INDEX и COPY.
Рядом идёт системная статистика, собранная из procfs. Это load average, загрузка CPU, память и swap, нагрузка на диски и сеть.
Отдельно полезен экран по процессам, он открывается по Shift+S. Там pgcenter склеивает данные из pg_stat_activity с метриками каждого бэкенда из /proc/[pid]/stat и /proc/[pid]/io. Сразу видно, во что упёрся медленный запрос, в процессор или в диск, без выхода из утилиты. Экран работает только в локальном режиме.
🖇Как запустить
Проще всего через Docker:
docker pull lesovsky/pgcenter:latest
docker run -it --rm lesovsky/pgcenter:latest pgcenter top -h 1.2.3.4 -U user -d dbname
Если ставите пакетом, под DEB, RPM и APK есть готовые сборки на странице релизов.
После установки запуск выглядит так:
pgcenter top -h 127.0.0.1 -U postgres -d mydb
Кроме живого режима есть запись статистики на будущее. Команда pgcenter record складывает метрики в файлы, а pgcenter report строит из них отчёты для разбора уже после инцидента.
Метрики по процессам тоже пишутся, и их можно проиграть через pgcenter report -N. Ещё внутри есть профайлер событий ожидания, просмотр и правка конфигов с перезагрузкой сервиса, а также чтение логов Postgres без остановки мониторинга.
🖇 Пара ограничений
Утилита рассчитана на Linux и на других системах работать не будет. Для полного доступа к статистике нужны права SUPERUSER либо роли для чтения метрик и логов. С удалённым Postgres и с Amazon RDS часть функций недоступна, потому что туда не попадает системная статистика хоста.
➡️ Репозиторий
📍 Навигация: Вакансии • Задачи • Собесы • Канал в Max
🐸 Библиотека Go-разработчика
#GoToProduction | 2 038 |
| 6 | 🔥 Приглашаем на бесплатный открытый вебинар курса «Высоконагруженные системы: архитектура и масштабирование»:
«Асинхронная обработка данных в высоконагруженных системах»
🗓 Когда: 16 июня, 20:00 (мск)
На вебинаре разберём, как грамотно внедрять асинхронность и строить по-настоящему производительные системы.
Что будет на вебинаре:
— Зачем и когда переходить на асинхронную обработку данных в высоконагруженных проектах
— Очереди сообщений, веб-сокеты и другие инструменты асинхронного взаимодействия
— Реальный архитектурный кейс: от веб-сервера до брокера сообщений и базы данных
— Типичные узкие места асинхронных систем и проверенные способы их устранения
👉 Зарегистрироваться: https://otus.ru/lessons/highloadarchitect/?utm_source=telegram&utm_medium=cpm&utm_campaign=hl&utm_term=goproglib&utm_content=mql-lesson-16-06-2026_test_usp-universal_hl_text_no-headline_text_long_aibanner_lesson-banner_white_standart#event-7191
Бесплатное занятие приурочено к курсу «Высоконагруженные системы: архитектура и масштабирование», где вы научитесь проектировать высоконагруженные системы, способные выдерживать экстремальные нагрузки и работать стабильно в любых условиях.
🎁При покупке курса вы получите в подарок мини-курс по Kafka, который поможет подготовиться к собеседованию в бигтех
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576 | 1 900 |
| 7 | 🧑💻 Зачем мьютекс в uuid, если UUID не хранят состояние
В исходниках пакета uuid рядом с генерацией UUIDv7 лежит мьютекс уровня пакета и переменная с временем последнего вызова. UUID считаются значениями без состояния, поэтому блокировка выглядит лишней. Разберём, зачем она там.
Первые 48 бит UUIDv7 это метка времени в миллисекундах. Поэтому такие значения сортируются по времени создания и удобны как ключи в базе. Но внутри одной миллисекунды программа создаёт тысячи идентификаторов с одинаковой меткой, и без счётчика их порядок стал бы случайным.
Пакет хранит последнее выданное время вместе со счётчиком в lastV7time и проверяет, что новое значение строго больше прошлого:
func getV7Time() (milli, seq int64) {
timeMu.Lock()
defer timeMu.Unlock()
nano := timeNow().UnixNano()
milli = nano / nanoPerMilli
seq = (nano - milli*nanoPerMilli) >> 8
now := milli<<12 + seq
if now <= lastV7time {
now = lastV7time + 1
milli = now >> 12
seq = now & 0xfff
}
lastV7time = now
return milli, seq
}
Если посчитанное время не больше прошлого, функция берёт lastV7time + 1. Так порядок держится даже при переводе часов назад, просто встроенная метка ненадолго разойдётся с реальной.
Мьютекс нужен потому, что NewV7 зовут из разных горутин, а lastV7time одна на весь пакет. Используется общий timeMu, тот же, что защищает время старых версий UUID.
Состояние живёт в одном процессе. Между несколькими машинами строгий порядок внутри миллисекунды не гарантирован, хотя сортировка по времени всё равно работает.
📍 Навигация: Вакансии • Задачи • Собесы • Канал в Max
🐸 Библиотека Go-разработчика
#GoDeep | 1 901 |
| 8 | 🌴 Деревья поиска на Go: вставка, поиск, удаление
BST — двоичное дерево поиска. Простая идея: левый потомок всегда меньше родителя, правый — больше. Это даёт поиск за O(log n), но только если дерево сбалансировано. Об этом — в конце поста.
Структура узла
type Node struct {
Val int
Left *Node
Right *Node
}
type BST struct {
Root *Node
}
Вставка
Идём по дереву вниз: если значение меньше текущего узла — налево, больше — направо. Когда упёрлись в nil — вставляем:
func (t *BST) Insert(val int) {
t.Root = insert(t.Root, val)
}
func insert(node *Node, val int) *Node {
if node == nil {
return &Node{Val: val}
}
if val < node.Val {
node.Left = insert(node.Left, val)
} else if val > node.Val {
node.Right = insert(node.Right, val)
}
return node
}
Дубликаты здесь просто игнорируются. Можно добавить счётчик в узел, если нужно их хранить.
Поиск
Та же логика, что и вставка, но вместо создания узла возвращаем результат:
func (t *BST) Search(val int) bool {
return search(t.Root, val)
}
func search(node *Node, val int) bool {
if node == nil {
return false
}
if val == node.Val {
return true
}
if val < node.Val {
return search(node.Left, val)
}
return search(node.Right, val)
}
Удаление
Три случая:
- узел без потомков — просто удаляем
- узел с одним потомком — заменяем им
- узел с двумя потомками — находим минимальный элемент правого поддерева (in-order successor), ставим его на место удалённого
func (t *BST) Delete(val int) {
t.Root = deleteNode(t.Root, val)
}
func deleteNode(node *Node, val int) *Node {
if node == nil {
return nil
}
if val < node.Val {
node.Left = deleteNode(node.Left, val)
} else if val > node.Val {
node.Right = deleteNode(node.Right, val)
} else {
if node.Left == nil {
return node.Right
}
if node.Right == nil {
return node.Left
}
// Находим минимум в правом поддереве
min := findMin(node.Right)
node.Val = min.Val
node.Right = deleteNode(node.Right, min.Val)
}
return node
}
func findMin(node *Node) *Node {
for node.Left != nil {
node = node.Left
}
return node
}
Обходы
Три классических варианта, каждый даёт узлы в разном порядке:
// In-order: левый → корень → правый (отдаёт отсортированный список)
func inOrder(node *Node) {
if node == nil {
return
}
inOrder(node.Left)
fmt.Println(node.Val)
inOrder(node.Right)
}
// Pre-order: корень → левый → правый (удобен для копирования дерева)
func preOrder(node *Node) {
if node == nil {
return
}
fmt.Println(node.Val)
preOrder(node.Left)
preOrder(node.Right)
}
// Post-order: левый → правый → корень (удобен для удаления дерева)
func postOrder(node *Node) {
if node == nil {
return
}
postOrder(node.Left)
postOrder(node.Right)
fmt.Println(node.Val)
}
Где ломается BST
Если вставлять элементы по порядку — 1, 2, 3, 4, 5 — дерево вырождается в связный список. Поиск становится O(n) вместо O(log n):
1
\
2
\
3
\
4
\
5
Именно для этого придумали самобалансирующиеся деревья.
💬 Разбирать механизм, который не даёт дереву деградировать?
📍 Навигация: Вакансии • Задачи • Собесы • Канал в Max
🐸 Библиотека Go-разработчика
#ReadySetGo | 1 839 |
| 9 | 🗑 Сборщик мусора видно прямо в терминале
Растут задержки в Go-сервисе? Обычно включают GODEBUG=gctrace=1 и втыкают в простыню логов в stderr. Поймать там всплеск STW-паузы или понять, что GC стал срабатывать чаще после правок, почти нереально.
gcscope рисует это вживую. Терминальный TUI показывает GC-циклы, STW-паузы, рост кучи (live/goal) и сигналы pacer в реальном времени.
Попробовать демо
Встроенная демо-нагрузка, ничего ставить не надо.
go run ./cmd/gcscope lab churn
➡️ На своём коде
Собираем бинарник и запускаем под наблюдением.
go build -o ./myapp ./cmd/myapp
gcscope run ./myapp -- --your-flag value
Код приложения менять не нужно. Всё после -- уходит в вашу программу.
➡️ Что ещё умеет
Режим attach цепляется к живому сервису по HTTP через runtime/metrics. Режим diff сравнивает два snapshot-файла и показывает разницу по heap и STW между запусками. Историю можно листать на паузе, графики зумить, состояние сохранять в JSON клавишей s.
Ставится одной командой:
go install github.com/timur-developer/gcscope/cmd/gcscope@latest
➡️ Репозиторий
📍 Навигация: Вакансии • Задачи • Собесы • Канал в Max
🐸 Библиотека Go-разработчика
#GoToProduction | 2 277 |
| 10 | ✏️ Переменная цикла своя на каждой итерации
В Go переменная цикла for ... range создаётся заново на каждой итерации. Это снимает одну из самых частых проблем при работе с горутинами и замыканиями, когда несколько функций случайно ссылаются на одно и то же значение. Разберём как этим пользоваться.
Замыкание захватывает не значение переменной, а саму переменную. Если бы v была одна на весь цикл, все запущенные горутины ссылались бы на общую ячейку и видели бы её последнее значение.
Поскольку в Go у каждой итерации своя v, такого не происходит:
for _, v := range data {
go func() { fmt.Println(v) }()
}
Каждая горутина печатает значение своей итерации, а не последний элемент data. Никаких обходных приёмов внутри тела цикла для этого не нужно.
На каждом проходе компилятор заводит новую переменную и копирует в неё текущее значение. Замыкание, которое вы создаёте внутри тела, привязывается именно к этой копии. Когда итерация заканчивается, её переменная остаётся жить ровно столько, сколько на неё ссылаются запущенные функции.
То же касается и индекса в форме с двумя переменными:
for i, v := range items {
go func() {
fmt.Println(i, v)
}()
}
И i, и v уникальны для каждого прохода, поэтому пара значений всегда соответствует своей итерации.
Поведение привязано к версии языка в директиве go файла go.mod. Оно действует, когда там указано go 1.22 или выше. Если в модуле прописана версия старше, тот же код соберётся со старой семантикой даже на новом компиляторе. Так одна и та же кодовая база ведёт себя предсказуемо, а апгрейд тулчейна не меняет логику молча.
ℹ️ О чём помнить
Копия создаётся под каждую итерацию, но это именно копия значения. Если в v лежит срез или указатель, копируется он, а не данные за ним, и общий доступ к этим данным из горутин по-прежнему требует синхронизации. Свойство решает проблему захвата переменной, а не гонок по самим данным.
Опираться на это можно в любом коде, где замыкания и горутины создаются внутри for ... range. Значение каждой итерации остаётся при ней, и писать переобъявление внутри тела больше не требуется.
📍 Навигация: Вакансии • Задачи • Собесы • Канал в Max
🐸 Библиотека Go-разработчика
#GoDeep | 2 177 |
| 11 | 📍 Навигация: Вакансии • Задачи • Собесы • Канал в Max
🐸 Библиотека Go-разработчика
#GoGiggle | 2 241 |
| 12 | 🔥 Инженерная методичка по ИИ от Романа Барлоса (Team Lead в Yandex Cloud)
Продолжаем делиться экспертизой команды курса «Разработка ИИ-агентов».
Роман собрал мастхев-инструменты и ключевые работы для тех, кто хочет выйти за рамки вайбкодинга.
🛠️ Полезные инструменты:
• Understand Anything — граф знаний по коду и зависимостям.
• DeepTutor — open-source платформа для персонализированного обучения.
• Superpowers — набор практик для системной разработки с ИИ.
• Awesome Agent Skills — коллекция навыков для ИИ-агентов.
📚 Ключевые работы по LLM:
• Attention Is All You Need (2017) — архитектура Transformer.
• GPT-1 (2018) — начало эпохи GPT.
• GPT-2 (2019) — решение новых задач без дообучения.
• GPT-3 (2020) — обучение на примерах из запроса.
• InstructGPT (2022) — RLHF и современные чат-боты.
На курсе Роман выступает консультантом программы: помогает формировать содержание уроков с опорой на актуальные инженерные практики».
Занять свое место на потоке:
👉 Курс «Разработка ИИ-агентов» | 2 191 |
| 13 | 🤩 Разбор строк через strings.Cut
Часто строку нужно разрезать ровно один раз по разделителю. Так делят почту на имя и домен, заголовок на ключ и значение, путь на префикс и остаток.
Раньше для этого брали strings.Index или strings.Split, и оба варианта тянули за собой лишний код с проверкой границ. В Go 1.18 появился strings.Cut, который закрывает этот случай одной строкой.
strings.Index возвращает позицию разделителя или -1, если его нет. Дальше нужно вручную проверять результат и аккуратно нарезать строку по смещениям, не выходя за границы.
Старый способ:
i := strings.Index(email, "@")
if i < 0 {
return "", "", false
}
username := email[:i]
domain := email[i+1:]
Три строки на нарезку плюс отдельная проверка на -1. Если забыть про +1, в домен попадёт сам символ разделителя.
Современный способ:
username, domain, found := strings.Cut(email, "@")
Функция возвращает часть до разделителя, часть после него и флаг found. Если разделителя нет, found будет false, а первой частью вернётся вся исходная строка.
Чем отличается от `strings.Split`
strings.Split режет строку по всем вхождениям и возвращает срез. Когда разрез нужен один, приходится брать SplitN с лимитом и потом разбирать срез по индексам. strings.Cut сразу отдаёт две именованные части и не выделяет срез под результат, поэтому работает экономнее.
Практический пример
Разбор строки заголовка вида Content-Type: application/json выглядит так:
key, value, ok := strings.Cut(header, ": ")
if !ok {
return fmt.Errorf("invalid header: %q", header)
}
key = strings.TrimSpace(key)
value = strings.TrimSpace(value)
Флаг ok сразу отделяет корректные строки от мусора, без ручной возни с индексами.
Используйте strings.Cut везде, где строку нужно разделить ровно один раз, а Split оставьте для случаев с множеством вхождений. Код станет короче, а ошибок с границами среза не будет.
📍 Навигация: Вакансии • Задачи • Собесы • Канал в Max
🐸 Библиотека Go-разработчика
#GoToProduction | 2 158 |
| 14 | 📰 Первый летний дайджест
Короткий, как и отпуск..
— Go закрыл три уязвимости
Вышли версии Go 1.26.4 и 1.25.11. Закрывают три уязвимости в стандартной библиотеке.
— Go может разрешить превращать функции в интерфейсы с одним методом
В трекере Go обсуждают предложение #47487. Оно разрешает приводить значение функции к интерфейсу с ровно одним методом, если сигнатура функции совпадает с сигнатурой этого метода.
📍 Навигация: Вакансии • Задачи • Собесы • Канал в Max
🐸 Библиотека Go-разработчика
#GoLive | 2 417 |
| 15 | 🧑💻 Конструктор, из которого собран 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 | 2 314 |
| 16 | Попросил нейронку написать счётчик сотрудников..
📍 Навигация: Вакансии • Задачи • Собесы • Канал в Max
🐸 Библиотека Go-разработчика
#GoGiggle | 2 517 |
| 17 | 📎 Чего не дают логи, метрики и трейсы
Идея «три столпа наблюдаемости» звучит убедительно. Соберите логи, метрики и трейсы, отправьте в одну платформу, и поймёте систему. На практике у команды есть все три, а баг в проде она всё равно не находит. Ниже главные мысли статьи о том, почему так выходит, с примерами на 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 | 2 274 |
| 18 | 😎 Знакомьтесь с экспертом 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-канале
На курсе Роман выступает консультантом программы: он помогает формировать содержание уроков с опорой на актуальные инженерные практики и жесткие требования индустрии.
Узнать больше о программе и разработке автономных систем:
👉 Курс «Разработка ИИ-агентов»
Так, продолжаем знакомить вас с командой?
👍 — Да, ждем новых лиц
🔥 — Жду полезные материалы от Романа | 2 269 |
| 19 | ❓ Можно ли использовать слайс как ключ в мапе
Вопрос на первый взгляд простой, но именно такие мелочи отделяют тех, кто Go использует, от тех, кто Go понимает.
Прежде чем лезть в документацию — подумайте сами. Вот что стоит вспомнить:
🔹 В Go ключ мапы должен быть comparable — то есть поддерживать операции == и !=
🔹 Спросите себя: можно ли сравнить два слайса через ==? Что вообще значит «два слайса равны»?
➡️ Ответ
📍 Навигация: Вакансии • Задачи • Собесы • Канал в Max
🐸 Библиотека Go-разработчика
#ReadySetGo | 2 542 |
| 20 | 📎 Обёртывание ошибок через %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 | 2 653 |
Уже доступно! Исследование Telegram 2025 — ключевые инсайты года 
