Библиотека 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 004 підписників, посідаючи 5 688 місце в категорії Технології та додатки та 27 925 місце у регіоні Росія.
📊 Показники аудиторії та динаміка
З моменту свого створення невідомо, проект продемонстрував стрімке зростання, зібравши аудиторію у 24 004 підписників.
За останніми даними від 09 червня, 2026, канал демонструє стабільну активність. Хоча за останні 30 днів спостерігається зміна кількості учасників на 54, а за останні 24 години на 1, загальне охоплення залишається високим.
- Статус верифікації: Не верифікований
- Рівень залученості (ER): Середній показник залученості аудиторії становить 10.58%. Протягом перших 24 годин після публікації контент зазвичай збирає 7.65% реакцій від загальної кількості підписників.
- Охоплення публікацій: В середньому кожен допис отримує 2 539 переглядів. Протягом першої доби публікація в середньому набирає 1 837 переглядів.
- Реакції та взаємодія: Аудиторія активно підтримує контент: середня кількість реакцій на один пост – 8.
- Тематичні інтереси: Контент зосереджений навколо ключових тем, таких як навигация, лучшее_из_библиотеки_2025, git, string, golive.
📝 Опис та контентна політика
Автор описує ресурс як майданчик для висловлення суб'єктивної думки:
“Все самое полезное для Go-разработчика в одном канале.
По рекламе: @proglib_adv
Учиться у нас: https://proglib.io/w/32d20779
Для обратной связи: @proglibrary_feeedback_bot
РКН: https://gosuslugi.ru/snet/67a4a8c24689c2151c752af0
#WXSSA”
Завдяки високій частоті оновлень (останні дані отримано 10 червня, 2026), канал підтримує актуальність та високий рівень охоплення публікацій. Аналітика показує, що аудиторія активно взаємодіє з контентом, що робить його важливою точкою впливу в категорії Технології та додатки.
Триває завантаження даних...
| Дата | Залучення підписників | Згадування | Канали | |
| 10 червня | +3 | |||
| 09 червня | +8 | |||
| 08 червня | +1 | |||
| 07 червня | +7 | |||
| 06 червня | +2 | |||
| 05 червня | +10 | |||
| 04 червня | +4 | |||
| 03 червня | +7 | |||
| 02 червня | +8 | |||
| 01 червня | +5 |
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| 2 | 🥺 Big money вакансии для Go-разработчиков за неделю
Middle / Senior Бэкенд разработчик — до 405 000 $ (в год) — удаленно по Сан-Франциско
Golang-разработчик — до 400 000 ₽ в офис или удаленно (Москва)
➡️ Еще больше топовых вакансий — в нашем канале Go jobs
🐸 Библиотека Go-разработчика
#GoWork | 1 778 |
| 3 | 📎 Почему цепочка middleware ломает безопасность, даже когда каждый обработчик корректен
Стек middleware разрастается до десятка с лишним обработчиков. Каждый написан осознанно и протестирован, а ревью всё равно находит обход аутентификации. Дыра не внутри обработчика, а в порядке их выполнения.
👉 Почему так происходит
Порядок обычно складывается стихийно. Обработчики добавляют по мере задач, и очерёдность повторяет хронологию, а не смысл. Кто добавлен раньше, тот снаружи. При этом влияние нового обработчика на безопасность всей цепочки никто не проверяет.
В итоге порядок принимает решения, которые никто явно не принимал. Когда срабатывает аутентификация, может ли запрос получить ответ до неё, кто видит личность в контексте. Эта политика нигде не записана и меняется при каждой перестановке.
👉 Как этого избежать
Разбейте цепочку на слои доверия и зафиксируйте, что внутри блока безопасности порядок обязателен:
// Слой безопасности, порядок обязателен
// авторизации нужна личность из контекста
// аутентификации нужен резолв тенанта из контекста
handler = authorizationMiddleware(handler)
handler = authenticationMiddleware(handler)
handler = tenantMiddleware(handler)
Запретите ранний выход до аутентификации. Ни один обработчик выше блока безопасности не должен сам возвращать неошибочный ответ. Быстрый ответ на health check выносите на отдельный неаутентифицированный маршрут.
Сделайте порядок проверяемым в CI. Пусть пайплайн отклоняет PR, который переставляет обработчики внутри блока безопасности без явного ревью. Тогда комментарии о порядке работают как ограничение, а не пожелание.
Тестируйте цепочку целиком. Юнит тесты не ловят такие дыры, потому что баг живёт во взаимодействии. Нужны сквозные тесты на враждебные комбинации заголовков, путей и параметров.
Полезнее спрашивать не про то, корректен ли каждый middleware, а про то, что цепочка считает истинным к моменту запуска каждого обработчика. Держите порядок явным, проверяемым и покрытым тестами на всю цепочку сразу.
📍 Навигация: Вакансии • Задачи • Собесы • Канал в Max
🐸 Библиотека Go-разработчика
#GoDeep | 1 873 |
| 4 | 💻 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 | 1 968 |
| 5 | 🔥 Приглашаем на бесплатный открытый вебинар курса «Высоконагруженные системы: архитектура и масштабирование»:
«Асинхронная обработка данных в высоконагруженных системах»
🗓 Когда: 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 845 |
| 6 | 🧑💻 Зачем мьютекс в 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 838 |
| 7 | 🌴 Деревья поиска на 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 822 |
| 8 | 🗑 Сборщик мусора видно прямо в терминале
Растут задержки в 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 226 |
| 9 | ✏️ Переменная цикла своя на каждой итерации
В 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 162 |
| 10 | 📍 Навигация: Вакансии • Задачи • Собесы • Канал в Max
🐸 Библиотека Go-разработчика
#GoGiggle | 2 233 |
| 11 | 🔥 Инженерная методичка по ИИ от Романа Барлоса (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 182 |
| 12 | 🤩 Разбор строк через 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 115 |
| 13 | 📰 Первый летний дайджест
Короткий, как и отпуск..
— Go закрыл три уязвимости
Вышли версии Go 1.26.4 и 1.25.11. Закрывают три уязвимости в стандартной библиотеке.
— Go может разрешить превращать функции в интерфейсы с одним методом
В трекере Go обсуждают предложение #47487. Оно разрешает приводить значение функции к интерфейсу с ровно одним методом, если сигнатура функции совпадает с сигнатурой этого метода.
📍 Навигация: Вакансии • Задачи • Собесы • Канал в Max
🐸 Библиотека Go-разработчика
#GoLive | 2 174 |
| 14 | 🧑💻 Конструктор, из которого собран 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 231 |
| 15 | Попросил нейронку написать счётчик сотрудников..
📍 Навигация: Вакансии • Задачи • Собесы • Канал в Max
🐸 Библиотека Go-разработчика
#GoGiggle | 2 499 |
| 16 | 📎 Чего не дают логи, метрики и трейсы
Идея «три столпа наблюдаемости» звучит убедительно. Соберите логи, метрики и трейсы, отправьте в одну платформу, и поймёте систему. На практике у команды есть все три, а баг в проде она всё равно не находит. Ниже главные мысли статьи о том, почему так выходит, с примерами на 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 231 |
| 17 | 😎 Знакомьтесь с экспертом 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 261 |
| 18 | ❓ Можно ли использовать слайс как ключ в мапе
Вопрос на первый взгляд простой, но именно такие мелочи отделяют тех, кто Go использует, от тех, кто Go понимает.
Прежде чем лезть в документацию — подумайте сами. Вот что стоит вспомнить:
🔹 В Go ключ мапы должен быть comparable — то есть поддерживать операции == и !=
🔹 Спросите себя: можно ли сравнить два слайса через ==? Что вообще значит «два слайса равны»?
➡️ Ответ
📍 Навигация: Вакансии • Задачи • Собесы • Канал в Max
🐸 Библиотека Go-разработчика
#ReadySetGo | 2 504 |
| 19 | 📎 Обёртывание ошибок через %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 640 |
| 20 | 🫳 Типичная микросервисная архитектура 🫳
Постоянно слышу, что монолит - это прошлое, а микросервисы, типа единственный путь к успеху. Все ищут ту самую структуру, которая позволит масштабироваться до бесконечности.
На схеме классический скелет современной системы. Выглядит разумно, но без четкого понимания каждый блок может стать точкой отказа:
• API Gateway
Единая точка входа для всех клиентов. Итог: если гейтвей "прилег" или перегружен, твои крутые микросервисы внизу превращаются в бесполезный набор кода, до которого никто не может достучаться.
• Load Balancer
Раскидывает трафик, чтобы один сервер не закипел. Итог: всё работает плавно, пока балансировщик правильно настроен. Ошибка в конфиге и весь трафик летит в один сервис, убивая его за секунды.
• Service Registry & Discovery
Сервисы должны как-то находить друг друга. Итог: если эта штука заглючит, сервис А просто не узнает, где искать сервис Б. Система развалится на куски, которые не умеют общаться.
• Разделение по доменам (Domain A / Domain B)
У каждого сервиса своя база. Итог: ты получаешь независимость, но платишь за это адом при попытке собрать общую аналитику или сделать сложный транзакционный запрос между доменами.
Уже переезжали на микросервисы?
❤️ — да, это было больно, но оно того стоило
🔥 — сидим на монолите и в ус не дуем
🔹 Практический интенсив «Архитектуры и шаблоны проектирования»
🔹 Получить консультацию менеджера
🔹 Сайт Академии 🔹 Сайт Proglib
🏃♀️ Азбука айтишника
#ликбез | 2 534 |
Вже доступно! Дослідження Telegram за 2025 — головні інсайти року 
