Go Update
3.11K subscribers
8 photos
73 links
Канал про новости связанные с языком программирования Go. Эволюция языка, стандартной библиотеки и просто интересные вещи над которыми работает Go Core Team и не только.

Админ: @lepage_d
Download Telegram
Минутка юмора.

Можете отправить это человеку который продолжает вас убежать в том, что ChatGPT скоро заменит всех разработчиков инженеров людей.
😁44🗿7🤡2😐1
Про нововведения в Go 1.24

Долго собирался написать серию (хотя бы один!) постов про вещи которые к нам подъедут в Go 1.24, но так никак и не смог собраться. А потом обнаружил, что один наш коллега уже все это сделал в подробном и, главное, интерактивным виде. Правда есть нюанс — сам пост на английском.

Однако тем кто не знает английского не стоить грустить — методом гуглежки было обнаружено, что от него же есть серия статей которая почти полностью дублирует записи в блоге. И оно в телеграмме! Поэтому смело идем и начинаем читать, что нас ждет в предстоящей версии.

П.С. Ну а я постараюсь в ближайшее время запилить обзор предложение от Яна Ланса Тейлора о новом синтаксисе обработки ошибок и как оно разделило сообщество почти поровну.
👍121
0️⃣ Omitzero или убираем пустые значения при серилизации в json

Я уверен, что большинство в курсе о том, что пакет json поддерживает структурный тег omitempty. На данный момент это единственный прямолинейный способ указать, что поле не следует выводить в json если оно содержит нулевое значение. Однако у этого тега есть два минуса:

1. Он плохо работает со структурами.
2. Он неумеет в переопределение принципа по которому определяется сам факт нулевого значения.

Оба пункта довольно долго портили кровь разработчикам сложных вложенных API и заставляли их пользоваться указателями, там, где можно было обойтись без них. И вот Go Team приняла волевое решение и реализовала новый тег. Встречаем omitzero. Принцип работы прост до невозможности:

1. Если поле это структура и она пустая, то маршалить ее он не будет.
2. Если у типа поля определен метод IsZero и он вернул true то и его маршалить не будут.

КМК именно это можно было привезти еще в версии Go 1.10, т.к. фиче не нужны новые языковые фишки, а необходимость ее была видна еще с Go 1.1. Чтож, лучше поздно чем никогда.
👍358
🎉 Вышел Go 1.24! 🎉

Этот момент настал!

Ключевые нововведения:
— Дженерики теперь умеют в псевдонимы (aliases) т.е. теперь можно писать так


type MyType[T any] = myType[T,*T]


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

— Теперь можно отслеживать версии и использовать утилиты прямо с помощью команды go tool. Краткий смысл сего: оно помещает все зависимости добавляемой тулзы в require блок, а саму утилиту в блок tool. Учтите, что если вы не указываете отдельный go.mod файл с помощью флага -modfile (его принимают большинство команд) то зависимости внешней тулзы перемешаются с вашими. Однако есть и хорошая новость — из-за умного механизма «вычистки» MVS если кто то импортирует ваш модуль, то зависимости которые нужны для утилит к нему не попадут.

go test теперь гоняет go vet с небольшим числом анализаторов перед запуском тестов для поиска распространенных ошибок (в том числе ошибок в оформлении тестов). go vet тоже подтянули, теперь, например, ругается на printf функции где аргумент только строка.

— Бинари запущенные с помощью go run и go tool теперь кешируются внутри внутри билд кэша. Никаких больше пересборок на каждом go run.

go build и go install научили в json вывод.

— С помощью новой переменной окружения GOAUTH можно определить принцип для авторизации на приватных серверах модулей. Подробности с помощью go help goauth

go build теперь вставляет в бинарь информацию о версии (наконец-то можно перестать делать это вручную!) с использованием тега и/или хеша коммита вашего гита (или mercurial и прочая).

— Новая реализация map на основе Swiss Tables. Бигтехи ваши вопросы на собесах больше неактуальны 🤡.

— Инлайнинг стал мощнее. Теперь, с большей вероятностью, тело функции которую вы передаете как аргумент будет вставлено в место ее вызова. Делали в основном для итераторов которые уступали по скорости циклам. Вместе с прошлым изменением и прочими изменениями в рантайме дало совокупный буст в 3-5% по производительности.

— Различные улучшения CGO с помощью новых директив.

— Новый способ гонять бенчи for b.Loop() { ... }. Основной плюс (кроме того, что меньше писать) в том, что гонялке бенчмарков больше не нужно вызывать вашу функцию несколько раз, ибо сама найдет нужные параметры во время цикла. А значит дорогие блоки инициализации и удаления по итогу бенча стали дешевле.

— С помощью переменной окружения GOCACHEPROG можно настроить свое утилиту которое будет отвечать за кеширование, вместо стандартного «все на диск в папочку». Пригодиться тем, у кого распределенные билды или много чего собирается в докере. Документация.

— Пакет со слабыми указателями стал доступен всем.

— Подъехала замена финалайзерам. С типобезопастностью и сигнатурой которая намекает как делать правильно (и длинной докой объясняющей все сценарии). А еще их можно повесить сколько угодно в отличии от финалайзеров. Почему это важно я писал ранее.

— Пакет testing/synctest который в будущем позволит нам полностью дропнуть все моки времени. Пока обещают изменения API поэтому скрыто за флагом GOEXPERIMENT=synctest

— Появился OpenRoot. TLDR: открыв каталог таким образом из него нельзя убежать используя симлинки и прочая. Штука интересная для тех у кого пути до файлов генерируются извне.

— Куча прочих улучшений, включая новый функции для итераторов в пакеты bytes и strings.

— У тестов и бенчей появился свой контекст! Можно будет дропнуть кучу кода отвечающего за создание контекстов в тестах.

Полное описание (жирного) релиза вот тут.
🔥41👍186
Немного юмора.
😁64🤯6😨3
😢 Ян Ланс Тейлор покидает Google 😢

После 19 (!!!) лет работы и более 16 лет работы над нашим языком Go, Ян Ланс Тейлор объявил о том, что покидает Google.

В числе его заслуг:
— Работа компилятора Go.
— GCCGO фронтенд который позволяет собирать программы на Go с использованием компилятора GCC.
— Дженерики, которые появились в версии 1.18.
— Поддержка Go во внутренней системе сборки SWIG Google.
— Куча предложений и работ над улучшением языка.

Сам Ян говорит, что очень доволен своей работой. Go развивается и его принятие рынком растет гораздо быстрее чем оригинальная команда могла даже вообразить когда начинала работу над языком. Однако вместе с этим ему видно, что сам Google изменился, язык Go изменился и вообще ландшафт языков программирования изменился с тех пор как он начал эту работу. В течении последнего года он понял, что больше не подходит для работой над Go внутри Google. И пришла пора двигаться дальше.

На некоторое время возьмет перерыв от работы, но надеется, что ему еще удастся поработать над Go в будущем.

П.С. Мужик, конечно, легенда — работает на OSS и GNU проектами с 1990 года. Желаю ему хорошо отдохнуть и продолжать делать крутые вещи.

П.П.С. После ухода Яна и ухода Расса с должности руководителя Go (но не ухода из Google!) из старой гвардии остался только Роберт Гризмер. С одной стороны это хорошо — значит язык не зависит от конкретных людей. С другой есть волнение за будущее языка и то как новые лица справятся с таким наследием. Поживем — увидим!
😐24😨15👍96🤯2😁1😡1
🔀 Динамический GOMAXPROCS 🔀

До релиза Go 1.25 осталось около недели, а значит, самое время восполнить пробелы и написать всё то, о чем я (по-хорошему) должен был рассказать в течение последнего полугодия разработки новой версии языка. Начнем с небольшого, но значимого изменения: динамического GOMAXPROCS.

Для тех, кто не в курсе: Go позволяет определить число горутин, которые могут одновременно выполняться в пределах рантайма. Ключевое слово — одновременно. Это значит, что горутин у вас может быть сколько угодно, но выполняться из них (лопатить код, а не находится в ожидании сети, файлов или ответа из сишной либы), в момент времени, будет только число, указанное в GOMAXPROCS. По-хорошему, это число обычно равно числу физических ядер на вашем CPU. Но в серверных окружениях начинаются тонкости, главная из которых, cgroups, является столпом для Docker и K8S.

Смысл вот в чем: в контейнеризированном мире на приложение может быть выделено даже не ядро, а фракция или квота, при этом значения сии могут быть динамическими и изменяться в процессе работы кластера. Процесс может ошибочно исходить из того, что у него есть 64 ядра всего блейда (и как следствие — возможность 64-х активных потоков), но по факту доступных именно нашему процессу ядер намного меньше. И это не вдаваясь в подробности таких вещей, как "привязка к ядрам CPU конкретного процесса" которые актуальны в NUMA окружениях.

До версии Go 1.25 эту проблему частично решала библиотека automaxprocs от Uber, которая выставляла значения наиболее приближенные к ожидаемым оркестратором. Но делала она это только один раз и только на старте. Кроме того, много людей банально не знали об этой тонкости работы рантайма Go и, как следствие, неправильно использовали доступные ресурсы CPU.

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

На изменение GOMAXPROCS будут влиять в совокупности три вещи:

• Изменение числа ядер на машине.
• Изменение привязки приложения к ядрам CPU.
• И, специально для Linux, средний лимит пропускной способности, основанный на квотах CPU cgroup.

Стоит заметить, что это изменение, при всех его очевидных плюсах, имеет один, но явный неочевидный минус — если вы шардировали кеши по числу GOMAXPROCS то вас ожидают очень неприятные паники или скачки нагрузки. Поэтому, если-же вас по какой-то причине не устраивает новое поведение, то у вас есть целых три варианта:

• Вы можете не выставлять в go.mod версию go 1.25.x — обновление придёт к вам только когда вы захотите перейти на поведение языка версии 1.25.
• Вы можете самостоятельно выставить GOMAXPROCS с помощью переменных окружения или с помощью функции GOMAXPROCS. В таком случае автообновление будет выключено, и рантайм доверится вашему суждению.
• Также можно оставить прошлое поведение с помощью GODEBUG переменных containermaxprocs=0 и updatemaxprocs=0.

P.S. Для полноценного мониторинга Go теперь держит в памяти дескриптор доступа к файлам cgroups на время жизни всего процесса.
🔥41👍10👏3
🏎️ Об оптимизациях в Go 1.25 🏎️

В новом релизе, как и всегда, к нам приедут новые оптимизации для компилятора. Две из них меня заинтересовали больше всего:

• Цепочка из четырёх 1, 2, 3, 4 PR, суть которых можно описать с помощью одного примера:


var x []int

for i := 0; i < 4; i++ {
x = append(x, i)
}


Если в Go 1.24 и ранее такой код приводил к аллокации в хипе, то начиная с Go 1.25 — нет. А всё просто: make и append теперь, в большинстве случаев, не аллоцируют память в хип до 32 байтов включительно. Вместо этого они используют память на стеке и лишь при превышении объёма начинают идти в хип. Такая вот консервативная оптимизация для слайсов всех типов.

Нулевые значения и "константные" переменные больше не аллоцируют память в хипе при присвоении значения интерфейсу. Продемонстрировать проще всего вот так:


type doubleInt struct{ value1, value2 int }

localVariable := doubleInt{value1: 3, value2: 2}
globalAny = any(localVariable)

localVariable2 := doubleInt{}
globalAny2 = any(localVariable2)


Если ранее подобный код приводил к аллокации, то теперь компилятор достаточно умён, чтобы на этапе компиляции выделить специальное read-only место в памяти и использовать именно его во время исполнения. Особенно приятно, что reflect.Value.IsZero теперь использует сравнение по указателю для нулевых значений структур и массивов, что существенно удешевляет проверку.
🔥214👍3👏1
Короче я нашёл проблему — ребята которые делают Swift телеграмм так «удачно» подобрали цвета, что именно в моей «стоковой» теме моношрифт и ссылки выглядят одинаково. Удобство 11/10!
😁63
Немного примеров из комментариев. Мне кажется где-то заплакал UX дизайнер.
😁7
Об обсуждениях.

Вот уже более тринадцати лет нормальный синтаксис неподвижно обсуждается на GitHub.
По воле отцов-основателей выступает Повелитель Простоты и правит миллионами микросервисов благодаря мощи своего неисчислимого бойлерплейта.
Он — гниющий реликт минимализма, в ком незримые муки разработчиков продлеваются загадочными отказами «это не вписывается в философию».
Он — незыблемый столп экосистемы, которому каждый день приносят в жертву тысячи бестолковых предложений о try-catch, идиотские идеи
которых были озвучены уже десятки раз, а все самопротиворечащие доводы высказаны и рассмотрены.
На боли и страданиях гоферов стоит тот самый "Idiomatic Go"


Вы знаете, что такое безумие?

Кто-то скажет, что факт того, что язык получивший свой релиз в 2012-ом году, но не имевший дженериков аж до 2022го — это безумие. На что можно резонно возразить: дескать, нормальный синтаксис — это полдела, основная проблема в экосистеме! Другие могут сказать, что почти все реализации (включая и ту, которую в итоге получили мы) обладают рядом минусов и требуется их хорошо продумать, перед тем как вносить этот инструмент в язык. Третьи скажут, что внесение дженериков в язык привлекает внимание C++ любителей всё усложнять, а сам Go был ценен в первую очередь простотой и понятливостью даже свежему после универа программисту. Короче: оправданий можно придумать массу. На самом деле доподлинно никто не знает, почему внедрение дженериков заняло так много времени, поэтому любые попытки найти рациональное объяснение — не более чем «игра для ума» (по-простому — ещё один способ вентиляции лёгких), которая не несёт в себе никакой практической пользы.

Нет, скажу я вам. Безумие это хождение по кругу годами в поисках идеального синтаксиса который устроит всех. Например, обсуждение синтаксиса лямбд, которое ведётся уже более 8 лет и которое, по итогу, так и не сдвинулось с места. Синтаксиса! Не семантики и не деталей реализации. Ибо главный выбор, который остался перед нами, — это то, «будет ли новый синтаксис использовать =>, или ->, а может, \-> для разделения объявления и тела лямбды?». И если кто-то думает, что я шучу, то ему достаточно глянуть issue, в котором уже больше 900 скрытых комментариев, по которым уже несколько раз делали сводку (вручную, с помощью Gabby, с помощью других LLM, комбинацией из трёх прошлых способов) и которое раз за разом возвращается назад, к своему началу. К выбору идеального синтаксиса. К безумию.

Честно — у меня нет цензурных слов. Если вам когда-нибудь хотелось узнать, что такое "Bikeshedding" (в русском языке нет прямого перевода, но термин расшифровывается как «бессмысленное обсуждение тривиальных вопросов»), то это обсуждение — самый наглядный пример, который у меня есть. Где-то полгода назад, когда, как мне казалось, картинка начала выкристаллизовываться, я хотел написать об этом запись в блоге. И попросить людей поучаствовать, если им есть что высказать или подсказать, ведь это шанс поучаствовать в развитии языка, а создатели действительно слушают мнение людей по этому вопросу! Теперь я понимаю — первый раз за долгое время меня спасло то, что я что-то не сделал. Ибо с тех пор, несмотря на как минимум два резюме по итогам «ещё одной итерации обсуждения», продвижения по-прежнему нет.

Я не знаю, какой здесь сделать вывод. Но я уверен, что нас ждёт ещё минимум столько же комментариев в будущем.

In the grim darkness of the far future there is only "if err != nil".
12👍4🔥2👀2🗿1
⏲️ testing/synctest — останавливаем время ⏲️

Одними из самых сложных сценариев для тестирования являются сценарии где замешано время. Если использовать реальное время то тесты либо а) начинают занимать слишком много времени либо б) теряют в надежности из-за гонки "кода со временем". Особенно хорошо это ощущается в тестах которые используют time.Ticker, time.Timer и time.AfterFunc для управление потоком исполнения.

Приведу очень простой пример:

ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()

for {
select {
case <-time.After(500 * time.Millisecond):
println("do work...")
case <-ctx.Done():
println("Context done:", ctx.Err())
}
}


Для того, что-бы убедиться, что наш код выведет "do work..." 4 раза нам нужно подождать примерно 2 секунды, в течении которых наша программа фактически ничего не делает. Более того, нет никаких гарантий, что наш текст будет выведен именно 4 раза, а не 3 или 2 с учетом нагрузки на планировщик ОС.

Когда такой тест у нас один это нормально. Когда у нас их десятки это проблема. А когда у нас их за сотню то это минуты простаивающего CI, который мог бы делать что-то полезное. И тут у нас есть два решения:

• В пределах тестов кратно уменьшить время "ожидания". Допустим не 500мс а 50. Или вообще 5мс. Проблема такого подхода в том, что исполнение (и работа планировщика) тоже занимает время и тест становится менее надежным. При этом проблема "впустую потраченного времени" никуда не уходит.
• Используем одну из сторонних библиотек для "подделки" времени и замыкаемся на ее семантику (и баги) по всей программе.

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

Хорошая новость, что разработчики языка озаботились это проблемой, и в Go 1.25 пакет synctest стал наконец доступен любому желающему. Публичное API содержит всего две функции:

Первая это synctest.Test. Она запускает замыкание в изолированном пространстве-пузыре где время течёт "иначе". Все горутины созданные внутри этого замыкания разделяют этот "пузырь". Время в них стоит на месте, до тех пор пока все горутины не станут "прочно заблокированы". Термин "прочно заблокированы" может прозвучать странно, но по сути это лишь определенный набор блокировок которые приводят к сдвигу времени в "пузыре». Вот их полный список:

• Блокирующая попытка посылки или получения данных из канала созданного в том же "пузыре".
select с блокирующими операциями над каналами созданным в том же "пузыре".
• Вызов sync.Cond.Wait или time.Sleep.
sync.WaitGroup.Wait, если sync.WaitGroup.Add был вызван из того же "пузыря" (не горутины, это важно).

Однако следующие операции не приводят к "прочной блокировке" горутин:
• Лок мьютексов.
• Блокировка на операциях ввода-вывода (файлы, сеть и прочая).
• Сисколлы.

Вторая функция это synctest.Wait(). Ее единственная роль — дождаться момента когда все горутины в "пузыре" достигли "прочной блокировки" и затем вернуться.

Таком образом как только все горутины "прочно заблокированы" происходит одно из следующих:
• Если Wait был вызван, то он возвращается. Время не сдвигается.
• В противном случае время внутри "пузыря" сдвигается на достаточную величину для запуска в работу хотя-бы одной горутины если функция создававшая "пузырь" не закончила исполнение.
• В противном случае, происходит дедлок и наш вызов Test паникует.

Проще всего понять на живом примере (код не влез в этот пост). Обратите внимание, что время выставлено в часы однако время теста и порядок вывода в лог сохраняется раз за разом. Так мы обеспечиваем не только быстрое исполнение, но и ожидаемый детерминизм. Другой плюс нового пакета, заключается в том, что если горутина создавшая "пузырь" выйдет до того, как закончат работу все её дочерние горутины, то вы получите панику (пример). Таким образом на этапе тестирования еще и обеспечивается контроль очистки ресурсов.

Для более подробной документации рекомендую глянуть документацию. Там-же приведены и другие примеры, сценарии и особенности работы.
👍11🔥3
Go Update
⏲️ testing/synctest — останавливаем время ⏲️ Одними из самых сложных сценариев для тестирования являются сценарии где замешано время. Если использовать реальное время то тесты либо а) начинают занимать слишком много времени либо б) теряют в надежности из…
А теперь по простому:

func TestTime(t *testing.T) {
time.Sleep(365 * 24 * time.Hour)
go func() {
println("inside goroutine")
time.Sleep(time.Second)
}()

println("outside goroutine")
time.Sleep(time.Second)
}


Этот код не закончит исполнение в ближайший год.

func TestTime(t *testing.T) {
synctest.Test(t, func(t *testing.T) {
time.Sleep(365 * 24 * time.Hour)
go func() {
println("inside goroutine")
time.Sleep(time.Second)
}()

synctest.Wait()
println("outside goroutine")
time.Sleep(time.Second)
})
}


А этот код закончит исполнение менее чем за микросекунду и всегда выведет сначала "inside goroutine" а потом "outside goroutine".
17👍4
🛡️ Go 1.25: встроенная защита от CSRF в net/http 🛡️

Тем временем разработчики стандартной библиотеки продолжают упрощать нам жизнь. Практически всё кто связаны с вебразработкой слышали про атаку CSRF. Суть в том, что используя форму (и не только) злонамеренный сайт может заставить ваш браузер выполнить, например, перевод денег из банка на другой счёт, если у банка нет защиты от CSRF, а у вас в этот момент действующая кука от ЛК банка.

Я не буду касаться описания принципов работы "same site" и "same origin", так как про это написано уже масса статей, а коснусь лишь основных механизмов защиты от CSRF:

• Вместе с кукой присылать скрытый <input> в котором присылать дубль токена, который идет в самой куке. Если при запросе то, что в форме и то, что в куке не совпало — запрос отклоняется. Недостаток в том, что токен надо привязывать к пользователю и добавлять в каждую форму.
• Проверять через заголовок Origin что инициатор запроса был сам исходный сайт, а не сторонний. Тоже обладает рядом минусов (может быть null при кривых плагинах), и требует довольно сложной настройки для правильной поддержки cross-origin запросов.
• SameSite куки и "Non-simple requests" которые защищают от вариантов атаки HTTP -> HTTPS но в общем случае бесполезны.

На данный момент для защиты от CSRF в нашей экосистеме есть две либы: csrf и nosurf. Обе работают через дубль токена (т.е. требуют донастройки фронта) и обе почти не поддерживаются разработчиками.

Поэтому Go 1.25 в пакет net/http добавили готовую «прослойку» для защиты от CSRF, построенную на механизме Fetch Metadata который присутствует во всех современных браузерах с 2023го года.

Заголовок с сайта банка при запросе через fetch в таком случае будет выглядеть так:

GET /money/foo.json
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty


В то время как заголовок от зловредного сайта при «прямой» подгрузке будет выглядеть вот так


GET /money/cool.jpg
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: no-cors
Sec-Fetch-Dest: image


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

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

• Браузер добавляет Sec-Fetch-Site (same-origin / same-site / cross-site / none). Хендлер смотрит это заголовок, и если это не same-origin или none а метод это POST/PUT/PATCH/DELETE то запрос режется. Тоже самое если нет Sec-Fetch-Site: тогда смотрим Origin и сравниваем с Host и опять же, в случае несовпадения, режем POST/PUT/PATCH/DELETE запросы.
• В случае если дополнительно установлен список ориджинов через метод AddTrustedOrigin то полученный запрос сравнивается по заголовку Origin пока не будет найдет нужный, или запрос не будет отклонен.
• Запросы без Sec-Fetch-Site и без Origin пропускаются тк их явно не мог сделать браузер, защищать нечего.
• «Безопасные» методы GET/HEAD/OPTIONS всегда пропускаются (уповают на то, что вы не меняете состояние в этих методах и следуете разумным практикам)

Для более сложных случаев предусмотрены методы AddInsecureBypassPattern и функция SetDenyHandler которая явно разрешает запрос.
👍165
Осталось написать (и разобраться) про новый экспериментальный сборщик мусора и программа минимум будет закрыта 😄
👍176😁2
Go Update
🎂 Тем временем Земля сделала полный оборот вокруг Солнца, и мне исполнилось 32. В этот раз буду предельно краток: я жив, у меня всё хорошо, и этот блог не заброшен. Единственное, чего мне пока очень сильно не хватает, — это времени. Заметок скопилось за три…
🎂 Настал тот день когда мне исполнилось 33!

Да, да тот самый год, в который вас поздравляют используя аналогии к одной из самых ярких личностей в истории человечества 😁️️️️️️.

В (не)далеком детстве, когда мне было лет 7-8, я смотрел на взрослых, которым было за 30 (что казалось мне очень-очень далеко), и она казались кем-то, кто такой «опытный, мудрый, знающий». Думал, что вот: вырасту я, и сам буду такой взрослый-серьезный-мудрый. Машину водить, детей воспитывать. В очках ходить.

И вот теперь мне за 30. Я вожу машину (иногда даже две). Я воспитываю сына. Я хожу в очках (что кстати минус). И вот, что я вам скажу: хрень это все про «вырастишь, сам поймешь!». Фраза пустышка, которую так любили повторять родители и старшие близкие в процессе воспитания, но которая ничего под собой не имеет. Я не чувствую себя опытнее. Или мудрее. Или более знающим. Я ничего так и не «понял». Из года в год я надеюсь, что настанет тот самый магический момент когда я стану наконец «взрослым» (и хотя-бы перестану влезать в бессмысленные споры в чатике которые могут съесть час в лучшем случае). Но этот момент всё никак не настаёт.

Тем более последние годы здорово перевернули жизнь, а рождение сына, два года назад, вообще заставило взглянуть на себя по новому. Но вот сказать, что я теперь я стал весь из себя такой «мудрый-разумный» я не могу. В душе мне по прежнему кажется, что я ментально застрял где-то в возрасте 17-19 лет. Я по прежнему смотрю на своих друзей и вижу в них школьников а не серьезных дядь, коими я видел взрослых будучи мелким. При фразе «пропусти дядю!» я по прежнему оглядываюсь, пытаясь найти того самого «дядю». А вот единственное чего с годами становится объективно меньше это время, и как следствие сил. И то просто из-за количества рутинных дел которые приходится делать день за днём. Та вещь фундаментально непонятна когда тебе 8 и времени хватает на всё и даже больше.

В общем тут уже идет пятый параграф и надо бы начать подводить итоги. И вот мой итог на следующий год: надо нормально спать. Наверное это самая важная мудрость, которую я никак не могу постигнуть. Если вам между 18 и 28-30, то знайте, что «ремонт сбитого режима, за два дня, без регистрации и смс» это не навсегда. Я пишу эти строки сонный, ибо лёг поздно (пункт про время), а в 5 утра меня поднял сын «кики мама не, кики папа мими да!», что в переводе означало что «ему хочется кефир, а мама просыпаться отказалась». Пока просыпался-вставал-наливал-ждал-укладывал сон слетел и пришлось укладывать еще и себя (что гораздо дольше). В общем на сегодня сделал вывод, что на следующий ночной сон пойду вместе с ним. Но вот вечером я вероятно опять найду оправдание в голове, что-бы этого не делать…

Какой уж тут «опытный, мудрый, знающий» если банальный сон привести в порядок не можешь.

П.С. Статья про новый сборщик мусора делается, надеюсь успеть до релиза Go 1.25.
🔥4524👏3
Go Update
🎉 Вышел Go 1.24! 🎉 Этот момент настал! Ключевые нововведения: — Дженерики теперь умеют в псевдонимы (aliases) т.е. теперь можно писать так type MyType[T any] = myType[T,*T] Поздравляю тех, кому приходилось работать с указателями в дженериках, теперь…
🎉 Вышел Go 1.25! 🎉

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

♻️ Бинарей в комплекте теперь меньше. Разработчики компилятора активно использовать команду go tool у себя внутри, что убирает необходимость поставлять заготовки в комплекте. Но как минимум go build и go test бинари все еще на месте.

— Новая директива ignore в go.mod. Подробное описание тут. Если в вкратце: для этого вы раньше использовали каталог testdata и каталоги которые начинаются с точки.

— Когда go команда обновляет go 1.xx.y директиву в go.mod она больше не добавляет toolchain директиву.

go vet теперь ругается на неправильное использование sync.WaitGroup.Add и fmt.Sprintf("%s:%d", host, port) ибо есть net.JoinHostPort.

🍵 Новый экспериментальный сборщик мусора. О нем статья будет позже.

🔀️️️️️️ Новый тип runtime/trace.FlightRecorder позволяет записывать только значимые события, а не всё подряд для tracing’га (под капотом используется циклический буфер, который помнит N последних секунд).

🛠 Компилятор теперь генерирует дебаг-инфу в формате DWARF5. Практический итог: бинари едят меньше места и быстрее комбинируются.

🏎️️️️️️ Новый экспериментальный пакет encoding/json/v2. По хорошему про него тоже надо писать отдельную статью, но если в кратце — он намного быстрее того что было внутри encoding/json. А другая хорошая новость заключается в том, что если вы включили GOEXPERIMENT=jsonv2 то больше ничего менять не надо, так как encoding/json сам подключит новую внутряку.

— Тип os.Root приобрел несколько новых методов.

🏎️️️️️️ Функция reflect.TypeAssert позволяет приводить типы из reflect.Value в конкретный тип, минуя потенциально аллоцирующий вызов reflect.Value.Interface.

— Директива GODEBUG=checkfinalizers=1 позволяет понять, как дела в вашей очереди cleanup’ов и finalizer’ов во время каждого GC.

SetDefaultGOMAXPROCS позволяет сбросить настройки GOMAXPROCS если вдруг переменная прилетела через Env или через прошлый вызов GOMAXPROCS.

— Новый метод sync.WaitGroup.Go - больше нет необходимости тащить errgroup если вам не нужен был возврат ошибок и отмена контекста.

🔥testing.T/B/F теперь имеют метод Output() io.Writer который позволяет правильно редиректить вывод внутри вызова теста.

Читать про релиз вот тут.
🔥2633👍2