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

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

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

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

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

#WXSSA
Download Telegram
🧑‍💻 Эмулятор AWS-сервисов

Kumo — это небольшой инструмент на Go для локальной имитации AWS-сервисов. Он помогает разработчикам тестировать приложения без облака.

Проект подходит для unit-тестов, где нужен мок для облачных вызовов. Устанавливается через go install github.com/sivchari/kumo@latest. Запускается как прокси, а SDK настраивается на локальный эндпоинт.

Поддерживает базовые операции над S3: создание бакетов, загрузку объектов, список файлов. Для DynamoDB эмулирует таблицы, put/get item. Конфиг через флаги или env.

➡️ Репозиторий

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

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

#GoLive
Please open Telegram to view this post
VIEW IN TELEGRAM
👍201❤‍🔥1
🛠 ECS на Go

Entity Component System (ECS) это архитектурный паттерн, популярный в геймдеве и симуляциях. Идея простая: вместо объектов с данными и поведением используются сущности без данных, компоненты с данными и системы/запросы, которые обрабатывают сущности с нужным набором компонентов.

Ark это архетипная реализация ECS для Go. Архетипный подход означает, что сущности с одинаковым набором компонентов хранятся вместе в памяти, что максимизирует локальность данных при итерации.

Что внутри

Типобезопасный API с дженериками, никакого interface{} и рефлексии в горячих путях. Отношения между сущностями как first-class feature. Система событий с фильтрацией. Batch-операции для массовых изменений. Сериализация мира через ark-serde. Ноль внешних зависимостей, 100% покрытие тестами.

Никаких встроенных систем, только запросы. Структуру приложения выбираем сами, или используем ark-tools со scheduler'ом:
world := ecs.NewWorld()
mapper := ecs.NewMap2[Position, Velocity](world)
filter := ecs.NewFilter2[Position, Velocity](world)

query := filter.Query()
for query.Next() {
pos, vel := query.Get()
pos.X += vel.DX
pos.Y += vel.DY
}


Свежий релиз v0.8.0

7 апреля вышла v0.8.0 с заметными изменениями. Добавлена итерация по таблицам, которая даёт примерно двукратное ускорение по сравнению с обычной итерацией:
for query.NextTable() {
positions, velocities := query.GetColumns()
for i := range positions {
pos, vel := &positions[i], &velocities[i]
pos.X += vel.X
pos.Y += vel.Y
}
}


Также очистка памяти компонентов через memclrNoHeapPointers вместо обнуления вручную, перемещение нетривиальных компонентов стало быстрее на 30% за счёт typedmemmove вместо рефлексии, добавлены регрессионные бенчмарки для сравнения PR с main-веткой.

➡️ Репозиторий

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

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

#GoToProduction
Please open Telegram to view this post
VIEW IN TELEGRAM
6👍2
Что выведет код с картинки

strings.ContainsAny проверяет, содержит ли строка хотя бы один символ из набора. Но что происходит, когда оба аргумента пустые строки?

Подсказка: загляни в документацию к функции и обрати внимание на крайние случаи.

Ответ: в нашем канале с задачами

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

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

#ReadySetGo
Please open Telegram to view this post
VIEW IN TELEGRAM
⚙️ Компилятор Go строит типы и ловит циклические зависимости

Go 1.26 принёс незаметное, но важное изменение в type checker. Команда Go опубликовала подробный разбор того, как именно компилятор конструирует типы и обнаруживает циклические зависимости.

Как устроена конструкция типов

Когда компилятор встречает объявление типа, он строит внутреннее дерево структур. Для простого случая:
type T []U
type U *int


Всё линейно: сначала строится T, внутри неё []U, внутри неё U, внутри неё *int. Каждый тип становится «завершённым» когда все его поля заполнены и все зависимые типы тоже завершены. Процесс идёт вглубь и разматывается обратно.

Рекурсивные типы

С рекурсией интереснее:
type T []U
type U *T

Здесь T встречается пока ещё строится. Компилятор просто ставит указатель на незавершённый T и движется дальше, рассчитывая что T завершится позже. Когда конструкция доходит до конца, весь "цикл" типов завершается одновременно.

Проблема возникает когда незавершённый тип нужно не просто упомянуть, а заглянуть внутрь:
type T [unsafe.Sizeof(T{})]int


Чтобы вычислить размер массива, нужно знать размер T. Но чтобы знать размер T, нужно завершить построение массива. Круговая зависимость, которую невозможно разрешить, это ошибка цикла.

В Go 1.26 переписали подход: вместо сложной bespoke-логики для каждого случая, компилятор теперь отслеживает неполные значения систематически. В каждом месте где может возникнуть значение неполного типа, вставлена проверка:
if !isComplete(T) {
reportCycleErr(T)
return invalid
}


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

➡️ Блог разработчиков

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

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

#GoDeep
Please open Telegram to view this post
VIEW IN TELEGRAM
11👍5🔥2👏1
💡 Замените счётчики на итераторы

В Go давно есть идиоматичный способ обходить коллекции: range. Но многие стандартные типы исторически предлагали только Len() и At(i), и код превращался в ручной счётчик. Анализатор stditerators из golang.org/x/tools находит такие места и предлагает замену.

Типичный паттерн, который можно встретить в Go-проекте:
for i := 0; i < x.Len(); i++ {
use(x.At(i))
}


Это работает, но многословно. Появились итераторы: метод All() у ряда стандартных типов возвращает iter.Seq, по которому можно пройтись через range. stditerators находит старые конструкции и предлагает переписать их вот так:
for elem := range x.All() {
use(elem)
}


Анализатор понимает оба варианта счётчика — классический for i := 0; i < x.Len(); i++ и более новый for i := range x.Len().

Что покрывает

Анализатор работает с конкретными типами из стандартной библиотеки, у которых уже есть метод All(). Это не универсальный «переписыватель» для всего подряд, а точечный инструмент с заранее известным списком поддерживаемых типов.

Как запустить:
go install golang.org/x/tools/gopls@latest


Или через go vet с плагином:
go run golang.org/x/tools/go/analysis/passes/stditerators/cmd/stditerators@latest ./...


В большинстве редакторов с gopls анализатор подсветит проблемное место прямо в коде и предложит автоматический фикс.

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

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

#GoToProduction
Please open Telegram to view this post
VIEW IN TELEGRAM
9
🤔 Разрабатываете ИИ-агентов, но всё ещё не уверены в их стабильности и прогнозируемости?

Мы поговорили с десятками разработчиков ИИ-агентов и сделали отдельный курс по AgentOps.

🧠 На нём вы узнаете:

– как оптимизировать траты на токены;
– как на практике оценить качество работы агента;
– как «докручивать» RAG-системы без потери качества;
– как обеспечить устойчивость агента к сбоям внешних сервисов без падения всей системы и про многое-многое другое.

📅 Старт: 19 мая.

👥 Спикеры — практики с опытом в AI и Data Science в крупных IT-компаниях, таких как Яндекс, Huawei, МТС и др.

Длительность: 6-12 недель в зависимости от тарифа.


🔗 Программа курса и другие подробности
1
🤯 Представьте, что ваш AI-агент работает так же предсказуемо, как обычный микросервис. Звучит утопически, но это именно то, к чему должна прийти разработка в 2026 году.

Основная боль текущих реализаций — полная непредсказуемость поведения. Сегодня агент выполнил задачу за два шага, а завтра ушёл в рекурсию и потратил все лимиты.

Наш обновлённый курс «Разработка AI-агентов» научит, как приручить этот хаос с помощью Python и современных фреймворков. Мы не будем учить «общаться» с нейросетью, мы будем строить из неё надёжный инструмент.

Что вы получите:


— понимание того, как управлять логикой агента на уровне кода;
— навыки работы с LangChain и библиотеками оркестрации;
— готовые паттерны для обработки ошибок и галлюцинаций;
— опыт создания систем, которые реально экономят время.

Есть пара мест со скидкой до завтра, решайтесь 👈🏻
🤩 Дайджест недели

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

oaswrap/spec v0.4.0

Патчи с исправлениями безопасности

Эмулятор AWS-сервисов

Entity Component System на Go

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

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

#GoLive
Please open Telegram to view this post
VIEW IN TELEGRAM
⚙️ CLI, который замораживает dev-сервер вместо его убийства

Типичная ситуация: запущен dev-сервер на порту 3000, нужно на полминуты освободить порт под другую задачу. Убиваете процесс и теряете кэши в памяти, состояние билд-вотчера, прогретые соединения. Потом поднимаете всё заново.

Разработчик написал инструмент park, который решает это иначе: замораживает процесс и освобождает порт, а потом возвращает всё как было. Тот же PID, та же память, те же открытые файлы. Процесс не знает, что что-то произошло.

park 3000          # заморозить и освободить порт
# делаем что нужно на порту 3000
park resume 3000 # вернуть всё обратно


Почему Ctrl+Z не работает

Ctrl+Z отправляет SIGSTOP — процесс замирает, но ядро по-прежнему считает порт занятым. Попытка занять его другим процессом даёт Address already in use. SIGSTOP не закрывает сокет.

park решает это через инъекцию close(fd) прямо в работающий процесс без его перезапуска и изменения кода.

Установка:
curl -fsSL https://raw.githubusercontent.com/mr-vaibh/park/main/install.sh | sh


Инсталлятор сам определяет ОС и архитектуру. На macOS автоматически подписывает бинарник с нужными правами для инъекции в процессы.

➡️ Репозиторий

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

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

#GoToProduction
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13
✏️ Автоматизация рутины в Go-проектах

Большинство Go-разработчиков знают про go generate, но редко его используют. А зря — это простой способ убрать ручную работу из цикла разработки.

Что такое go generate и зачем оно нужно

В каждом проекте есть код, который кто-то должен написать руками: моки для тестов, protobuf-файлы, бойлерплейт для новых сущностей. Обычно это делается руками, иногда забывается, иногда делается неправильно.

go generate решает эту проблему. Вы один раз описываете команду прямо в коде, а потом запускаете одну команду и всё генерируется автоматически.

Как это работает

Вы добавляете специальный комментарий в .go-файл:
//go:generate mockgen -source=service.go -destination=mock_service.go -package=service


Потом запускаете:
go generate ./...


Go находит все такие комментарии в проекте и выполняет указанные команды. Всё.

Что можно генерировать

Моки для тестов. Если вы используете mockgen или moq, достаточно добавить комментарий рядом с интерфейсом и мок всегда будет актуальным:
//go:generate moq -out=user_repo_mock.go . UserRepository
type UserRepository interface {
FindByID(id int) (*User, error)
Save(user *User) error
}


Protobuf-файлы. Вместо того чтобы каждый раз вспоминать флаги protoc, достаточно один раз прописать команду:
//go:generate protoc --go_out=. --go-grpc_out=. api.proto


Встраивание ресурсов. Генераторы вроде go-bindata упаковывают статику прямо в бинарник.

Строковые представления для констант. stringer автоматически генерирует метод String() для ваших типов:
//go:generate stringer -type=Status
type Status int

const (
Active Status = iota
Inactive
Banned
)


Практический совет

Добавьте go generate ./... в ваш Makefile или CI-пайплайн. Тогда сгенерированный код всегда будет пересоздаваться при сборке, и никто не забудет обновить моки после изменения интерфейса:
generate:
go generate ./...

build: generate
go build ./...


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

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

#GoDeep
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11
🧑‍💻 Свой diff-драйвер для git

git diff умеет делегировать сравнение файлов внешнему инструменту. Это называется diff-драйвер. Штатный вывод git не всегда читаем особенно для JSON, YAML или OpenAPI-спецификаций. Вместо того чтобы смотреть на кашу из + и -, можно подключить инструмент, который покажет изменения в удобном виде.

Чем это отличается от textconv

Есть более простой способ — textconv. Он конвертирует файл в текст, и git сравнивает уже текст. Но если нужно не просто показать разницу построчно, а сформировать собственный вывод, например, changelog между двумя версиями API, textconv не подойдёт. Тут нужен полноценный драйвер.

Что git передаёт в драйвер

Многие ожидают, что инструмент получит два аргумента: файл «до» и файл «после». На самом деле git передаёт семь:
# при изменении существующего файла
my-diff-tool \
path/to/file.json # 1: путь к файлу в репозитории
/tmp/git-blob-xxx/file.json # 2: "до"
f0a1311ae439... # 3: SHA-1 хэш "до"
100644 # 4: octal mode "до"
/tmp/git-blob-yyy/file.json # 5: "после"
e39975894a72... # 6: SHA-1 хэш "после"
100644 # 7: octal mode "после"


При создании или удалении файла вместо несуществующей версии придёт /dev/null, а неприменимые аргументы заменяются точкой .:
# новый файл
my-diff-tool \
path/to/file.json
/dev/null # файла "до" не было
.
.
/tmp/git-blob-yyy/file.json
5c55e5b99b21...
100644

# удалённый файл
my-diff-tool \
path/to/file.json
/tmp/git-blob-xxx/file.json
6b24e38aa4aa...
100644
/dev/null # файла "после" нет
.
.


Пример драйвера:
#!/usr/bin/env bash

# diff-драйвер для OpenAPI-спецификаций через oasdiff

if [[ "$2" == "/dev/null" ]]; then
echo "$1 was added"
exit 0
elif [[ "$5" == "/dev/null" ]]; then
echo "$1 was deleted"
exit 0
fi

oasdiff changelog "$2" "$5" --color always


Аргументы $2 и $5 это пути к временным файлам «до» и «после», которые git уже подготовил.

Как подключить драйвер

В .gitattributes указываем, для каких файлов его использовать:
*.yaml diff=oasdiff


В .git/config или глобальном ~/.gitconfig регистрируем сам драйвер:
[diff "oasdiff"]
command = /path/to/oasdiff-driver.sh


После этого git diff будет вызывать скрипт для всех .yaml-файлов вместо стандартного построчного сравнения.

Diff-драйвер нужен, когда стандартный вывод git бесполезен. Написать его несложно: достаточно bash-скрипта, который принимает семь аргументов и знает, что делать с /dev/null для новых и удалённых файлов. Всё остальное берёт на себя git.

➡️ Источник

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

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

#GoToProduction
Please open Telegram to view this post
VIEW IN TELEGRAM
9👍2
🔒 internal: Go защищает архитектуру вашего проекта

Когда проект растёт, рано или поздно кто-то импортирует не то, что нужно. Репозиторий тянет сервис, хендлер лезет напрямую в базу и архитектура начинает разваливаться. Go решает это на уровне компилятора.

Что такое internal

Папка internal это встроенный механизм Go для ограничения импортов. Любой пакет внутри internal/ можно импортировать только из кода, который находится в родительском модуле этой папки. Всё остальное компилятор просто не пропустит.

Типичная структура проекта:
myapp/
├── cmd/
│ └── main.go
├── internal/
│ ├── service/
│ │ └── user.go
│ └── repository/
│ └── user.go
└── pkg/
└── utils/


Код в cmd/ может импортировать internal/service и internal/repository. А вот внешний пакет или другой модуль нет. Go выдаст ошибку компиляции:
imports myapp/internal/service: use of internal package not allowed


Можно вкладывать internal глубже

internal работает не только на уровне корня проекта. Его можно положить внутрь любого пакета:
myapp/
├── payment/
│ ├── internal/
│ │ └── processor/
│ └── payment.go


internal это не соглашение, а правило, которое компилятор применяет сам.

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

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

#GoDeep
Please open Telegram to view this post
VIEW IN TELEGRAM
16❤‍🔥5👍5🔥1🌚1
👀 Go-фреймворк для серверного UI без React и npm

Doors это бэкенд-фреймворк для веб-приложений на Go. Он позволяет строить реактивный UI без JS-фреймворков, без гидратации и без npm. Весь бизнес-логика живёт на сервере, браузер работает только как тонкий клиент для отображения.

Стандартный стек Go + React требует писать и поддерживать два слоя: API на Go и фронт на JS. Это дублирование типов, синхронизация состояния, сборка, зависимости. Htmx даёт частичные обновления страницы, но не даёт нормального реактивного состояния и контроля из Go.

Doors убирает API-слой полностью. Сервер держит живое состояние каждой вкладки пользователя, а браузер просто синхронизирует изменения DOM.

Как это работает

При загрузке страницы сервер создаёт экземпляр сессии и отдаёт cookie. Дальше между клиентом и сервером держится лёгкое соединение через короткие HTTP-запросы с поддержкой QUIC.

Пользователь что-то делает и событие летит на Go-обработчик. Сервер считает изменения и отдаёт конкретные обновления DOM.

Два ключевых примитива:

Door — динамический контейнер в HTML. Умеет обновляться, заменяться, удаляться. Каждый Door имеет свой жизненный цикл и локальный context, который можно использовать как хук при размонтировании.

Beam — реактивное состояние на сервере. SourceBeam хранит мутабельное значение, производные Beam считаются из него. Обновления гарантированно консистентны по дереву контейнеров.

Пример запуска:
import "github.com/doors-dev/doors"

func main() {
app := doors.New()
// регистрация страниц и обработчиков
app.Run(":8080")
}


➡️ Репозиторий

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

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

#GoToProduction
Please open Telegram to view this post
VIEW IN TELEGRAM
❤‍🔥8👍43🌚1
🌐 Топ-вакансий для Go-разработчиков за неделю

Senior Go Developer — удаленно по Москве

Golang Middle/Senior Developer — до 420 000 ₽, удаленно кроме РФ, РБ и Израиля

Junior Бэкенд-разработчик — от 80 000 до 120 000 ₽ в офис в Тамбове

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

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

#GoWork
Please open Telegram to view this post
VIEW IN TELEGRAM
🤩 Тесты с реальными сервисами без моков

Мокать базу данных — занятие неблагодарное. Каждое изменение схемы тянет за собой правки в моках, а уверенности в корректности поведения всё равно нет. Настоящий тест это тест против реального PostgreSQL, Redis или любого другого сервиса.

ory/dockertest
решает эту задачу: библиотека поднимает Docker-контейнеры прямо из Go-теста и убирает их по завершении.

Как это работает:
func TestPostgres(t *testing.T) {
pool := dockertest.NewPoolT(t, "")

postgres := pool.RunT(t, "postgres",
dockertest.WithTag("14"),
dockertest.WithEnv([]string{
"POSTGRES_PASSWORD=secret",
"POSTGRES_DB=testdb",
}),
)

hostPort := postgres.GetHostPort("5432/tcp")

err := pool.Retry(t.Context(), 30*time.Second, func() error {
db, err := sql.Open("pgx", "postgres://postgres:secret@"+hostPort+"/testdb")
if err != nil {
return err
}
return db.Ping()
})
if err != nil {
t.Fatalf("не удалось подключиться: %v", err)
}
}


Контейнер поднимается, тест выполняется, контейнер удаляется. Всё через t.Cleanup, без лишнего кода.

Установка:
go get github.com/ory/dockertest/v4


➡️ Репозиторий

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

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

#GoToProduction
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14😁1