Библиотека Go-разработчика | Golang
24.1K subscribers
2.77K photos
53 videos
88 files
5.42K links
Все самое полезное для Go-разработчика в одном канале.

Учиться у нас: clc.to/qaSdww

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

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

РКН: https://gosuslugi.ru/snet/67a4a8c24689c2151c752af0

#WXSSA
Download Telegram
🐳 Go в Kubernetes мог зря конкурировать за CPU — с Go 1.25 это изменилось

До Go 1.25 рантайм ориентировался на CPU всей машины. Поэтому pod с лимитом в 2 CPU на 64-ядерной ноде мог получить GOMAXPROCS=64.

Linux при превышении CPU limit начинал throttling — процесс мог полностью приостанавливаться на оставшуюся часть периода. Это особенно неприятно для tail latency.

🌞 В Go 1.25 рантайм на Linux начал учитывать CPU limit из cgroup:

runtime.GOMAXPROCS(0)


Например, pod с лимитом в 2 CPU → GOMAXPROCS будет 2. Значение также периодически пересчитывается, если cgroup limit меняется.

⚠️ Но есть ловушка: если вы вручную задаёте GOMAXPROCS через env или:


runtime.GOMAXPROCS(8)


автоматическая настройка отключается.

🔘 То же самое касается старого automaxprocs: после перехода на Go 1.25+ стоит проверить, нужен ли он вообще. И ещё нюанс: Go ориентируется на CPU limit, а не CPU request.

📌 Если Go-сервис живёт в Kubernetes, проверить GOMAXPROCS после обновления Go — довольно дешёвый способ найти старую настройку, которая больше не нужна.

🔗 Источник

📍 Навигация: ВакансииЗадачиСобесы

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

#GoDeep
Please open Telegram to view this post
VIEW IN TELEGRAM
5👏4👾3😢1
🤩 Go 1.25 больше не получает security-фиксы

19 августа вышел Go 1.27 — и по политике Go поддерживаемыми теперь остаются только 1.27 и 1.26.

Если проект всё ещё собирается на 1.25, это хороший момент для обновления. Для тех, кто пока не готов переходить на 1.27, есть актуальная ветка 1.26 с патч-релизом 1.26.7.

Проверить зависимости на известные уязвимости можно через:


govulncheck ./…


А заодно стоит посмотреть на изменения в encoding/json: в Go 1.27 появился новый encoding/json/v2, а старый пакет теперь работает поверх его реализации.

🔗 Источники: ⁠Go Release History · ⁠Go Vulnerability Database

📍 Навигация: ВакансииЗадачиСобесы

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

#GoLive
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8😢3💯2
This media is not supported in your browser
VIEW IN TELEGRAM
🤩 templ: типобезопасный HTML в Go

html/template работает со строковыми шаблонами, а templ позволяет писать HTML-компоненты прямо в .templ и превращать их в обычный Go-код.


templ Hello(name string) {
<div class="greeting">Привет, { name }</div>
}


После templ generate компонент можно использовать как обычную функцию:


view.Hello("гофер").Render(ctx, w)


📍 Плюс — типы и ошибки в компонентах проверяются при компиляции, есть автоматическое экранирование HTML.

Особенно удобно для серверного рендеринга и связки Go + htmx, когда полноценный frontend-фреймворк не нужен.

🔗templ · ⁠GitHub

📍 Навигация: ВакансииЗадачиСобесы

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

#GoToProduction
Please open Telegram to view this post
VIEW IN TELEGRAM
6👍6
🧹 t.Cleanup: уборка в Go-тестах без лишних defer

Подняли тестовую БД, создали временный файл или запустили сервер? t.Cleanup позволяет привязать очистку прямо к жизненному циклу теста.

🟡 Главный плюс — хелперы могут сами отвечать за освобождение ресурсов:


func newTestDB(t *testing.T) *sql.DB {
t.Helper()

db := openTempDB(t)
t.Cleanup(func() {
db.Close()
})

return db
}


🟡 Теперь тесту не нужно помнить про defer:


func TestUsers(t *testing.T) {
db := newTestDB(t)
// ...
}


Cleanup выполнится после завершения теста, даже если тот упал через t.Fatal. Несколько cleanup-функций выполняются в обратном порядке регистрации.

📍 Навигация: ВакансииЗадачиСобесы

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

#GoToProduction
Please open Telegram to view this post
VIEW IN TELEGRAM
👍152🙏2👾1
🤩 Table driven tests в Go

Обычная история: есть функция и десять сценариев. Если писать по тесту на каждый сценарий, код быстро превращается в копипасту. Table driven подход делает один тест, а сценарии складывает в таблицу.

Вы описываете кейсы в таблице, обычно это слайс структур. Потом в цикле запускаете каждый кейс как сабтест через t.Run, чтобы у каждого сценария было имя и его можно было запустить отдельно.

🟡 Пример на простой функции:


func Split(s, sep string) []string {
return strings.Split(s, sep)
}

func TestSplit(t *testing.T) {
tests := []struct {
name string
input string
sep string
want []string
}{
{name: "simple", input: "a/b/c", sep: "/", want: []string{"a", "b", "c"}},
{name: "no sep", input: "abc", sep: "/", want: []string{"abc"}},
{name: "trailing", input: "a/b/c/", sep: "/", want: []string{"a", "b", "c", ""}},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
got := Split(tc.input, tc.sep)
if !reflect.DeepEqual(got, tc.want) {
t.Fatalf("want %v got %v", tc.want, got)
}
})
}
}


Еще мелочь, но полезная. Внутри сабтеста t.Fatal завершает только текущий сабтест, а не весь набор, поэтому для table driven тестов это часто удобнее чем тянуть continue и пачку if.

📍 Навигация: ВакансииЗадачиСобесы

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

#GoDeep
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥21🥰1🥱1
🚨 Go 1.27 поменял encoding/json изнутри

API старого encoding/json остался прежним, но под капотом теперь работает новый движок encoding/json/v2. Для существующего кода это должно быть прозрачно — Go сохраняет старую семантику через набор compatibility-опций.

Но производительность изменилась.

В независимом бенчмарке на одинаковых данных:

🔘 Unmarshal в структуру — примерно в 1,5 раза быстрее;
🔘 Unmarshal в any — примерно в 1,5 раза медленнее;
🔘 Marshal — немного медленнее, зато заметно меньше аллокаций;
🔘 потоковая работа через новый API MarshalWrite требует значительно меньше памяти.


Самая интересная ловушка — any. Старый API разрешает дубликаты ключей JSON, поэтому новый движок не может использовать свой быстрый путь для any. В результате динамический JSON может обрабатываться медленнее.

🤩 А если перейти непосредственно на encoding/json/v2, появляются новые дефолты: дубликаты ключей и невалидный UTF-8 отклоняются, nil-слайсы и map по умолчанию кодируются иначе, а порядок ключей map не гарантируется без Deterministic.

После перехода на Go 1.27 недостаточно проверить только компиляцию. Если encoding/json находится на горячем пути — стоит прогнать свои бенчмарки. Особенно если приложение активно работает с any или map[string]any.

А encoding/json/v2 уже можно внедрять постепенно, сохраняя нужные v1-семантики через DefaultOptionsV1().

🔗 Официальный гайд по миграции encoding/json/v2

📍 Навигация: ВакансииЗадачиСобесы

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

#GoLive
Please open Telegram to view this post
VIEW IN TELEGRAM
9👍32🥱1👾1
💡 Почему Go нельзя просто установить и забыть

С Go часто делают так: выбрали версию, прописали её в Dockerfile — и вспоминаем о ней только при следующем большом обновлении. Но security-патчи выходят внутри той же ветки. И если ваша версия старая, опубликованная уязвимость превращает её в известную цель.

📍 Поэтому версия Go в проде должна обновляться примерно так же, как обычные зависимости.

Что стоит сделать:

— закрепить конкретный toolchain в go.mod;
— регулярно пересобирать Docker-образ;
— следить за security-анонсами Go;
— проверять зависимости через govulncheck.

Например:


toolchain go1.26.6


А CI может брать версию прямо из go.mod:


- uses: actions/setup-go@v5
with:
go-version-file: go.mod


🔗 Источник

📍 Навигация: ВакансииЗадачиСобесы

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

#GoToProduction
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13❤‍🔥2🔥2😢1
🔗 Как Go запускает горутины

В Go тысячи горутин не привязаны напрямую к потокам ОС. Runtime распределяет их через GMP-модель:

⬇️G (Goroutine) — что
⬇️нужно выполнить;
⬇️M (Machine) — поток ОС,
⬇️на котором выполняется
⬇️код;
⬇️P (Processor) — ресурс
⬇️планировщика, который
⬇️связывает G и M.

У каждого P есть своя локальная очередь горутин. Если работы не хватает, планировщик может взять её из глобальной очереди или украсть часть очереди другого P — это work-stealing.

🟡 А если M блокируется на syscall, P не обязан ждать его возвращения: runtime может передать P другому потоку через handoff.

🟡 Отдельно за состоянием runtime следит sysmon, а сетевые операции обслуживает netpoller, поэтому ожидание I/O обычно не означает простой потока ОС. Именно эта связка позволяет Go одновременно держать много горутин и эффективно использовать несколько CPU.

А вся схема — на картинке 🤩

🔗 Читать подробнее про планировщика

📍 Навигация: ВакансииЗадачиСобесы

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

#GoDeep
Please open Telegram to view this post
VIEW IN TELEGRAM
9👍6🥰21
🤔 Вопрос с собеседования

Что произойдёт, если одна горутина надолго зациклится на CPU и не будет делать ни sleep, ни syscall, ни операций с каналами?

❤️ — вторая горутина не выполнится, потому что P всего один
🔥 — планировщик вытеснит первую горутину и запустит вторую
👍 — вторая выполнится только после runtime.Gosched()

👇 Правильный ответ (нажми, чтобы прочитать):

🔥 Начиная с Go 1.14 планировщик поддерживает асинхронное вытеснение. Поэтому даже CPU-bound горутина, которая не блокируется и не вызывает runtime-функции, не может бесконечно удерживать P.

GOMAXPROCS(1) означает, что одновременно выполняется только одна горутина, но планировщик может переключать между несколькими G.

До Go 1.14 такой бесконечный цикл действительно мог надолго заблокировать выполнение других горутин.


📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека Go-разработчика
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥613👍3🤔1
🔄 Можно ли в Kafka перечитать сообщения?

Да. Пока сообщение не удалено по retention, consumer может вернуться к старому offset и обработать его снова.

🔴 Это особенно полезно, если в обработчике обнаружили баг:


исправили код → сдвинули offset назад → переиграли сообщения


Например, для consumer group можно сбросить offset через kafka-consumer-groups.

💡 Важно: offset хранится для consumer group, поэтому сброс влияет на чтение этой группой.

Kafka в этом плане отличается от классической очереди: прочитанное сообщение не исчезает сразу — его можно переиграть.

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека Go-разработчика
Please open Telegram to view this post
VIEW IN TELEGRAM
6🔥2
👩‍💻 15 вопросов по PostgreSQL, которые стоит знать Go-разработчику

Если идёте на Middle Go, одного синтаксиса SQL мало. На собеседовании легко уйти в индексы, транзакции и конкурентный доступ.

Сохраняйте чек-лист:

B-tree — когда используется и какие запросы ускоряет?
EXPLAIN ANALYZE — что показывает и чем отличается от EXPLAIN?
Почему PostgreSQL выбирает Seq Scan, хотя есть индекс?
Составной индекс — что это и зачем нужен?
Левый префикс — почему порядок колонок в индексе важен?
Как выбрать порядок колонок в составном индексе?
MVCC — как PostgreSQL позволяет транзакциям работать параллельно?
Уровни изоляции — какие бывают и чем отличаются?
Deadlock — как возникает и как его предотвращать?
SELECT ... FOR UPDATE — когда нужен?
N+1 — откуда появляется и как его найти?
ACID — что означает каждая буква на практике?
Connection pool — зачем он нужен и какие проблемы возникают при неправильных настройках?
Replication lag — почему реплика отстаёт и чем это опасно?
Partitioning vs Sharding — в чём разница и когда применять каждый подход?


🔥 Если можете не просто дать определение, а привести пример из реального сервиса на Go, скорее всего, с базовыми вопросами PostgreSQL на собеседовании проблем не будет.

С вас 🔥, если полезно!

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека Go-разработчика
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥235
🌞 Готовим вебинар про AI в разработке и хотим сделать его максимально полезным

Что реально хочется разобрать? Где чаще всего застреваете? Что пробовали, но так и не получилось нормально внедрить?


🤩 Пишите вопросы в комментариях — самые залайканные разберём на вебинаре в первую очередь.

Задавайте всё, что давно хотелось спросить 📍

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека Go-разработчика
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
💡 Тестирование ввода из stdin

Тестирование функций, которые читают данные с консоли через fmt.Scan и stdin в Go, часто становится настоящей задачей. В таких случаях нельзя просто передать параметры функции — код напрямую взаимодействует со стандартным вводом.

Пример проблемы:


func ReadName() string {
var name string
fmt.Print("Enter your name: ")
fmt.Scan(&name)
return name
}


Для этой функции сложно написать unit-тест, потому что она читает из os.Stdin, а в тестах обычно хочется подставлять свои данные.

Решение: подменяем os.Stdin

В тестах можно временно переназначить os.Stdin на чтение из заранее подготовленного буфера:


func TestReadName(t *testing.T) {
input := "Alice\n"
r, w, _ := os.Pipe()
w.WriteString(input)
w.Close()
oldStdin := os.Stdin
defer func() { os.Stdin = oldStdin }()
os.Stdin = r

got := ReadName()
want := "Alice"
if got != want {
t.Errorf("got %q, want %q", got, want)
}
}


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

📍 Навигация: ВакансииЗадачиСобесы

🐸 Библиотека Go-разработчика
Please open Telegram to view this post
VIEW IN TELEGRAM
6