Библиотека Go-разработчика | Golang
Все самое полезное для Go-разработчика в одном канале. Учиться у нас: clc.to/qaSdww По рекламе: @proglib_adv Для обратной связи: @proglibrary_feeedback_bot РКН: https://gosuslugi.ru/snet/67a4a8c24689c2151c752af0 #WXSSA
Ko'proq ko'rsatish📈 Telegram kanali Библиотека Go-разработчика | Golang analitikasi
Библиотека Go-разработчика | Golang (@goproglib) Rus til segmentidagi kanali faol ishtirokchi. Hozirda hamjamiyat 23 929 obunachidan iborat bo'lib, Texnologiyalar & Aralashmalar toifasida 5 589-o'rinni va Rossiya mintaqasida 27 749-o'rinni egallagan.
📊 Auditoriya ko‘rsatkichlari va dinamika
невідомо sanasidan buyon loyiha tez o‘sib, 23 929 obunachiga ega bo‘ldi.
06 Iyul, 2026 dagi oxirgi ma’lumotlarga ko‘ra kanal barqaror faollikka ega. Oxirgi 30 kunda obunachilar soni -88 ga, so‘nggi 24 soatda esa -4 ga o‘zgardi va umumiy qamrov yuqori darajada qolmoqda.
- Tasdiqlash holati: Tasdiqlanmagan
- Jalb etish (ER): Auditoriya o‘rtacha 11.51% darajada jalb etiladi. Nashrdan keyingi dastlabki 24 soatda kontent odatda umumiy obunachilar sonining 7.44% ini tashkil etuvchi reaksiyalarni to‘playdi.
- Post qamrovi: Har bir post o‘rtacha 2 754 marta ko‘riladi; birinchi sutkada odatda 1 781 ta ko‘rish yig‘iladi.
- Reaksiyalar va o‘zaro ta’sir: Auditoriya faol: har bir postga o‘rtacha 9 ta reaksiya keladi.
- Tematik yo‘nalishlar: Kontent навигация, лучшее_из_библиотеки_2025, git, string, golive kabi asosiy mavzularga jamlangan.
📝 Tavsif va kontent siyosati
Muallif resursni shaxsiy fikrni ifoda etish maydoni sifatida ta’riflaydi:
“Все самое полезное для Go-разработчика в одном канале.
Учиться у нас: clc.to/qaSdww
По рекламе: @proglib_adv
Для обратной связи: @proglibrary_feeedback_bot
РКН: https://gosuslugi.ru/snet/67a4a8c24689c2151c752af0
#WXSSA”
Yuqori yangilanish chastotasi (oxirgi ma’lumot 07 Iyul, 2026 da olingan) sababli kanal doimo dolzarb va katta qamrovli bo‘lib qoladi. Analitika auditoriya kontent bilan faol hamkorlik qilishini, uni Texnologiyalar & Aralashmalar toifasidagi muhim ta’sir nuqtasiga aylantirishini ko‘rsatadi.
Ma'lumot yuklanmoqda...
| Sana | Obunachilarni jalb qilish | Esdaliklar | Kanallar | |
| 06 Iyul | +7 | |||
| 05 Iyul | +6 | |||
| 04 Iyul | +8 | |||
| 03 Iyul | +9 | |||
| 02 Iyul | +7 | |||
| 01 Iyul | +4 |
[T Constraint[T]] заработало не только для функций, но и для объявлений обобщённых типов. Один из приёмов, которые это открывает, это клонирование с сохранением конкретного типа.
Что это решает
Представьте пайплайн, стадии которого форкаются под A/B эксперименты, и каждому форку нужно своё независимое состояние. Стадии имеют разные конкретные типы.
Если написать обобщённое копирование, которое возвращает интерфейс Stage, вызывающий код получит абстракцию и не сможет использовать результат как *TransformStage без приведения типа. Приведение прячется где-то в глубине кода, компилятор перестаёт вам помогать, а в рантайме появляется место для паники.
До 1.26 выразить «операция над T возвращает T» на уровне объявления обобщённого типа было нельзя. Компилятор ругался на рекурсивный тип.
Как это работает
Идея в том, что параметр типа T появляется в ограничении на сам T. Тип обязан уметь клонировать именно себя:
type Cloneable[T any] interface {
Clone() T
}
// DeepCopy возвращает T, а не Cloneable[T].
func DeepCopy[T Cloneable[T]](v T) T {
return v.Clone()
}
Тот же приём на реальном пайплайне выглядит так:
type Stage[T any] interface {
Clone() T
Execute(ctx context.Context, event Event) (Event, error)
Name() string
}
// ForkStage возвращает T, а не Stage[T].
// Вызывающий получает *TransformStage, без приведения.
func ForkStage[T Stage[T]](s T) T {
return s.Clone()
}
На вызове конкретный тип остаётся живым:
original := &TransformStage{ /* ... */ }
fork := ForkStage(original) // fork имеет тип *TransformStage
fork.SomeSpecificMethod() // доступно без приведения
Тип пронесён через операцию целиком. Ни одного скрытого .(TransformStage) в коде.
Паттерн решает не переиспользование алгоритма, а сохранение идентичности типа. Когда значение порождает копию себя, вы хотите получить обратно тот же конкретный тип, а не супертип, про который компилятор молча забывает. Для форков состояния, снапшотов и любых самоклонирующихся структур это убирает целый класс приведений и связанных с ними рантайм-багов.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека Go-разработчика
#GoToProduction| 2 | 👣 Многие разработчики приходят в Go с багажом паттернов из Java и C#. В результате простой и понятный код постепенно обрастает слоями абстракций, лишними интерфейсами и десятками DTO, которые усложняют поддержку проекта.
🗓 8 июля в 20:00 МСК приглашаем вас на открытый урок в преддверии старта курса «Go-разработчик. Продвинутый уровень». На занятии разберём, почему привычные подходы из других языков не всегда работают в Go, как выстроить архитектуру через Handler → Service → Repository без циклических зависимостей, где действительно нужны интерфейсы и как избежать избыточных абстракций.
❗️Вы узнаете, какие ошибки чаще всего встречаются на проверках кода, научитесь проектировать приложения с понятным разделением ответственности и поймёте, как писать код, который останется читаемым и через полгода.
➡️ Регистрируйтесь и познакомьтесь с подходом, который помогает писать на Go проще, надёжнее и профессиональнее: https://clc.to/gqjQAA
Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru | 1 466 |
| 3 | 💻 Фреймворк, где файловая система это карта маршрутов
Связка Go и HTMX хорошо стартует, но со временем почти каждый проект обрастает одним и тем же обвесом. Диспетчер маршрутов, стек лейаутов, безопасные URL, проверки на устаревшую генерацию, отпечатки ассетов, команды для отладки.
Без общего фреймворка каждое приложение изобретает свою приватную конвенцию роутинга и растаскивает строковые пути по хендлерам, шаблонам, редиректам и тестам.
goldr стандартизирует этот слой и при этом оставляет приложение явным.
➡️ Что делает goldr
goldr это server-first, HTML-first, HTMX-native фреймворк на Go. Он не вытаскивает центр тяжести из Go. Файловая система становится картой маршрутов,
.templ файлы владеют HTML, HTMX остаётся видимым прямо в разметке, хендлеры остаются обычным Go, а сгенерированный код берёт на себя повторяющуюся работу вокруг маршрутов.
Вы получаете полный рабочий цикл приложения на Go и HTMX. Это маршрутные страницы, вложенные лейауты, HTMX-фрагменты, экшены на мутации, сгенерированные хелперы для URL, live reload, отпечатанные и встроенные статические ресурсы, команды инспекции маршрутов и визуальный инспектор в браузере, который умеет подсвечивать области отрендеренной страницы.
При этом приложение по-прежнему владеет своим net/http сервером, миддлварями, статикой, авторизацией, сессиями, парсингом запросов, валидацией и деплоем. goldr не компилирует CSS, не бандлит JavaScript, не регистрирует хендлеры за вас и не выбирает CDN.
➡️ Как устроены маршруты
В goldr файловая система и есть карта маршрутов. Директория маршрута это единица локального поведения:
app/routes/
layout.go -> логика лейаута для / и ниже
layout.templ -> HTML лейаута
route.go -> GET /
page.templ -> HTML страницы
users/
route.go -> GET /users, GET /users/table, POST /users/create
page.templ -> HTML страницы users
by_id/
route.go -> GET /users/{id}
page.templ -> HTML детальной страницы
frag_table.templ -> HTML фрагмента
Один route.go объявляет страницу, HTMX-фрагменты и POST-экшены для этой части приложения:
var Route = goldr.RouteDef{
Page: page,
Fragments: goldr.Fragments{
goldr.FragmentRoute("/table", table),
},
Actions: goldr.Actions{
goldr.Action(http.MethodPost, "/create", postCreate),
},
}
Из файловой системы и этих объявлений goldr генерирует диспатч и типобезопасные хелперы URL. Вместо захардкоженных путей шаблоны ссылаются на сгенерированные хелперы:
urls.Users.Path()
urls.Users.Table.Path()
urls.Users.Create.Path()
urls.Users.ByID.Bind(id).Path()
Важно, что HTMX остаётся видимым на месте вызова. Сгенерированный путь фрагмента подставляется прямо в атрибут hx-get, а не прячется за проприетарными компонентами:
templ UsersView() {
<button
hx-get={ urls.Users.Table.Path() }
hx-target="#users-table"
hx-swap="innerHTML"
>
Refresh users
</button>
<div id="users-table"></div>
}
Директория by_id/ маппится в динамический сегмент {id}. Подчёркивания в статических именах превращаются в дефисы в URL, поэтому Go-безопасное имя build_info/ отдаёт путь /build-info.
➡️ Команды разработки
goldr dev держит локальный цикл в движении. Он генерирует templ и маршруты, отпечатывает ассеты, перезапускает приложение и перезагружает браузер. goldr generate обновляет обвязку маршрутов, хелперы URL, вывод templ и отпечатки ассетов одной командой. goldr check проверяет, что сгенерированные файлы актуальны, ничего при этом не записывая.
Команды routes list, routes explain и routes layouts показывают дерево маршрутов из терминала, а routes refs собирает прямые HTMX-ссылки из .templ файлов.
Если у вас растёт Go-приложение с HTMX, которое должно оставаться читаемым, goldr стоит посмотреть.
➡️ Репозиторий
Иногда маршруты ведут сюда.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека Go-разработчика
#GoToProduction | 1 287 |
| 4 | 🔥 Открытое занятие по AgentOps — курс стартовал!
Сегодня в 19:00 по МСК пройдет первое занятие нового потока, на которое может прийти каждый. Оцените пользу нашего подхода на ретрансляции урока в VK!
👨💻 Спикер: Андрей Носов
Тема: Архитектура управления: state machine для AI-агентов
Будем разбираться, как использовать State machine в качестве главного оружия против стохастики (непредсказуемости) LLM.
Что в программе:
● State machine: инварианты и терминальные состояния;
● Паттерны маршрутизации: Supervisor, ReAct, Plan-and-Solve;
● Детекция циклов и настройка аварийных выходов;
● Абстракция от модели: как сделать каркас, который переживет смену LLM/провайдера;
● Адаптация графов под ограничения локальных моделей;
● Версионирование графов и миграции стейта.
Результат занятия: Вы поймете, как спроектировать надежный каркас агента с жестким контролем исполнения и переходов.
👉 Подписывайтесь на нашу группу ВКонтакте, чтобы не пропустить старт трансляции! | 1 556 |
| 5 | 👨💻 Шардируйте локи или ускорение in-memory кеша до 8 раз
Конкурентный in-memory кеш в Go часто пишут через один sync.Mutex. Пока нагрузка низкая, всё в порядке. Но под конкурентным доступом единственный лок превращается в узкое место, и добавление ядер не помогает, а иногда даже вредит.
Миша Стребков собрал один и тот же кеш string → string шестью способами на чистой стандартной библиотеке и прогнал бенчмарки под чтением, сбалансированной нагрузкой и записью на 1–8 ядрах. Порядок победителей меняется в зависимости от профиля, а одно «очевидное» решение с ростом числа ядер работает медленнее.
Шесть вариантов
1. naive это обычная map без блокировок, не потокобезопасна и падает на конкурентной записи.
2. mutex использует один sync.Mutex, прост и корректен, но не масштабируется.
3. rwmutex даёт параллельные чтения и эксклюзивную запись через sync.RWMutex.
4. syncmap это встроенная sync.Map.
5. sharded разбивает данные на 256 частей, у каждой свой мьютекс, ключ выбирает часть по хешу.
6. cow реализует copy-on-write через atomic.Pointer, чтения без блокировок, но каждая запись копирует всю мапу.
➡️Что показали замеры
sharded и cow наращивают пропускную способность с ростом ядер, а mutex остаётся плоским. Более того, у mutex на 8 ядрах пропускная способность падает до 0.66 от одноядерной. Чтения не идут параллельно, а кеш-линия с локом гоняется между ядрами. Вы добавили железо и потеряли производительность.
rwmutex упирается в потолок около 2× и перестаёт расти после 4 ядер. Счётчик читателей сам становится точкой конкуренции. На записи он оказывается хуже обычного мьютекса.
cow выигрывает на чистом чтении с огромным отрывом, 87 миллионов операций в секунду на 8 ядрах. Но как только появляется запись, он проваливается почти в ноль, потому что каждый Set копирует мапу на миллион записей.
sharded единственный дизайн, который держится у вершины во всех профилях сразу.
Победитель в пятнадцати строках
sharded это просто N независимых мап, каждая под своим локом. Хеш ключа выбирает часть, поэтому операции над разными ключами почти никогда не трогают один и тот же лок. Конкуренция падает примерно в N раз:
const shards = 256 // степень двойки, чтобы маскировать вместо modulo
type part struct {
mu sync.Mutex
m map[string]string
}
type Sharded struct{ parts [shards]*part }
func (c *Sharded) at(key string) *part {
h := uint64(14695981039346656037) // FNV-1a
for i := 0; i < len(key); i++ {
h = (h ^ uint64(key[i])) * 1099511628211
}
return c.parts[h&(shards-1)]
}
func (c *Sharded) Get(key string) (string, bool) {
p := c.at(key)
p.mu.Lock()
v, ok := p.m[key]
p.mu.Unlock()
return v, ok
}
func (c *Sharded) Set(key, value string) {
p := c.at(key)
p.mu.Lock()
p.m[key] = value
p.mu.Unlock()
}
Одна деталь про явный Unlock. На Go 1.26 замер показал, что defer p.mu.Unlock() здесь стоит около +8% (примерно 1 нс) поверх явного анлока. На горячем пути это заметно, поэтому горячие методы разблокируют лок явно.
Почему 256 частей
Достаточно, чтобы убить конкуренцию, и не так много, чтобы жечь память. Свип количества частей на 8 ядрах и сбалансированной нагрузке растёт круто до 256, а дальше выходит на плато. Переход от одного лока к 256 даёт скачок в 9 раз (с 4.6 до 43 миллионов операций в секунду). После 256 отдача падает, 1024 добавляют +13%, 4096 всего +18% при кратно большем расходе памяти.
Цифры на 8 ядрах, ns/op, меньше лучше, равномерное распределение
mix mutex rwmutex syncmap sharded cow
read-only 168 53 30 21 11.5
read-heavy 168 259 37 22 12000000
balanced 190 282 57 24 46500000
write-heavy 208 222 73 25 82500000
Восьмизначные значения cow в столбце записи реальные и указаны в наносекундах. 82 500 000 нс это 82 миллисекунды на один Set. Такова цена чтений без блокировок.
➡️ Что использовать
По умолчанию берите sharded. Он лучший или почти лучший везде, масштабируется с ядрами и пишется тривиально. Это ответ для большинства конкурентных мап.
cow подходит для данных, которые почти всегда только читают. Это снапшоты конфигов, таблицы маршрутизации, feature-флаги. Чтения непобедимы, но только если записи редкие и батчатся. Для записи он не годится.
sync.Map берите в её нише, ключи пишутся один раз и читаются вечно, либо горутины работают с непересекающимися наборами ключей. За пределами этого она посредственна и аллоцирует (40–72 B/op).
sync.RWMutex нужен редко. Он выигрывает только в узком углу с преобладанием чтений и малым числом ядер, а на записи хуже обычного мьютекса.
Обычный mutex нормален при низкой конкуренции или малом числе ядер. Не тяните за сложность, потребность в которой не можете измерить.
Рост числа ядер сделал кеш на одном мьютексе медленнее, и это чистая конкуренция за кеш-линию самого лока. RWMutex оказался полумерой, которая бьёт по записи. Перекос нагрузки (Zipf) это палка о двух концах, а не равномерный штраф, он ускоряет чтения за счёт кеш-локальности и одновременно концентрирует конкуренцию на записи.
Весь код, сырой вывод benchstat и однокомандный свип для воспроизведения лежат в репозитории.
➡️ Источник
Нашу новостную рассылку не нужно ускорять, она и так быстрая
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека Go-разработчика
#GoDeep | 1 467 |
| 6 | ❓ Нужны ли посты на CD-дисках по почте | 2 021 |
| 7 | 🤖 Дайджест недели
Первый июльский дайджест
— GitHub предлагает выслать код на CD-диске
GitHub иронично отреагировал на решение Sony прекратить выпуск дисков для PlayStation. Теперь разработчики могут заполнить специальную форму и получить свой публичный репозиторий записанным на физический CD-ROM.
— 1 часть цикла постов про сравнение двух структур
— Учимся уходить красиво
— gokrazy/rsync v0.3.4
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека Go-разработчика
#GoLive | 2 114 |
| 8 | 🧑💻 В Go предлагают лимит на количество HTTP заголовков
В репозитории Go обсуждают новое поле Server.MaxHeaderValueCount в пакете net/http. Статус уже Likely Accept, идёт финальный период комментариев. Если всё пройдёт гладко, поле появится в Go 1.28.
Сейчас сервер net/http ограничивает заголовки только по общему размеру через MaxHeaderBytes. Отдельного лимита на их количество нет. Этим пользуются атаки типа DoS. Злоумышленник шлёт тысячи мелких заголовков, например с именем в один байт без значения. На проводе такой заголовок почти ничего не весит, но во внутренних структурах сервера каждый занимает заметно больше памяти.
Реализация HTTP/2 в Go к DoS атаке устойчива. Сервер закладывает 32 байта накладных расходов на каждое значение заголовка при подсчёте MaxHeaderBytes. Но пользователи всё равно в неудобном положении. Кому нужны большие заголовки, скажем SSO куки на несколько килобайт, приходится поднимать MaxHeaderBytes. Вместе с лимитом растёт и число мелких заголовков, которые сервер готов принять. Слишком большой лимит открывает дорогу DoS, слишком маленький ломает легитимные запросы. Один параметр на два разных риска.
Предлагаемое решение выглядит так:
package http
// DefaultMaxHeaderValueCount is the maximum permitted number of
// header values in an HTTP request.
// This can be overriden by setting [Server.MaxHeaderValueCount]
const DefaultMaxHeaderValueCount = 500
type Server struct {
// Other fields omitted...
// MaxHeaderValueCount controls the maximum number of header
// values that the server is willing to parse from a request.
// If zero, DefaultMaxHeaderValueCount is used.
MaxHeaderValueCount int
}
По умолчанию сервер примет не больше 500 значений заголовков на запрос. Считают именно значения, а не имена. Иначе атакующий мог бы прислать один заголовок с огромным числом пустых значений и обойти лимит.
Ждать релиза Go 1.28 необязательно. Автор предложил переходный вариант через переменную окружения, он оформлен отдельным issue 80020. Запуск выглядит так.
GODEBUG=httpmaxheadervalues=500 ./your-server
Значение из GODEBUG задаёт дефолт, а явно выставленное поле в Server будет иметь приоритет.
Если у вас сервис на Go с большим MaxHeaderBytes, стоит следить за этим proposal. Новый параметр позволит держать оба лимита раздельно и защищаться от лавины мусорных заголовков без риска сломать реальный трафик.
➡️ Наша новостная рассылка не имеет лимитов
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека Go-разработчика
#GoLive | 2 234 |
| 9 | 📋 Чек-лист из 8 признаков, что вас скоро уволят
Услышали на созвоне слово «оптимизация» больше трех раз? Поздравляем, Вы уже в процессе.
Статья про то, как компания вежливо, но разрушительно, готовит вас к уходу: задачи исчезают, не зовут на встречи, условия труда волшебным образом меняются, а повышение замораживают на бесконечность. Все это не совпадение, все это признаки.
➡️ Пройтись по чек-листу
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека Go-разработчика | 2 144 |
| 10 | 📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека Go-разработчика
#GoGiggle | 2 053 |
| 11 | 🎬 Как ИИ ускоряет разработку и где ломаются архитектуры
Мы провели открытый вебинар, где разобрали реальные боли проектирования автономных систем. Ольга Лукьянова на практическом кейсе показала, как использовать ИИ-ассистентов для реальных задач. Вы просили запись встречи — она уже в открытом доступе!
Что внутри:
— Как с помощью ИИ быстрее разбираться в незнакомом коде и готовить пулл-реквесты;
— Критерии выбора между одним агентом и мультиагентной системой;
— Разбор популярных архитектурных ошибок и ограничений современных ИИ;
— Практические рекомендации по проектированию и внедрению облачных агентов.
👉 Посмотреть полную запись можно тут:
● VK
● YouTube
🚀 Хотите пойти дальше открытого вебинара? Если вы готовы перейти от простых промптов к проектированию надежных, отказоустойчивых ИИ-систем, которые не сливают бюджет компании на API, приходите на курс AgentOps. Поток уже стартовал, но двери еще приоткрыты!
👉 Успеть на курс AgentOps | 2 054 |
| 12 | 🤓 Go получит SIMD-инструкции без ассемблера
Сейчас, если нужно использовать SIMD в Go, есть по сути один путь — писать ассемблерные вставки руками. Это медленно, легко ошибиться, а ещё такой код нельзя инлайнить и он мешает асинхронной вытесняющей многозадачности рантайма.
Для задач вроде обработки векторов, хеширования, парсинга протоколов или AI-инфраструктуры это ощутимое ограничение. Команда Go предложила решение — добавить архитектурно-специфичные SIMD-интринсики прямо в язык, без изменения синтаксиса.
Что предлагают
Идея в двухуровневом подходе. Низкий уровень — это архитектурно-специфичный пакет simd, где операции почти один в один соответствуют машинным инструкциям. Высокий уровень — портируемый API поверх него, который появится позже. Сравнение с syscall и os тут в тему. Большинство кода будет работать с высокоуровневым API, а для редких случаев останется доступ к низкоуровневым операциям.
На старте фокус на AMD64. Пробуется всё это под флагом GOEXPERIMENT=simd, ветка называется dev.simd.
Векторные типы описаны как непрозрачные структуры, компилятор распознаёт их и хранит в векторных регистрах:
type Uint32x4 struct { a0, a1, a2, a3 uint32 }
type Float64x4 struct { a0, a1, a2, a3 float64 }
Операции реализованы как методы:
// Сложение элементов двух векторов.
// Соответствует инструкции VPADDD на x86.
func (Uint32x4) Add(Uint32x4) Uint32x4
Загрузка и сохранение работают через указатель на массив нужного размера:
func LoadUint32x4(*[4]uint32) Uint32x4
func (Uint32x4) Store(*[4]uint32)
Отдельно продуманы маски. На разных архитектурах маска хранится по-разному — где-то это регистр с одним битом на элемент, где-то обычный векторный регистр. Поэтому маска тоже сделана непрозрачным типом, а компилятор сам выбирает представление в зависимости от того, как маска используется дальше:
func (Uint32x4) AddMasked(Uint32x4, Mask32x4) Uint32x4 // VPADDD.Z
func (Uint32x4) Equal(Uint32x4) Mask32x4 // VCMPEQD или VPCMPD
Для проверки поддержки процессором нужных возможностей добавлены функции вроде HasAVX512(). Компилятор считает их чистыми функциями, поскольку они не меняются после старта программы, и может использовать это для оптимизаций.
Предложение сейчас в статусе active и рассматривается на еженедельных встречах по Go-предложениям. Часть операций, как Gather и Scatter, отложена на Go 1.27 из-за вопросов безопасности памяти. Портируемый высокоуровневый API и поддержка масштабируемых векторов, таких как ARM64 SVE, тоже в планах на будущее.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека Go-разработчика
#GoLive | 2 222 |
| 13 | 📹 Что должен делать агент-оркестратор?
Посмотрите короткий отрывок из вебинара с Дмитрием Юдиным, внутри концентрат инсайтов о ии-агентах. А если хотите погрузиться в тему с головой, у нас доступна и полная запись этого эфира.
Готовы перейти от теории к практике и собрать свой первый продакшн-кейс?
Прямо сейчас действует мощная акция «3 курса по цене 1»:
🔥 При покупке VIP-тарифа нового потока «Разработка ИИ-агентов» вы получаете в подарок хардкорный курс «AgentOps» + ещё один любой курс Академии на ваш выбор!
Выгода в цифрах: два топовых курса по созданию и контролю агентов обойдутся вам всего в 134.000 ₽ вместо 263.000 ₽. Плюс третий курс бонусом (например, можно подтянуть математику для AI). Ваша чистая экономия — 129 000 ₽!
Сомневаетесь, подойдет ли вам формат? Оставьте заявку и пройдите бесплатный демо-урок, чтобы протестировать платформу перед покупкой.
👉 Пройти демо-урок и забрать 3 курса по цене 1 | 2 134 |
| 14 | 💡 Интересный факт о http.ListenAndServe
Второй параметр в http.ListenAndServe обязателен, но на самом деле Go — это гибкий язык.
Когда вы передаёте nil в качестве хендлера, то есть несколько вариантов, которые приходят в голову: паника, 404 на все запросы или сервер попросту не запустится.
➡️ Узнать ответ
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека Go-разработчика
#ReadySetGo | 2 205 |
| 15 | 🔄 Вышел gokrazy/rsync v0.3.4
gokrazy/rsync это реализация протокола rsync на чистом Go, и клиент, и сервер, с поддержкой передачи файлов в обе стороны.
В версии v0.3.4 решены три проблемы
➡️ Политику landlock расширили, добавив в неё /etc, а на gokrazy ещё и /tmp, потому что без доступа к этим путям через какое-то время ломалось разрешение DNS на системах с запущенным Tailscale.
➡️ Отдельно поправили совместимость с новыми версиями форка openrsync от Apple, и закрыли баг, из-за которого передача файла иногда падала с ошибкой file has changed mid-transfer.
➡️ Из менее заметного, но полезного, в релиз попал вклад нового контрибьютора, добавляющий клиенту возможность задать собственный net.DialContext. Это позволяет управлять тем, как именно устанавливается сетевое соединение, например проксировать его или привязывать к конкретному интерфейсу, не трогая остальной код клиента.
Если вы используете gokrazy/rsync вместе с Tailscale или синхронизируете большие файлы, которые могут меняться во время передачи, обновление до v0.3.4 стоит того, чтобы не упираться в уже известные и закрытые баги.
➡️ Репозиторий
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека Go-разработчика
#GoLive | 2 340 |
| 16 | 👨💻 Лишние проверки на nil в Go. Когда защита от паники превращается в проблему
В коде на Go всё чаще встречается одна и та же картина, почти перед каждым обращением к указателю стоит if x != nil. Выглядит как разумная подстраховка, но часто это сигнал, что в системе уже не понятно, какие значения действительно могут быть nil, а какие нет, и проверяется всё подряд на всякий случай.
➡️ Проверка на зависимость
Структура RateLimiter хранит клиент Redis:
func (r *RateLimiter) Allow(ctx context.Context, req *Request) (bool, error) {
userID := GetUserID(req)
if r.redis != nil {
return r.checkLimit(ctx, userID)
}
return false, nil
}
Проверка r.redis != nil ничего не лечит. Если клиент равен nil, ошибка произошла раньше, при инициализации, и проверка здесь просто позволяет коду работать дальше в уже сломанном состоянии.
В Go лучше падать сразу и громко, чем тащить невалидное состояние по системе.
Перенос проверки в конструктор NewRateLimiter выглядит лучше, но тоже не решает задачу до конца, потому что nil всё равно успевает дойти до конструктора. Правильное место для обработки ошибки это сама точка создания клиента:
redisClient, err := NewRedisClient(addr)
if err != nil {
return nil, err
}
limiter := NewRateLimiter(redisClient)
Если клиент создан успешно, дальше по системе он уже не может быть nil, и проверки внутри RateLimiter просто не нужны. Если же системе важно переживать временную недоступность Redis, это стоит явно смоделировать отдельным типом, который сам внутри себя справляется с повторами, а наружу всегда отдаёт нечто гарантированно рабочее.
➡️ Громкий отказ
Частый аргумент в пользу лишних проверок звучит так, не хочу ронять программу из-за своего изменения, лучше залогировать и продолжить. Только выбор здесь не между падением и продолжением работы, а между громким отказом и тихим.
Явная ошибка заметна сразу, привязана к месту, где она произошла, и понятно, какая операция не удалась. Проглоченная ошибка устроена наоборот, она всплывает позже, после того как уже отработал другой код, и к моменту, когда виден симптом, найти причину сложнее.
На тихие отказы потом приходится тратить силы отдельно, выстраивая метрики и алерты, чтобы заметить то, что сами же и спрятали.
➡️ Где проводить границу
Полезно думать о коде как о внешнем и внутреннем слое. Внешний слой это там, где данные входят в программу, например HTTP-обработчик. Внутренний слой это код, до которого эти данные доходят дальше по стеку вызовов:
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
req, err := DecodeRequest(r)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
allowed, err := h.limiter.Allow(r.Context(), req)
// ...
}
Проверять запрос на nil нужно один раз, на границе, в момент декодирования. После этого Allow уже может работать с запросом как с доверенными данными, без единой проверки на nil внутри.
Проверка на nil уместна, когда она охраняет границу системы или моделирует осознанно опциональное состояние. Если же она тихо обрабатывает состояние, которое по замыслу вообще не должно быть возможным, это уже сигнал проблемы в дизайне. Решение тогда не в том, чтобы добавить ещё проверок, а в том, чтобы постепенно установить инварианты, на которые сможет опираться остальной код.
➡️ Оригинал
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека Go-разработчика
#GoDeep | 2 210 |
| 17 | 🖥 Эмулятор ZX Spectrum на Go
Писать ретро-эмуляторы и тестировать их это разные удовольствия. Эмулятор обычно требует окна, видеокарты, звуковой системы, и каждый прогон автотеста превращается в проблему, особенно в CI, где никакого дисплея просто нет.
Либо приходится гонять эмулятор руками и проверять результат на глаз, либо городить виртуальный X-сервер только ради одного теста.
zenzx — эмулятор ZX Spectrum на Go. Помимо обычного графического режима он умеет работать совсем без окна, просто прогонять нужное число кадров и сохранять результат в виде PNG.
➡️Что умеет эмулятор
ZenZX поддерживает модели 48K, 128K, +2 и +3, включая контроллер дисковода у модели +3, а также загрузку с ленты и снапшоты. Собирается он в двух вариантах.
GUI-сборка по умолчанию рендерит через raylib, с поддержкой звука, и требует CGO вместе с системными библиотеками OpenGL, X11 или Wayland, и ALSA. Headless-сборка собирается с тегом headless, не требует CGO, не открывает окно и не трогает звуковую карту. Она загружает модель, прогоняет заданное число кадров и сохраняет PNG-снимки экрана, декодированные прямо из видеопамяти.
➡️ Сборка и запуск
Для обычной сборки нужны Go 1.25 или новее, а для GUI-варианта ещё и C-тулчейн с raylib и oto:
./build.sh # обычный GUI-бинарник, нужны CGO и системные библиотеки
./build_headless.sh # headless-бинарник без CGO
Запуск GUI выглядит так:
./zenzx -model=48k
./zenzx -model=128k
./zenzx -model=plus3
./zenzx -tape=game.tap -tapemode=accurate
ZenZX интересен не столько как ещё один эмулятор Спектрума, а как пример того, как отделить эмуляцию от рендеринга и звука так, чтобы можно было гонять её в CI или в скрипте без единого окна.
➡️ Репозиторий
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека Go-разработчика
#GoToProduction | 2 232 |
| 18 | ОПРОС: Ответьте на пару вопросов и получите промокод на все наши курсы! 🎁
Команда Prоglib.аcаdemy готовит к запуску новые продукты, и нам нужна ваша помощь. Мы хотим создавать обучение, которое будет решать ваши реальные карьерные задачи и бить точно в цель.
Поделитесь своим опытом и ожиданиями, чтобы мы сделали наши курсы еще полезнее именно для вас! Заполнение анкеты займет буквально 2–3 минуты, а с нас — скидка на любой наш курс!
👉 Пройти опрос в Яндекс Формах и забрать промокод | 2 205 |
| 19 | 👨💻 Сравнение двух Go-структур без хардкода полей. Часть 4, указатели, nil и выводы
В прошлой части мы дошли до момента, где надо сравнить два поля. На этом месте чаще всего ломаются наивные реализации. Реальные модели базы полны *string, *int64, *time.Time. Указатель может быть nil, то есть «значения нет».
Сравнение указателя с не-указателем, или двух указателей, где один nil, требует аккуратности:
dtoIsPtr := dtoField.Kind() == reflect.Ptr
dbIsPtr := dbField.Kind() == reflect.Ptr
if dtoIsPtr && dbIsPtr {
if dtoField.IsNil() && dbField.IsNil() {
continue // оба nil, ничего не изменилось
}
if dtoField.IsNil() != dbField.IsNil() {
// одна сторона nil, другая нет, это точно изменение
if dtoField.IsNil() {
updateMap[dbGormColumnName] = nil
} else {
updateMap[dbGormColumnName] = dtoField.Elem().Interface()
}
continue
}
// оба не nil, разворачиваем и сравниваем значения
dtoField = dtoField.Elem()
dbField = dbField.Elem()
} else if dtoIsPtr || dbIsPtr {
// смешанный случай, одна сторона указатель, другая обычное значение
if dtoIsPtr {
if dtoField.IsNil() {
updateMap[dbGormColumnName] = nil
continue
}
dtoField = dtoField.Elem()
}
if dbIsPtr {
if dbField.IsNil() {
updateMap[dbGormColumnName] = dtoField.Interface()
continue
}
dbField = dbField.Elem()
}
}
Кода много, но каждая ветка отвечает на один вопрос. Оба nil, делать нечего. Один из двух nil, наличие значения изменилось, пишем nil или новое значение. Оба заданы, разворачиваем и сравниваем как обычные значения. Смешанный случай, разворачиваем ту сторону, что указатель. Ошибка тут даёт либо лишние обновления, либо пропущенные, и оба бага видны только в проде.
Сравнение значений
Когда обе стороны развёрнуты до обычных значений, остаётся сравнить. Ожидаешь однострочник a.Interface() == b.Interface(), но есть ловушка. Одно и то же логическое число может храниться разными типами. В DTO поле CityID int, а в модели базы CityID int64. Для оператора == в Go это разные типы, и сравнение их упакованных форм вернёт false.
Поле будет помечаться как изменённое при каждой синхронизации. Поэтому compareValues приводит числовые семейства к общему виду:
func (m *Mapper) compareValues(a, b reflect.Value) bool {
aKind := a.Kind()
bKind := b.Kind()
switch {
case m.isSignedInt(aKind) && m.isSignedInt(bKind):
return a.Int() == b.Int()
case m.isUnsignedInt(aKind) && m.isUnsignedInt(bKind):
return a.Uint() == b.Uint()
case m.isSignedInt(aKind) && m.isUnsignedInt(bKind):
return a.Int() >= 0 && uint64(a.Int()) == b.Uint()
case m.isUnsignedInt(aKind) && m.isSignedInt(bKind):
return b.Int() >= 0 && a.Uint() == uint64(b.Int())
case m.isFloat(aKind) && m.isFloat(bKind):
return a.Float() == b.Float()
default:
return a.Interface() == b.Interface()
}
}
Методы .Int(), .Uint() и .Float() расширяют любую разрядность до самой большой формы, так что int8, int16, int, int64 сворачиваются в одно сравнение. Случаи знаковое против беззнакового защищены проверкой >= 0, чтобы отрицательное число не превратилось в гигантское беззнаковое. Всё, что не число, падает в обычный ==.
У рефлексии есть свои минусы, и автор перечисляет их прямо. Она медленнее прямого доступа к полям, но для реакции на события и горстки записей это неважно. Вы теряете проверку маппинга на этапе компиляции, опечатка в теге match не уронит сборку, поле просто не сматчится, и тут спасает маленький юнит-тест на структуру. Сравниваются только плоские скалярные поля, вложенные структуры и срезы идут как один непрозрачный кусок. Неэкспортируемые поля недоступны.
Весь приём это смена вопроса. Вместо «как сравнить эти две конкретные структуры» автор спросил «как сравнить любые две структуры, которые сами рассказали, как их поля соотносятся». Теги уже несли эту информацию для GORM и JSON, осталось добавить один тег и научить маленькую функцию его читать.
Получилось около 130 строк рефлексии вместо растущей кучи хрупких блоков if. Код работает на всех моделях и становится проще в поддержке по мере роста системы. Если ловите себя на том, что пишете одну и ту же логику по полям в N-й раз, проверьте, не лежат ли метаданные для обобщения прямо в ваших тегах. Чаще, чем кажется, они там уже есть.
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека Go-разработчика
#GoDeep | 2 181 |
| 20 | 😋 Топ-вакансий для Go-разработчиков за неделю
Go Developer — удаленно по Москве
Middle Golang разработчик — от 320 000 ₽, удаленно
Senior Golang Developer — до 500 000 ₽, гибрид в Москве или удаленно
➡️ Еще больше топовых вакансий — в нашем канале Go jobs
🐸 Библиотека Go-разработчика
#GoWork | 2 335 |
Endi mavjud! Telegram Tadqiqoti 2025 — yilning asosiy insaytlari 
