Библиотека Go-разработчика | Golang
23.4K subscribers
2.28K photos
46 videos
87 files
4.68K links
Все самое полезное для Go-разработчика в одном канале.

По рекламе: @proglib_adv

Учиться у нас: https://proglib.io/w/32d20779

Для обратной связи: @proglibrary_feeedback_bot

РКН: https://gosuslugi.ru/snet/67a4a8c2468
Download Telegram
📰 Дайджест недели

Вот и закончились 6 рабочих дней. Вспоминаем как это было.

Cursor 2.0

Cursor представил ускоренную модель Composer и обновленный интерфейс для параллельной работы с агентами, улучшая код-ревью и автоматическое тестирование.

Отчёт по языкам от GitHub

Вышел ежегодный Octoverse от GitHub, в котором отмечается рекордный рост числа разработчиков, активность в проектах с AI и смена лидерства по языкам программирования.

Реверс-прокси с балансировкой

LLM сражаются в покерном турнире

Разработчики рассказали как работает новый GC

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

#GoLive
Please open Telegram to view this post
VIEW IN TELEGRAM
1
💻 Когда i нормально, а d — преступление

Go поощряет краткость но не в ущерб смыслу. Правило простое: коротко для локального и широко для интерфейса и домена

Список общепринятых сокращений переменных:

i, j, k — циклы
err — ошибки
ctx — контекст
r, w — Reader, Writer
u, d, s — Receiver'ы методов. Первая буква типа.
db — Database
cfg — Config
buf — буфер
ok — флаг успеха
n — number, количество
v — value. Только с range
_ — Throwaway. Игнорируем результат.
conn — Connection

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

#GoToProduction
Please open Telegram to view this post
VIEW IN TELEGRAM
👍41🤔42
Go давно вышел за рамки веба. На нём уже пишут базы и прокси, видео-сервисы, блокчейн-узлы, компиляторы и даже игры — и делают это не ради эксперимента, а в продакшене.

В новом сезоне онлайн-конференции Podlodka Go Crew (10-14 ноября) разбираемся, как язык открывает путь к более сложным и интересным задачам — от инфраструктуры и DevEx до real-time и системных сервисов — и почему это отличный шанс вырасти как инженер.

В программе:

⚙️ Как сделать быстрый клиент для базы данных. Разберём, как реализовать асинхронное взаимодействие с БД на Go на примере Tarantool, какие оптимизации реально ускоряют код и как эволюционировать от наивного решения до производительного, — вместе с Олегом Жуковцом (VK Tech).

🌐 Как управлять сетями прямо из Go.
Посмотрим, как устроены интерфейсы в Linux, как ими управлять и собирать сложные топологии без боли. Узнаем, как работает CNI в Kubernetes и почему мир виртуальных сетей держится на Go, в докладе Даниила Губанова (Точка).

🔒 Блокчейн как real-time система. Без маркетинга: только Go, каналы, горутины и контроль над хаосом. Разберём блокчейн как инженерную задачу: сеть, криптографию и конкуррентность — вместе с Ниной Лукиной (01tech).

💬 Круглый стол «Когда Go выходит за рамки». Поговорим с нанимающими тимлидами о том, кого ищут под нестандартные Go-задачи: где важны инженерная зрелость, осознанность и умение разбираться в системах под капотом, — и как туда попасть.

💡Тем, кто хочет вырасти из CRUD-сервисов и попробовать себя в системных и инфраструктурных задачах, будет особенно полезно.

🗓 Билеты уже на https://podlodka.io/gocrew

По промокоду goproglib получите скидку🔥
6😁4🤔2
💡 Топ-вакансий для Go-разработчиков за неделю

Senior Golang Developer — от 350 000 ₽. Удаленно по Москве.

Архитектор — от 500 000 ₽

Старший разработчик Go — от 300 000 ₽. Гибрид или офис в Москве

Golang Developer — до 6 000$ на удалёнку по Португалии

Golang-разработчик — 250 000 ₽ и офис в Москве

➡️ Еще больше топовых вакансий — в нашем канале Go jobs

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

#GoWork
Please open Telegram to view this post
VIEW IN TELEGRAM
😁3👍1
📎 Кастомные ошибки в Go

Встроенный интерфейс error — это минимализм. Но когда приложение растёт, одного текста сообщения становится недостаточно. Нужно знать, что сломалось, почему это произошло и как это обработать.

Кастомный тип ошибки — это структура, которая содержит не только сообщение, но и дополнительные данные. Это позволяет обработчику ошибки принять осознанное решение: может, это ошибка валидации и стоит показать пользователю сообщение о неправильном вводе.

Как это выглядит на практике:
// Определяем свой тип ошибки
type InvalidInputError struct {
FieldName string
Value string
}

// Реализуем интерфейс Error()
func (e *InvalidInputError) Error() string {
return fmt.Sprintf("invalid input for field '%s': '%s'", e.FieldName, e.Value)
}

// Используем его в функции
func processInput(input string) error {
if len(input) == 0 {
return &InvalidInputError{FieldName: "input", Value: input}
}
return nil
}

// А вот и обработка
func main() {
err := processInput("")
if err != nil {
if invalidErr, ok := err.(*InvalidInputError); ok {
fmt.Printf("Validation error: %s (Field: %s)\n", invalidErr.Error(), invalidErr.FieldName)
} else {
fmt.Printf("Unexpected error: %s\n", err)
}
}
}


Мы поймали ошибку через type assertion и получили доступ к полям структуры. Это даёт намного больше гибкости, чем просто if err != nil.

В современном Go для распаковки обёрнутых ошибок есть errors.As() — это удобнее, чем type assertion, особенно если ошибку кто-то обернул через fmt.Errorf("%w", err).

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

#GoDeep
Please open Telegram to view this post
VIEW IN TELEGRAM
6👍4
⚙️ Docker команды, которые должен знать разработчик

Сколько раз вы открывали терминал и забывали простую Docker команду? Гугл в помощь, потом опять ищете то же самое через неделю. Рассказываем про команды, которые нужны в реальной работе.

Вам нужно видеть, какие контейнеры работают прямо сейчас:
docker ps


Это покажет только живые контейнеры. Но если контейнер упал или его остановили, он исчезнет из списка.

Чтобы увидеть всё, включая мёртвые:
docker ps -a


Самая частая команда в разработке:
docker run -d -p 8080:80 nginx


Разбираем:
-d — запустить в фоне, чтобы терминал не занимался.
-p 8080:80 — проксировать локальный порт 8080 на порт 80 внутри контейнера.
nginx — образ, который запускаем.

Результат: контейнер крутится в фоне, вы можете открыть https://localhost:8080 и увидите nginx.

Контейнер поднялся, поэкспериментировали, теперь нужно его убить:
docker stop имя-или-id


Контейнер остановится, но останется на диске.

Если нужно удалить совсем:
docker rm имя-или-id


Или в один ход — остановить и удалить:
docker rm -f имя-или-id


Флаг -f форсирует удаление даже если контейнер работает.

Посмотреть все образы у вас на машине:
docker images


Удалить образ, если он вам больше не нужен:
docker rmi название-образа


Если удалите образ, контейнеры которые на нём основаны, перестанут работать.

Контейнер падает или работает странно? Посмотрите логи:
docker logs имя-или-id


Это покажет всё что контейнер вывел в stdout.

Можно добавить флаг -f чтобы следить в реальном времени:
docker logs -f имя-или-id


Иногда нужно залезть внутрь контейнера и что-то проверить. Откройте интерактивный шелл:
docker exec -it имя-или-id bash


Флаг -it означает интерактивный терминал. Теперь вы внутри, можете запускать команды, смотреть файлы, отлаживать.

Ещё полезно посмотреть детали контейнера:
docker inspect имя-или-id


Будет JSON со всей информацией: какие переменные окружения, какие портами, версии образа, сетевая конфигурация.

Со временем контейнеры и образы накапливаются. Чистим:
docker system prune -a


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

Контейнер падает, данные теряются — такое быть не должно. Для этого есть тома:
docker volume create my_volume


Теперь у вас есть том. Запускаете контейнер и монтируете том внутрь:
docker run -d -v my_volume:/data nginx


Флаг -v монтирует том my_volume в папку /data внутри контейнера. Когда контейнер упадёт, данные в томе остаются. Запустите контейнер снова — данные на месте.

По умолчанию контейнеры могут общаться через IP адреса, но это хрупко. Правильнее создать свою сеть:
docker network create my_network


Теперь запускаете контейнеры в этой сети:
docker run -d --network my_network --name api nginx
docker run -d --network my_network --name db postgres


Контейнеры внутри сети видят друг друга по имени. Это удобнее чем помнить IP адреса.

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

#GoToProduction
Please open Telegram to view this post
VIEW IN TELEGRAM
👍28🔥2🥱1
🛠 Как найти и починить утечки, которые валят API

API падает каждый день? Память растёт, горутины множатся, потом крах. Это не магия — это утечки ресурсов. Вот как их найти и убить.

Шаг 1: Собрать доказательства перед тем как гадать

Не начинайте с предположений. Сначала соберите логи. Ищите паттерны: растут ли таймауты, появляются ошибки «context canceled», скачет ли error rate?

Heap и goroutine профили. Это главное. Добавьте pprof endpoint, если его нет:
import _ "net/http/pprof"

go func() {
log.Println(http.ListenAndServe(":6060", nil))
}()


На следующем инциденте вытащите профили:
curl localhost:6060/debug/pprof/heap > heap.pb
curl localhost:6060/debug/pprof/goroutine?debug=2 > goroutines.txt


Проверьте лимиты: /proc/<pid>/limits, количество открытых файловых дескрипторов, состояние сокетов.

Шаг 2: Прочитать профили и понять, что протекает

Откройте goroutine профиль текстом — там все ответы:
go tool pprof -http=:8080 heap.pb


Что нужно найти:

• Горутины в CLOSE_WAIT. Это сокеты, которые никто не закрыл нормально.

• Горутины, зависшие на channel send/receive. Если тысячи горутин ждут отправить или получить из канала — канал где-то забился или заблокирован.

• Горутины в syscall. Много горутин ждут на сетевых операциях — это может быть утечка соединений или зависание на стороне сервера.

Шаг 3: Найти корни утечек в коде

Три главных виновника:

• Горутины без контекста. Запустили горутину для async операции, но не гарантировали её завершение:
// Плохо: горутина может зависнуть
go func() {
resp, _ := http.Get(url)
// ...
}()

// Хорошо: контекст отменяет работу
go func(ctx context.Context) {
req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
resp, _ := httpClient.Do(req)
}(r.Context())


• HTTP клиенты без переиспользования. Создаёте нового клиента на каждый запрос:
// Плохо: новый Transport на каждый вызов
func handleRequest(w http.ResponseWriter, r *http.Request) {
client := &http.Client{}
resp, _ := client.Get("https://api.example.com/data")
}

// Хорошо: переиспользуем один клиент
var httpClient = &http.Client{
Transport: &http.Transport{
MaxIdleConns: 200,
MaxIdleConnsPerHost: 100,
IdleConnTimeout: 90 * time.Second,
},
}


• Неограниченные очереди. На пике нагрузки канал растёт без предела:
// Плохо: неограниченный канал
jobs := make(chan Job)

// Хорошо: ограничиваем размер
jobs := make(chan Job, 1000)

select {
case jobs <- job:
// принято
default:
http.Error(w, "перегружены", http.StatusServiceUnavailable)
}


Чтобы не падать в проде можно попробовать имитировать нагрузку на дев стенде:
# Генерируем нагрузку
ab -n 100000 -c 100 https://localhost:8080/endpoint

# В другом терминале снимаем профиль каждую минуту
for i in {1..60}; do
curl localhost:6060/debug/pprof/goroutine?debug=1 > goroutine_$i.txt
sleep 60
done


Растёт ли количество горутин? Если да — утечка. Если нет — ложная тревога.

Не полагайтесь только на профили. Мониторьте в реальном времени:
// Метрика: количество горутин
runtime.NumGoroutine()

// Метрика: память
var m runtime.MemStats
runtime.ReadMemStats(&m)
m.Alloc // текущее использование

// Метрика: открытые файловые дескрипторы (Linux)
files, _ := ioutil.ReadDir("/proc/self/fd")
len(files) // количество открытых fd


Выставляйте эти метрики в Prometheus или что у вас есть. Алерты на рост горутин выше нормы — это первый звоночек.

Не решайте задачу вслепую. Профилируйте, смотрите данные, ищите паттерны. Утечки это не магия — это просто ресурсы, которые вы забыли закрыть.

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

#GoToProduction
Please open Telegram to view this post
VIEW IN TELEGRAM
👍22🔥53😢1
✏️ FizzBuzz — классика собеседований

Задача проста на вид, но открывает много вопросов на интервью. Вот почему её так любят спрашивать.

Дано число n. Нужно вернуть массив строк, где для каждого числа от 1 до n:

• если кратно и 3 и 5 — «FizzBuzz»
• если кратно 3 — «Fizz»
• если кратно 5 — «Buzz»
• иначе — само число как строку

Решение:
func fizzBuzz(n int) []string {
res := make([]string, n)
for i := 1; i <= n; i++ {
res[i-1] = strconv.Itoa(i)
if i % 3 == 0 { res[i-1] = "Fizz" }
if i % 5 == 0 { res[i-1] = "Buzz" }
if i % 15 == 0 { res[i-1] = "FizzBuzz" }
}
return res
}


Число 15 — это наименьшее общее кратное чисел 3 и 5. Когда число одновременно делится на 3 и на 5, оно всегда делится на 15.

На собеседовании сначала напишите просто, потом обсудите улучшения. FizzBuzz — не про трюки синтаксиса, а про чистоту мышления и умение общаться с интервьюером.

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

#ReadySetGo
Please open Telegram to view this post
VIEW IN TELEGRAM
🥱9👍5😁3🤔1
🧑‍💻 Среда или понедельник

Как у вас началась рабочая трёхдневка? У админа сбились абсолютно все настройки по пониманию какой сейчас день недели. Тяжелее только новогодние праздники.

💬 Работаете или взяли хитрый отпуск? Ждём вас в комментах 👇

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

#GoTalk
Please open Telegram to view this post
VIEW IN TELEGRAM
😁9🥱1
⚙️ GoCrypt 1.1.0: теперь быстрее

GoCrypt изначально просто проходил через все поля структуры на каждый вызов, искал теги, выполнял рефлексию. Для больших структур это замедлялось быстро.

Новая версия 1.1.0 это переработала.

Раньше каждый вызов Encrypt() и Decrypt() переанализировал структуру с нуля. Если вы обрабатываете пользователя с 15 полями, где только 3–4 нужно шифровать, библиотека изучала все 15. В тысячный раз.

Теперь типы кешируются через sync.Map. Первый проход — сохраняются информация о том, какие поля нужны. Все последующие операции просто смотрят в кеш.

➡️ Репозиторий либы

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

#GoLive
Please open Telegram to view this post
VIEW IN TELEGRAM
👍201😁1
🔒 Когда fmt.Sprintf становится бомбой

SQL-инъекция — это не призрак из учебников по безопасности. Это реальная уязвимость, которая прячется в коде, написанном в спешке. И она может находиться в вашем приложении прямо сейчас.Её главная фишка в том, что она выглядит безобидно.

Пара строк кода, которые кажутся логичными и работают в тестах. Но в боевых условиях это становится открытой дверью в вашу базу данных.

Когда вы склеиваете SQL-запрос из частей, вы решаете за базу данных, что считать кодом, а что — данными. И вы почти гарантированно ошибаетесь.

Хакер, в отличие от вас, знает это. Он понимает, что можно передать в поле username и заставить его работать как код. Он не пытается угадать пароль — он меняет саму структуру запроса.

Параметризованные запросы — это не украшение, а архитектура

Разница между уязвимым и безопасным кодом — это не регулярные выражения или специальные функции для очистки. Это просто разделение: запрос идёт одним пакетом, данные — другим.

// Сначала структура...
query := "SELECT id, username, email FROM users WHERE username = ?"
// ...потом данные
err := db.QueryRow(query, username).Scan(&id, &uname, &email)


Драйвер БД уже знает, что делать. Он не будет интерпретировать данные как команды.

Одной инъекции недостаточно, чтобы взломать приложение, если на входе стоит валидация.

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

#GoToProduction
Please open Telegram to view this post
VIEW IN TELEGRAM
👍192
🤨 Игнорирование контекста — это путь боли

Новичок пишет код примерно так:
res, err := http.Get(url)


Выглядит невинно, но если вызов зависнет, то зависнет и горутина. Навсегда. Нет таймаута, нет способа его отменить. Сервис просто накапливает горутины, пока не упадёт.

Профессионалы всегда передают контекст через все слои приложения:
req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
res, err := http.DefaultClient.Do(req)


Они распространяют его на весь путь — от HTTP хендлера через бизнес-логику до репозиториев:
func (r *UserRepo) Get(ctx context.Context, id int) (*User, error) {
// ctx здесь и управляет отменой, и ловит таймауты
}


Это не просто хорошая практика — это основа надёжности.

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

#GoToProduction
Please open Telegram to view this post
VIEW IN TELEGRAM
👍27🤔51💯1
⚙️ Go-библиотека для интеграции OAuth

gologin предоставляет цепочки http.Handler-ов для аутентификации через Google, GitHub, Twitter, Bitbucket, Tumblr или любых других OAuth1 и OAuth2 провайдеров.

Вместо того, чтобы вручную парсить OAuth-потоки, обрабатывать CSRF-токены и делать API-запросы за данными пользователя, вы просто подключаете готовые обработчики и получаете аутентифицированного пользователя в контексте запроса.

Быстрый старт

Интегрировать вход через GitHub занимает всего несколько строк:
import (
"github.com/dghubble/gologin/v2"
"github.com/dghubble/gologin/v2/github"
"golang.org/x/oauth2"
githubOAuth2 "golang.org/x/oauth2/github"
)

config := &oauth2.Config{
ClientID: "YourGithubClientID",
ClientSecret: "YourGithubClientSecret",
RedirectURL: "https://localhost:8080/callback",
Endpoint: githubOAuth2.Endpoint,
}

mux := http.NewServeMux()
mux.Handle("/login",
github.StateHandler(gologin.DefaultCookieConfig,
github.LoginHandler(config, nil)))
mux.Handle("/callback",
github.StateHandler(gologin.DefaultCookieConfig,
github.CallbackHandler(config, issueSession(), nil)))


Готово. Пользователь нажимает на /login, перенаправляется на GitHub, а затем на /callback с кодом авторизации.

Для веб-приложений используются LoginHandler и CallbackHandler, которые управляют редиректами.

Для мобильных приложений есть TokenHandler, который работает с токенами, передаваемыми напрямую. Twitter, например, включает специальный TokenHandler именно для таких случаев.

➡️ Репозиторий либы

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

#GoLive
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1531
🎁 И мозг прокачать, и макбук утащить!

Proglib.academy разыгрывает MacBook Pro 14 (M3 Pro, 36 GB, 1 TB SSD) 💻

Условия:

1️⃣ Покупаешь любой курс Proglib до 15 ноября.
2️⃣ Проходишь минимум 2 учебные недели (можно осилить за два вечера).
3️⃣ Пишешь куратору в чат своего курса: #розыгрыш.

Что за курсы?

Математика для Data Science (6 месяцев боли и просветления).
Основы Python, ML, алгоритмы, AI-агенты и даже курс для тех, кто в IT, но не кодит.

👉 Участвовать в розыгрыше
🥱32🤔1🤩1
💻 От логирования к передаче вверх

Go известен своей простотой, но именно в этой простоте скрыта мощная возможность — передача ошибок вверх по стеку вызовов. Часто начинающие разработчики просто логируют ошибку и возвращают nil, теряя всю информацию о контексте:
user, err := repo.GetUser(id)
if err != nil {
log.Println("failed to get user:", err)
return nil
}


Такое решение убивает возможность понять, где именно и почему произошла ошибка.

Вот как это делают опытные разработчики:
user, err := repo.GetUser(ctx, id)
if err != nil {
return nil, fmt.Errorf("get user %d: %w", id, err)
}


%w — это ключ к вложенным ошибкам в Go 1.13 и новее. Такой подход сохраняет смысл ошибки и ее цепочку, что помогает в отладке и трассировке.

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

#GoToProduction
Please open Telegram to view this post
VIEW IN TELEGRAM
👍24🥱62
🤩 Finally — отсортированные часы

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

#GoGiggle
Please open Telegram to view this post
VIEW IN TELEGRAM
😁29👾3
📰 Дайджест недели

Вот и прошла трёхдневная рабочая неделя. Вспоминаем что произошло.

Ещё один ИИ из Китая

Свежий Cup o' Go

У Firefox новый маскот

Как найти и починить утечки, которые валят API

GoCrypt 1.1.0

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

#GoLive
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1