🧪 Сравнение инструментов для генерации моков
https://habr.com/ru/companies/avito/articles/939388/
Семён Эйгин из Авито (мейнтейнер minimock) сравнивает три популярных инструмента для генерации моков:
- mockery
- gomock
- minimock
Очевидно, автор предвзят, но статья всё равно интересная. Просто учитывайте это во время чтения.
Какие проблемы обсуждаются:
1. Типизация параметров
- mockery и gomock используют
- minimock генерирует строго типизированные методы:
- На практике: можно пропустить ошибку в стиле
2. Контроль количества вызовов
- gomock по умолчанию разрешает только один вызов метода
- mockery и minimock позволяют неограниченные вызовы
- Двойственная ситуация: gomock помогает поймать лишние вызовы, но требует явного
3. Тестирование асинхронного кода
- mockery: приходится встраивать каналы через
- gomock: нужен самописный хелпер с
- minimock: встроенная поддержка через
————
Выбор автора, предсказуемо — minimock как "самый простой и топорный, покрывающий 99% случаев".
И я в целом согласен: строгая типизация экономит время на дебаге, встроенная поддержка асинхронности избавляет от костылей.
Хотя, я не отношусь к выбору моков настолько же серьёзно — я сам всё ещё использую mockery, потому что описанные его минусы не столь существенны, чтобы мне захотелось взять и перейти на что-то другое.
#article #testing #mocks
https://habr.com/ru/companies/avito/articles/939388/
Семён Эйгин из Авито (мейнтейнер minimock) сравнивает три популярных инструмента для генерации моков:
- mockery
- gomock
- minimock
Очевидно, автор предвзят, но статья всё равно интересная. Просто учитывайте это во время чтения.
Какие проблемы обсуждаются:
1. Типизация параметров
- mockery и gomock используют
interface{}
в ожиданиях: GetUser(1)
интерпретируется как int вместо int64- minimock генерирует строго типизированные методы:
Expect(id int64)
- На практике: можно пропустить ошибку в стиле
(int64=1) != (int=1)
2. Контроль количества вызовов
- gomock по умолчанию разрешает только один вызов метода
- mockery и minimock позволяют неограниченные вызовы
- Двойственная ситуация: gomock помогает поймать лишние вызовы, но требует явного
Times()
или AnyTimes()
3. Тестирование асинхронного кода
- mockery: приходится встраивать каналы через
RunAndReturn
— плохо масштабируется- gomock: нужен самописный хелпер с
controller.Satisfied()
- minimock: встроенная поддержка через
mc.Wait(timeout)
————
Выбор автора, предсказуемо — minimock как "самый простой и топорный, покрывающий 99% случаев".
И я в целом согласен: строгая типизация экономит время на дебаге, встроенная поддержка асинхронности избавляет от костылей.
Хотя, я не отношусь к выбору моков настолько же серьёзно — я сам всё ещё использую mockery, потому что описанные его минусы не столь существенны, чтобы мне захотелось взять и перейти на что-то другое.
#article #testing #mocks
Хабр
Самый лучший мок на свете: разбираемся с инструментами для генерации моков в Go
Всем привет! Меня зовут Семён Эйгин, я бэкендер в Авито , люблю опенсорс и периодически что-то туда контрибьючу. В этой статье разбираемся с моками и выбираем самый удобный инструмент (не обязательно...
50👍12🤔2
Bubble Tea — TUI-фреймворк для Go
https://habr.com/ru/articles/939574/
Коротенький обзор фреймворка Bubble Tea. Сам обзор ни чем особо не примечателен, но фреймворк шикарный, очень рекомендую. Если вы любите красивые консольные утилиты. вам точно понравится.
#article #tui
https://habr.com/ru/articles/939574/
Коротенький обзор фреймворка Bubble Tea. Сам обзор ни чем особо не примечателен, но фреймворк шикарный, очень рекомендую. Если вы любите красивые консольные утилиты. вам точно понравится.
#article #tui
Хабр
Bubble Tea — TUI-фреймворк для Go. Мои открытия и ошибки
Недавно я наткнулся на Bubble Tea — терминальный UI-фреймворк для Go, и буквально влюбился в то, как он отрисовывает интерфейсы в консоли . В репозитории есть множество примеров — и...
👍11🔥8
Forwarded from Николай Тузов
Golang Дайджест
Bubble Tea — TUI-фреймворк для Go https://habr.com/ru/articles/939574/ Коротенький обзор фреймворка Bubble Tea. Сам обзор ни чем особо не примечателен, но фреймворк шикарный, очень рекомендую. Если вы любите красивые консольные утилиты. вам точно понравится.…
Раз уж на то пошло, советую обратить внимание вообще на все проекты Charm, там много интересного. Например:
- Bubbles — готовые компоненты для Bubble Tea: текстовые поля, списки, таблицы, прогресс-бары, спиннеры.
- Lip Gloss — библиотека стилей для терминальных приложений. Цвета, рамки, отступы, выравнивание — всё как в CSS, только для консоли. Используется как база для Bubble Tea.
- Gum — эдакий мост между Bubbles / Lip Gloss и shell-скриптами. То есть, можно делать те же красивые скрипты, но без кода на Go.
- Glow — рендеринг Markdown прямо в терминале с подсветкой синтаксиса и красивым форматированием. Можно читать README не выходя из консоли.
- VHS — записывает GIF/видео демонстраций терминальных приложений через простой скрипт. Идеально для документации и README.
- Soft Serve — self-hosted Git-сервер с TUI интерфейсом. Можно красиво смотреть репозитории, коммиты и файлы прямо через SSH
Ну и наше любимое:
- Crush — красивый консольный ИИ-агент . Поддерживает разные LLM (Claude, GPT, Gemini), использует LSP для контекста как в IDE, можно переключаться между моделями на лету.
Это только самое интересное, но там ещё много всякого. Советую пройтись по всему списку проектов и ознакомиться с каждым.
Вся экосистема построена вокруг идеи: терминал может быть красивым и удобным. И у них это отлично получается
Теперь подумываю сделать большое обзорное видео про всё это. Будет ли вам такое интересно?
#cli #tui
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
Charm
We make the command line glamorous. Charm has 49 repositories available. Follow their code on GitHub.
1👍18🔥4❤1
🐳 Container-aware GOMAXPROCS: Go наконец-то видит лимиты контейнеров
Пост в официальном блоге разработчиков Go, где они подробно рассказывают суть проблемы и как устроено недавнее техническое решение.
Go Team решили давнюю проблему совместимости с контейнерами. До версии 1.25 Go определял все ядра хоста, не учитывая CPU limits контейнера. Теперь GOMAXPROCS выставляется в соответствии с лимитами автоматически.
Суть проблемы:
- Контейнеру выделено 2 CPU на машине с 128 ядрами
- Go видит 128 ядер, создаёт кучу тредов
- Linux throttling тормозит приложение каждые 100ms
- Tail latency растёт
Что изменилось в 1.25:
- Go читает cgroup CPU limits и ставит GOMAXPROCS по ним
- Динамически обновляется при изменении лимитов
- Работает из коробки — просто обновите go.mod
- CPU requests игнорируются (только limits)
————
Наконец-то.. Проблеме много лет, и всё это время приходилось костылить через uber/automaxprocs или ENV-переменные. А теперь оно работает из коробки, как и должно было уже давно.
P.S. В Java эту проблему решили ещё в 2017 году😩
#go1_25 #go_official #kubernetes #docker
Пост в официальном блоге разработчиков Go, где они подробно рассказывают суть проблемы и как устроено недавнее техническое решение.
Go Team решили давнюю проблему совместимости с контейнерами. До версии 1.25 Go определял все ядра хоста, не учитывая CPU limits контейнера. Теперь GOMAXPROCS выставляется в соответствии с лимитами автоматически.
Суть проблемы:
- Контейнеру выделено 2 CPU на машине с 128 ядрами
- Go видит 128 ядер, создаёт кучу тредов
- Linux throttling тормозит приложение каждые 100ms
- Tail latency растёт
Что изменилось в 1.25:
- Go читает cgroup CPU limits и ставит GOMAXPROCS по ним
- Динамически обновляется при изменении лимитов
- Работает из коробки — просто обновите go.mod
- CPU requests игнорируются (только limits)
————
Наконец-то.. Проблеме много лет, и всё это время приходилось костылить через uber/automaxprocs или ENV-переменные. А теперь оно работает из коробки, как и должно было уже давно.
P.S. В Java эту проблему решили ещё в 2017 году
#go1_25 #go_official #kubernetes #docker
Please open Telegram to view this post
VIEW IN TELEGRAM
go.dev
Container-aware GOMAXPROCS - The Go Programming Language
New GOMAXPROCS defaults in Go 1.25 improve behavior in containers.
❤20🔥18🤯2🤔1
Николай Тузов
https://youtu.be/fHuJNsZPCJ0
Этого ролика вам точно будет достаточно для полного понимания нововведений, вне зависимости от вашего опыта
Подробно обсудили, что нового в новой версии, зачем это нужно, как оно устроено, в сложных местах делали ликбез для лучшего понимания изменений.
Дима был очень хорош, такого подробного и глубокого разбора вы больше нигде не увидите, а с комментариями Глеба оно ещё круче, очень рекомендую.
#gogetpodcast #podcast
Please open Telegram to view this post
VIEW IN TELEGRAM
YouTube
Go v1.25 — Глубокий разбор всех изменений | GoGetPodcast №17
Подробно обсудили - что добавилось в новой версии Go 1.25, зачем всё это нужно, как с этим работать.
Go 1.25 Release Notes: https://tip.golang.org/doc/go1.25
Состав:
- Николай Тузов
- Глеб Яльчик
- Дмтрий Матрёничев, ведёт шикарный ТГ-канал по Go: http…
Go 1.25 Release Notes: https://tip.golang.org/doc/go1.25
Состав:
- Николай Тузов
- Глеб Яльчик
- Дмтрий Матрёничев, ведёт шикарный ТГ-канал по Go: http…
🔥19👍6❤3
Forwarded from Go Update
🏗️ gogrep — инструмент для семантического поиска внутри вашей кодовой базы. 🏗️
Наверняка много кому приходилось сталкиваться с ситуацией «надо по коду найти вызовы по определенному паттерну». Чаще всего для этого мы используем регулярные выражения (grep, ag, rg). Однако у них всех есть один минус — они интерпретируют файлы как текст, а не как код. Из-за этого в результаты поиска попадают как нужные нам места вызова, так и комментарии, участки текста и прочая.
Решение этой проблемы: семантический поиск. Это когда утилита разбивает файл на синтаксическое дерево и производит поиск уже по самому дереву. Приведу простой пример:
Здесь мы явно говорим: найди все вызовы, у которых слева есть идентификатор
Документация по gogrep доступна тут. С описанием синтаксиса немного сложнее: большую (и лучшую) часть информации по мэтчингу и по фильтрам можно найти в тестах. Сама тулза является часть куда более мощной тулзы go-ruleguard (которая кстати входит в golangci-lint).
За обе утилиты огромнейшее спасибо Искандеру Шарипову.
Наверняка много кому приходилось сталкиваться с ситуацией «надо по коду найти вызовы по определенному паттерну». Чаще всего для этого мы используем регулярные выражения (grep, ag, rg). Однако у них всех есть один минус — они интерпретируют файлы как текст, а не как код. Из-за этого в результаты поиска попадают как нужные нам места вызова, так и комментарии, участки текста и прочая.
Решение этой проблемы: семантический поиск. Это когда утилита разбивает файл на синтаксическое дерево и производит поиск уже по самому дереву. Приведу простой пример:
~/mws/api > gogrep . 'ptr.Get($_)'
Здесь мы явно говорим: найди все вызовы, у которых слева есть идентификатор
ptr
а внутри вызова идет только один аргумент (не важно выражение, их сумма, или переменная). Таким образом мы идентифицируем именно конкретные места которые будут частью компилируемого кода.Документация по gogrep доступна тут. С описанием синтаксиса немного сложнее: большую (и лучшую) часть информации по мэтчингу и по фильтрам можно найти в тестах. Сама тулза является часть куда более мощной тулзы go-ruleguard (которая кстати входит в golangci-lint).
За обе утилиты огромнейшее спасибо Искандеру Шарипову.
GitHub
GitHub - quasilyte/gogrep: Syntax-aware Go code search, based on the mvdan/gogrep
Syntax-aware Go code search, based on the mvdan/gogrep - quasilyte/gogrep
🔥11👍1
Go Update
🚀 Расширение функции new для создания указателя на значения 🚀 Отличные новости! Предложение, обсуждение которого которого длится уже больше четырех лет и которое выдвинул сам Роб Пайк, наконец-то подходит к принятию. В чем суть: есть у нас встроенная функция…
Наконец-то можно будет выкинуть из проектов мой "любимый" lo.ToPtr()
Правда остаётся ещё lo.FromPtr(), но надежда уже есть.
Если что, мне жутко не нравится идея тащить в проект samber/lo, но не всегда удаётся с этим бороться. При этом, я даже не знаю что хуже — тащить этого монстра ради пары строк кода, или же желание использовать ещё больше его функционала😩
К слову, в предыдущем выпуске подкаста тема `lo` очень подробно обсуждалась в самом конце. Советую послушать, если нужны аргументы.
Правда остаётся ещё lo.FromPtr(), но надежда уже есть.
Если что, мне жутко не нравится идея тащить в проект samber/lo, но не всегда удаётся с этим бороться. При этом, я даже не знаю что хуже — тащить этого монстра ради пары строк кода, или же желание использовать ещё больше его функционала
К слову, в предыдущем выпуске подкаста тема `lo` очень подробно обсуждалась в самом конце. Советую послушать, если нужны аргументы.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥3❤2
Forwarded from Go Update
✔️ errors.AsType — типобезопастная замена errors.As ✔️
Тем временем, в 1.26 нас (вероятно) ждет еще одно приятное изменение: дженерики наконец доберутся до пакета errors.
Все изменение проще описать тремя строчками кода. В 1.25 у нас вот так:
А в 1.26 можно будет вот так:
Вроде и небольшое изменение, но оно ведет, как минимум, к двум положительным вещам:
• Зона видимости типизированной ошибки во многих участках у нас теперь будет меньше, а значит меньше захламляется пространство имен и снижается необходимость думать над правильным именем для ошибки.
• В отличии от errors.As, который вторым аргументом принимал
Кстати, причина по которой сигнатура текущей функции выглядит как
компиляцию не пройдет. А причина в том, что интерфейсы у нас это отдельная сущность которая существует не только во время компиляции, но и во время выполнения.
Тем временем, в 1.26 нас (вероятно) ждет еще одно приятное изменение: дженерики наконец доберутся до пакета errors.
Все изменение проще описать тремя строчками кода. В 1.25 у нас вот так:
var pe *fs.PathError
if errors.As(err, &pe) {
fmt.Println("Failed at path:", pe.Path)
}
А в 1.26 можно будет вот так:
if pe, ok := errors.AsType[*fs.PathError](err); ok {
fmt.Println("Failed at path:", pe.Path)
}
Вроде и небольшое изменение, но оно ведет, как минимум, к двум положительным вещам:
• Зона видимости типизированной ошибки во многих участках у нас теперь будет меньше, а значит меньше захламляется пространство имен и снижается необходимость думать над правильным именем для ошибки.
• В отличии от errors.As, который вторым аргументом принимал
any
, новая функция принимает только тех, кто реализует интерфейс error
. Несмотря на то, что у нас есть проверка внутри go vet
проверяющая второй аргумент у As
, всегда приятнее когда компилятор может самостоятельно поймать ошибку на этапе сборки приложения.Кстати, причина по которой сигнатура текущей функции выглядит как
As(err error, target any) bool
заключается в том, что указатель на интерфейс и указатель на тип реализующий интерфейс для компилятора две несовместимые конструкции. Иначе говоря, вот такой код
func As(err error, target *error) bool {
panic("unimplemented")
}
…
pe *fs.PathError
if As(err, &pathError) {
fmt.Println("Failed at path:", pathError.Path)
}
…
компиляцию не пройдет. А причина в том, что интерфейсы у нас это отдельная сущность которая существует не только во время компиляции, но и во время выполнения.
GitHub
errors: AsType (As with type parameters) · Issue #51945 · golang/go
Currently in 1.18 and before, when using the errors.As method, an error type you would like to write into must be predeclared before calling the function. For example: var myErr *MyCustomError if e...
🔥26❤3
Forwarded from go-with-me
В предыдущем посте мы немного напутали с определением такого многопоточного паттерна как Fan Out
На деле мы показывали Tee, который распространяет одно и то же значение V из канала-источника на N каналов-потребителей
Отличие Fan Out от Tee в том, что на N каналов распространяются разные значения из одного канала-источника. Тобишь, воркеры тянут значения из одного канала, борясь за них насмерть
Лирическое отступление закончено, наша совесть чиста, а сегодняшняя тема будет посвящена Fan In
Этот паттерн является обратным для Fan-Out. Мы собираем данные из нескольких каналов-источников и направляем их в один общий канал-потребитель
1. Default
Итак, что мы имеем?
— Есть воркеры — они кладут значения в N каналов и являются продьюсерами
— Каждый из этих N каналов будет получать значения от своего продьюсера. Назовем такие каналы "стоковыми"
— Есть один общий канал out, туда будет нужно отправить все значения из стоковых каналов
— Для этого мы запускаем N потоков, каждый из которых слушает свой стоковый канал, куда кладет значения продьюсер и редиректит все значения в out
Playground пример
Но что же будет, если какой-то наш продьюсер потух и больше не шлет никаких значений, а передаггый контекст не отменен? Как бы нам понять, что воркер не является активным и перезапустить его? — в этом нам поможет такой механизм как "Heartbeats"
Heartbeat — это регулярное сообщение от продьюсера/воркера, подтверждающее, что он жив и работает
2. Heartbeats
Приступим к рассмотрению этого чуда!
Основная идея проста:
— Имеем структуру, которая хранит в себе стоковый канал, используемый как пайп между воркером и стоком, и канал "сердцебиений"
— Функция Supervise ответственна за отслеживание "сердцебиений" и перезапуск воркера при их отсутствии по TTL
— Функция FanIn принимает на вход стоковые каналы и возвращает результирующий канал, из которого можно читать данные
Всмотримся в наши функции поподробнее
2.1. FanIn
— Не отклоняемся от цели: выкачиваем данные из стоковых каналов и перекладываем в out, реагируя на контекст и неблокирующе отправляя "сердцебиение" нашему супервизору, который пристально наблюдает за нашими воркерами
— WaitGroup здесь так же используется для того, чтобы дождаться конца работы наших стоков и отдать управление основному потоку
после дренажа всех "живых" значений
2.2 Supervise
— Создаем стоковый канал и канал "сердцебиений", агрегируем эти значения в структуре Source и возвращаем ее
— В отдельном потоке запускаем нашу рутину по отслеживанию и перезапуску воркеров
2.2.1 Смотрим на внутренности запущенного потока внутри Supervise
— Изначально происходит создание дочернего контекста с отменой для нашего воркера. Этот контекст будет рулить в тот момент, когда наш TTL пройдет и надо будет потушить воркера
— Создаем ticker, который будет слать ивенты, семантически значащие следующее: "в нашего воркера стреляли и он упал в лужу на..."
После получения ивента мы отменяем контекст и воркер окончательно "задыхается в луже"
— Первично запускаем работягу в отдельном потоке
— Если ловим ивент от тикера: производим отмену контекста, переназначаем этот же контекст и функцию отмены, сбрасываем таймер, и запускаем нового воркера в отдельном потоке
— В случае, когда из стокового потока нам пришло "сердцебиение" мы просто сбрасываем таймер и движемся дальше!
Стоит отметить, что воркеры должны "реагировать" на переданный контекст. Без этого мы получим утечку потоков и черт его знает, чем нам это грозит (профилированием и
устранением проблемы, которой можно было бы и избежать)
Таким образом, мы получаем более надежный Fan In, где все источники данных контролируемы и восстанавливаемы при зависаниях
Playground пример
Статью писали с Дашей: @dariasroom
Stay tuned
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍9❤6🔥2🤯1
conc — удобные примитивы для конкурентного кода
https://github.com/sourcegraph/conc
⭐️ ~10.1k
Небольшая библиотека от Sourcegraph, которая предлагает более безопасные и удобные обёртки над стандартными инструментами конкурентности в Go.
Впервые встретил её на своей текущей работе, и в целом мне понравилось, поэтому грех не поделиться.
Что в ней есть интересного:
- conc.WaitGroup — альтернатива стандартному sync.WaitGroup: ловит паники в горутинах и возвращает их в Wait(), а также не даёт забыть вызвать Wait()
- pool — конкурентный пул задач с ограничением числа горутин (WithMaxGoroutines), сбором ошибок (WithErrors, WithFirstError) и отменой задач при ошибках (WithContext)
- stream — параллельное выполнение задач с сохранением порядка результатов (удобно, когда порядок важен, но хочется параллелизма)
- iter.Map / ForEach — упрощённые хелперы для конкурентной обработки слайсов
🟠 Библиотека пока pre-1.0 (последний релиз в феврале 2023), API может меняться.
#library #concurrency #goroutines
https://github.com/sourcegraph/conc
⭐️ ~10.1k
Небольшая библиотека от Sourcegraph, которая предлагает более безопасные и удобные обёртки над стандартными инструментами конкурентности в Go.
Впервые встретил её на своей текущей работе, и в целом мне понравилось, поэтому грех не поделиться.
Что в ней есть интересного:
- conc.WaitGroup — альтернатива стандартному sync.WaitGroup: ловит паники в горутинах и возвращает их в Wait(), а также не даёт забыть вызвать Wait()
- pool — конкурентный пул задач с ограничением числа горутин (WithMaxGoroutines), сбором ошибок (WithErrors, WithFirstError) и отменой задач при ошибках (WithContext)
- stream — параллельное выполнение задач с сохранением порядка результатов (удобно, когда порядок важен, но хочется параллелизма)
- iter.Map / ForEach — упрощённые хелперы для конкурентной обработки слайсов
#library #concurrency #goroutines
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
GitHub - sourcegraph/conc: Better structured concurrency for go
Better structured concurrency for go. Contribute to sourcegraph/conc development by creating an account on GitHub.
❤12👍10🤯1
Как меняется стек, какие практики и инструменты становятся стандартом, как работают команды и какие задачи сейчас на передовой?
Ответить на эти и многие другие вопросы можно только одним способом — провести исследование: опросить как можно больше специалистов, обработать данные и показать результаты в удобном формате.
Именно этим уже несколько лет подряд занимается команда DevCrowd. И они снова запускают ежегодное исследование русскоязычных Go-разработчиков.
Посмотрите прошлое исследование — там очень много интересных и полезных данных, но читается всё это очень легко, благодаря шикарной подаче.
Поэтому я считаю, что проект обязательно нужно поддержать.
Присоединяйтесь — помогите собрать честный и актуальный срез профессии.
Зачем участвовать?
– Сравните свои задачи, подходы и процессы с коллегами
– Узнаете, какие технологии и практики в ходу у коллег
– Получите ориентиры для развития и найма
– Сделаете профессию Go-разработчика прозрачнее для сообщества и рынка
📊 Результаты исследования будут в начале ноября на devcrowd.ru
Заполнение не долгое, займёт ~10 минут
#devcrowd #research
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍3❤2🤯1