Библиотека Go для собеса | вопросы с собеседований
6.83K subscribers
218 photos
5 videos
1 file
388 links
Вопросы с собеседований по Go и ответы на них.

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

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

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

Наши каналы: https://t.iss.one/proglibrary/9197
Download Telegram
Как правильно использовать ctx.Done() внутри горутин и что произойдёт, если этого не делать

Контекст используется как сигнальный канал. Правильно обрабатывать ctx.Done() нужно всегда, особенно в горутинах
go func(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("goroutine stopped:", ctx.Err())
return
case <-time.After(1 * time.Second):
fmt.Println("working...")
}
}
}(ctx)


Если не слушать ctx.Done(), вы получите:
• Утечки горутин
• Зависание приложения
• Недетерминированное поведение при отмене


🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍1
Как вам вопросы прошедшей недели

Оцените их по шкале 🔥,❤️,👍,😢, 🥱,
где 🔥 — это супер, а 🥱 — это скучно.

Также приветствуется фидбек в комментариях.

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
👍21🔥137🥱1
Почему инициализация через init() не считается ленивой

Иногда экземпляр Singleton можно создавать заранее, при старте пакета. В Go для этого существует функция init().

Singleton с init() в действии
package main

import (
"fmt"
)

type singleton struct {
config string
}

var instance *singleton

func init() {
instance = &singleton{config: "preloaded"}
}

func GetInstance() *singleton {
return instance
}

func main() {
s := GetInstance()
fmt.Println("Singleton config:", s.config)
}


➡️ Особенности подхода:
• Инициализация происходит один раз, до выполнения main() — автоматически
• Синхронизация не требуется init() вызывается в однопоточном контексте
• Порядок инициализации между пакетами гарантирован Go-рантаймом

➡️ Подходит для простых случаев:
Объект всегда нужен в программе
Конфигурация не зависит от внешнего ввода
Важна простота, а не гибкость

➡️ Недостатки
Нарушает ленивую загрузку — объект создаётся даже если не используется
Затрудняет подмену или настройку из внешнего источника (например, через флаги, файлы, ENV)
Может ограничить тестируемость и повторную инициализацию

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
😁42👍1
Как правильно использовать context в юнит-тестах

context — мощный инструмент, но в тестах он может мешать, особенно если используется без ограничений по времени или отмене.

Чтобы избежать зависаний и утечек в юнит-тестах, всегда создавайте context с таймаутом:
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
defer cancel()


Это гарантирует:
Тест не будет висеть бесконечно
Ресурсы будут высвобождены
Горутины получат сигнал на завершение


Если ваш тест зависает — это может говорить о том, что где-то в коде игнорируется ctx.Done()

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6
Какой способ инициализации Singleton в Go выбрать: sync.Mutex, sync.Once или init()

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
4👍3
Зачем использовать select, если можно просто читать из канала

В Go оператор select — это конкурентный аналог switch, предназначенный исключительно для работы с каналами.

С его помощью можно:
• Ждать сразу несколько операций с каналами (чтение/запись)
• Управлять конкурентными потоками без блокировок
• Не блокироваться, если добавить
default ветку

select {
case msg := <-ch1:
fmt.Println("Received from ch1:", msg)
case ch2 <- 42:
fmt.Println("Sent 42 to ch2")
default:
fmt.Println("Nothing ready")
}


Если ch1 или ch2 готовы — будет выполнен соответствующий case.
Если ни один канал не активен — выполняется default, и select не блокирует выполнение.

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
👍52🤔1
Можно ли сделать Singleton тестируемым без нарушения его природы

Singleton может мешать тестированию, так как его состояние живёт весь runtime. Но есть обходные пути:

1️⃣ Вынос в интерфейс
type Storage interface {
Get(key string) string
}


2️⃣ Инъекция зависимости через параметр
func ProcessData(s Storage) { ... }


3️⃣ Сброс состояния Singleton (в тестах)
// В тестовых сборках
func resetSingleton() {
instance = nil
once = sync.Once{}
}


Warning: сброс Singleton — антипаттерн, но допустим в юнит-тестах

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🤔1
Как реализовать приоритет между каналами, если select выбирает случайно

Одно из важных свойств select в Go — рандомность выбора, если сразу несколько каналов готовы к операции.
select {
case msg := <-ch1:
fmt.Println("ch1:", msg)
case msg := <-ch2:
fmt.Println("ch2:", msg)
}


Если и ch1, и ch2 доступны — Go случайным образом выберет один case.
Это исключает жёсткий приоритет каналов и распределяет нагрузку справедливо (не детерминированно).

Это нужно для предотвращения "голодания" менее приоритетных каналов, также это позволяет реализовать честные очереди и worker pool без ручного балансировщика

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
😁9👍3🌚2
Что такое отношение happens-before в модели памяти Go

Отношение happens-before гарантирует упорядоченность и видимость операций между разными горутинами. Если операция A happens-before операции B, то все записанные до A значения памяти гарантированно будут видны при выполнении B.

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
😁2🎉1
Как вам вопросы прошедшей недели

Оцените их по шкале 🔥,❤️,👍,😢, 🥱,
где 🔥 — это супер, а 🥱 — это скучно.

Также приветствуется фидбек в комментариях.

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
👍22🔥10😢74👾1
Как Redis реализует сохранение данных на диск

Redis поддерживает два механизма сохранения данных: Redis Database Dump, который сохраняет данные в момент времени, и Append-Only File, который записывает каждую операцию записи.

Эти два метода могут использоваться вместе для достижения компромисса между производительностью и надежностью.

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥3
Go-сервис генерирует логи, но вы теряетесь в поиске и анализе?
Хотите научиться строить быстрый и надёжный поиск по данным микросервисов?

📅 17 июля в 20:00 (МСК) — открытый урок «Взаимодействие микросервиса на Go и Elasticsearch»

Разберём:
▪️ Архитектуру микросервисов на Go и ключевые нюансы
▪️ Базовые принципы работы с Elasticsearch
▪️ Интеграцию Go-сервиса с Elasticsearch для логирования и поиска
▪️ Настройку индексов, фильтрацию и агрегации

Представьте, что вы разворачиваете микросервис, подключаете его к Elasticsearch, логируете события и выдаёте мгновенный полнотекстовый поиск по данным. Ваш сервис становится прозрачным и управляемым.

🚀 Регистрируйтесь на урок «Взаимодействие микросервиса на Go и Elasticsearch»: https://clc.to/sTcjRQ

Реклама. ООО «Отус онлайн-образование», ОГРН 1177746618576, www.otus.ru
Какие правила happens-before действуют для атомарных операций из пакета sync/atomic

Атомарная операция Store happens-before последующей атомарной операции Load той же переменной (при отсутствии иных атомарных модификаций между ними).

Инициализация всех глобальных переменных happens-before старту функции main(), что гарантирует корректные первоначальные значения при запуске программы.

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
Как работает паттерн «Функциональные опции» в Go и как его можно реализовать

Паттерн «Функциональные опции» предоставляет удобный и гибкий способ конфигурации структур в Go без раскрытия их внутренних полей. Это решение помогает создать расширяемые и легко поддерживаемые объекты, что особенно важно, если в будущем предполагаются изменения или добавление новых параметров.

Этот подход идеален, когда необходимо предоставить дополнительные параметры конфигурации или в случае, когда структура может изменяться, не нарушая совместимость с предыдущими версиями кода. Он также широко используется в библиотеках, где важно сохранять совместимость с различными версиями.

Пример без функциональных опций:
type Server struct {
host string
port int
protocol string
}

func NewServer(host string, port int) *Server {
return &Server{host: host, port: port, protocol: "http"}
}

Этот код создает сервер с параметрами host и port, но с изменениями в требованиях необходимо менять сигнатуру функции, что неудобно.

Реализация функциональных опций
1️⃣ Определим тип для опций:
type ServerOption func(*Server)


2️⃣ Функция для изменения порта:
func WithPort(port int) ServerOption {
return func(s *Server) {
s.port = port
}
}


3️⃣ Модифицируем функцию NewServer:
func NewServer(host string, opts ...ServerOption) *Server {
server := &Server{host: host, port: 443, protocol: "https"}
for _, opt := range opts {
opt(server)
}
return server
}


Теперь можно гибко настроить параметры:
server1 := NewServer("localhost")               // с портом по умолчанию
server2 := NewServer("localhost", WithPort(8080)) // с портом 8080

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

🐸 Библиотека Go для собеса
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🤔5