Senior Go Interview Prep - Core Go: https://go.vbloher.org/docs/01-core-go/ - Механика defer в Go: https://go.vbloher.org/docs/01-core-go/defer/ - Встраивание структур и интерфейсов (Embedding): https://go.vbloher.org/docs/01-core-go/embedding/ - Ошибки в Go: error, wrapping, errors.Is/As/Join: https://go.vbloher.org/docs/01-core-go/errors/ - Дженерики в Go (1.18+): https://go.vbloher.org/docs/01-core-go/generics/ - Интерфейсы в Go: https://go.vbloher.org/docs/01-core-go/interfaces/ - Устройство map в Go: https://go.vbloher.org/docs/01-core-go/maps/ - panic / recover: механика, раскрутка стека и runtime-паники: https://go.vbloher.org/docs/01-core-go/panic-recover/ - Указатели в Go: https://go.vbloher.org/docs/01-core-go/pointers/ - Рефлексия в Go (reflect): https://go.vbloher.org/docs/01-core-go/reflection/ - Внутреннее устройство слайсов в Go: https://go.vbloher.org/docs/01-core-go/slices/ - Строки, руны и байты в Go: https://go.vbloher.org/docs/01-core-go/strings-runes-bytes/ - Система типов Go: defined types, alignment, memory layout: https://go.vbloher.org/docs/01-core-go/type-system/ - Concurrency: https://go.vbloher.org/docs/02-concurrency/ - sync/atomic: https://go.vbloher.org/docs/02-concurrency/atomic/ - Буферизованные vs небуферизованные каналы: https://go.vbloher.org/docs/02-concurrency/buffered-unbuffered/ - Канал vs Mutex: когда что выбрать: https://go.vbloher.org/docs/02-concurrency/channel-vs-mutex/ - Каналы: устройство hchan: https://go.vbloher.org/docs/02-concurrency/channels/ - Утечки горутин, дедлоки, livelock, starvation: https://go.vbloher.org/docs/02-concurrency/common-leaks-deadlocks/ - sync.Cond: https://go.vbloher.org/docs/02-concurrency/cond/ - context: https://go.vbloher.org/docs/02-concurrency/context/ - Горутины: жизненный цикл, стоимость, стек: https://go.vbloher.org/docs/02-concurrency/goroutines-lifecycle/ - sync.Mutex и sync.RWMutex: https://go.vbloher.org/docs/02-concurrency/mutex-rwmutex/ - sync.Once: https://go.vbloher.org/docs/02-concurrency/once/ - Паттерны конкурентности: https://go.vbloher.org/docs/02-concurrency/patterns/ - Race Detector (гонки данных и -race): https://go.vbloher.org/docs/02-concurrency/race-detector/ - Планировщик GMP: https://go.vbloher.org/docs/02-concurrency/scheduler-gmp/ - select: https://go.vbloher.org/docs/02-concurrency/select/ - sync.WaitGroup: https://go.vbloher.org/docs/02-concurrency/waitgroup/ - Runtime и память: https://go.vbloher.org/docs/03-runtime-memory/ - Паттерны аллокаций и снижение давления на GC: https://go.vbloher.org/docs/03-runtime-memory/allocation-patterns/ - Escape Analysis: когда переменная убегает в кучу: https://go.vbloher.org/docs/03-runtime-memory/escape-analysis/ - Сборщик мусора Go: concurrent tri-color mark-sweep: https://go.vbloher.org/docs/03-runtime-memory/gc/ - Тюнинг GC: GOGC и GOMEMLIMIT: https://go.vbloher.org/docs/03-runtime-memory/gogc-gomemlimit/ - GOMAXPROCS: параллелизм планировщика и проблема контейнеров: https://go.vbloher.org/docs/03-runtime-memory/gomaxprocs/ - Утечки горутин (goroutine leaks): https://go.vbloher.org/docs/03-runtime-memory/goroutine-leaks/ - Утечки памяти в Go (несмотря на GC): https://go.vbloher.org/docs/03-runtime-memory/memory-leaks/ - Модель памяти Go (Go Memory Model): happens-before и синхронизация: https://go.vbloher.org/docs/03-runtime-memory/memory-model/ - pprof: профилирование CPU, памяти и блокировок в Go: https://go.vbloher.org/docs/03-runtime-memory/pprof/ - Execution Tracer и runtime/trace: тайминги вместо агрегатов: https://go.vbloher.org/docs/03-runtime-memory/runtime-tracing/ - Стек vs Куча: где живут данные в Go: https://go.vbloher.org/docs/03-runtime-memory/stack-vs-heap/ - Тестирование: https://go.vbloher.org/docs/04-testing/ - testify, assert/require и golden files: https://go.vbloher.org/docs/04-testing/assertions-testify/ - Бенчмарки в Go: https://go.vbloher.org/docs/04-testing/benchmarks/ - Покрытие, -race и флаки-тесты: https://go.vbloher.org/docs/04-testing/coverage-race/ - Нативный fuzzing в Go (1.18+): https://go.vbloher.org/docs/04-testing/fuzzing/ - Интеграционные тесты, testcontainers-go, TestMain: https://go.vbloher.org/docs/04-testing/integration-testcontainers/ - Моки, стабы и тестируемость: https://go.vbloher.org/docs/04-testing/mocks/ - Table-driven тесты, subtests и параллельность: https://go.vbloher.org/docs/04-testing/table-driven/ - Backend: https://go.vbloher.org/docs/05-backend/ - Аутентификация и авторизация: AuthN/AuthZ, сессии vs токены, RBAC/ABAC, API keys, mTLS, секреты: https://go.vbloher.org/docs/05-backend/auth-authz/ - Graceful Shutdown HTTP/gRPC сервера в Go: https://go.vbloher.org/docs/05-backend/graceful-shutdown/ - gRPC: типы RPC, интерсепторы, контекст, метаданные, error model: https://go.vbloher.org/docs/05-backend/grpc/ - JWT (JSON Web Token): https://go.vbloher.org/docs/05-backend/jwt/ - Middleware-паттерн в Go: https://go.vbloher.org/docs/05-backend/middleware/ - net/http: Server, Handler, ServeMux, таймауты, Client и контекст: https://go.vbloher.org/docs/05-backend/net-http/ - OAuth2: роли, grant types, OIDC, токены и типовые ошибки: https://go.vbloher.org/docs/05-backend/oauth2/ - OpenAPI/Swagger, code generation, contract-first vs code-first, валидация: https://go.vbloher.org/docs/05-backend/openapi/ - Protocol Buffers: схемы, wire format, эволюция и совместимость: https://go.vbloher.org/docs/05-backend/protobuf/ - REST: принципы, версионирование, идемпотентность, статусы, пагинация, ошибки: https://go.vbloher.org/docs/05-backend/rest/ - Сети и протоколы: https://go.vbloher.org/docs/06-networking/ - Пулы соединений: http.Transport, БД, утечки: https://go.vbloher.org/docs/06-networking/connection-pooling/ - DNS: записи, резолвинг, кэширование, DNS в Go: https://go.vbloher.org/docs/06-networking/dns/ - Версии HTTP: 1.1, 2, 3: https://go.vbloher.org/docs/06-networking/http-versions/ - TCP/IP: модель, транспорт и что важно бэкендеру: https://go.vbloher.org/docs/06-networking/tcp-ip/ - TLS: handshake, сертификаты, mTLS, производительность: https://go.vbloher.org/docs/06-networking/tls/ - UDP и надёжность поверх UDP: https://go.vbloher.org/docs/06-networking/udp/ - WebSocket: upgrade, фреймы, масштабирование: https://go.vbloher.org/docs/06-networking/websocket/ - Базы данных: https://go.vbloher.org/docs/07-databases/ - Пул соединений к PostgreSQL в Go: database/sql, pgx, pgxpool, PgBouncer: https://go.vbloher.org/docs/07-databases/connection-pooling-pgx/ - Взаимоблокировки (Deadlocks) в PostgreSQL: https://go.vbloher.org/docs/07-databases/deadlocks/ - Индексы в PostgreSQL: https://go.vbloher.org/docs/07-databases/indexes/ - Уровни изоляции транзакций в PostgreSQL: https://go.vbloher.org/docs/07-databases/isolation-levels/ - MVCC в PostgreSQL: версии строк, видимость, VACUUM и bloat: https://go.vbloher.org/docs/07-databases/mvcc/ - Обзор NoSQL и Redis: https://go.vbloher.org/docs/07-databases/nosql-redis/ - Партиционирование таблиц в PostgreSQL: https://go.vbloher.org/docs/07-databases/partitioning/ - Архитектура PostgreSQL: https://go.vbloher.org/docs/07-databases/postgresql-architecture/ - Планирование и оптимизация запросов в PostgreSQL: https://go.vbloher.org/docs/07-databases/query-planning/ - Репликация в PostgreSQL: https://go.vbloher.org/docs/07-databases/replication/ - Шардирование (горизонтальное масштабирование): https://go.vbloher.org/docs/07-databases/sharding/ - Транзакции в PostgreSQL и Go (database/sql, pgx): https://go.vbloher.org/docs/07-databases/transactions/ - Распределённые системы: https://go.vbloher.org/docs/08-distributed-systems/ - CAP теорема: https://go.vbloher.org/docs/08-distributed-systems/cap-theorem/ - Circuit Breaker: https://go.vbloher.org/docs/08-distributed-systems/circuit-breaker/ - Консенсус и Raft: репликация состояния в присутствии отказов: https://go.vbloher.org/docs/08-distributed-systems/consensus-raft/ - Модели согласованности: https://go.vbloher.org/docs/08-distributed-systems/consistency/ - Гарантии доставки сообщений: at-most-once / at-least-once / exactly-once: https://go.vbloher.org/docs/08-distributed-systems/delivery-guarantees/ - Eventual Consistency: https://go.vbloher.org/docs/08-distributed-systems/eventual-consistency/ - Идемпотентность в распределённых системах: https://go.vbloher.org/docs/08-distributed-systems/idempotency/ - Apache Kafka: https://go.vbloher.org/docs/08-distributed-systems/kafka/ - Transactional Outbox: https://go.vbloher.org/docs/08-distributed-systems/outbox/ - RabbitMQ: AMQP 0-9-1, маршрутизация, надёжность доставки и сравнение с Kafka: https://go.vbloher.org/docs/08-distributed-systems/rabbitmq/ - Ретраи: backoff, jitter, budgets и идемпотентность: https://go.vbloher.org/docs/08-distributed-systems/retries/ - Saga Pattern: https://go.vbloher.org/docs/08-distributed-systems/saga/ - Observability: https://go.vbloher.org/docs/09-observability/ - Grafana: https://go.vbloher.org/docs/09-observability/grafana/ - Метрики: RED, USE, Golden Signals: https://go.vbloher.org/docs/09-observability/metrics/ - OpenTelemetry: https://go.vbloher.org/docs/09-observability/opentelemetry/ - Prometheus: https://go.vbloher.org/docs/09-observability/prometheus/ - SLI / SLO / SLA: https://go.vbloher.org/docs/09-observability/slo-sli/ - Структурированное логирование (slog): https://go.vbloher.org/docs/09-observability/structured-logging/ - Distributed Tracing: https://go.vbloher.org/docs/09-observability/tracing/ - System Design: https://go.vbloher.org/docs/10-system-design/ - Analytics Pipeline: https://go.vbloher.org/docs/10-system-design/analytics-pipeline/ - Chat System: https://go.vbloher.org/docs/10-system-design/chat/ - Фреймворк System Design интервью: https://go.vbloher.org/docs/10-system-design/framework/ - Notification Service: https://go.vbloher.org/docs/10-system-design/notification-service/ - Order Service: https://go.vbloher.org/docs/10-system-design/order-service/ - Payment Service: https://go.vbloher.org/docs/10-system-design/payment-service/ - Rate Limiter: https://go.vbloher.org/docs/10-system-design/rate-limiter/ - URL Shortener: https://go.vbloher.org/docs/10-system-design/url-shortener/ - DevOps: https://go.vbloher.org/docs/11-devops/ - CI/CD: пайплайны, стадии, стратегии деплоя: https://go.vbloher.org/docs/11-devops/cicd/ - Облака (AWS / GCP) для бэкендера: https://go.vbloher.org/docs/11-devops/cloud-aws-gcp/ - Docker для Go-разработчика: https://go.vbloher.org/docs/11-devops/docker/ - GitHub Actions и GitLab CI: https://go.vbloher.org/docs/11-devops/github-gitlab-ci/ - Kubernetes для Go-разработчика: https://go.vbloher.org/docs/11-devops/kubernetes/ - Terraform / Infrastructure as Code: https://go.vbloher.org/docs/11-devops/terraform/ - Алгоритмы: https://go.vbloher.org/docs/12-algorithms/ - Типовые алгоритмические задачи и паттерны: https://go.vbloher.org/docs/12-algorithms/common-problems/ - Асимптотическая сложность (Big-O): https://go.vbloher.org/docs/12-algorithms/complexity/ - Структуры данных в Go: https://go.vbloher.org/docs/12-algorithms/data-structures/ - Специфика live-coding на Go: https://go.vbloher.org/docs/12-algorithms/go-specifics/ - Behavioral: https://go.vbloher.org/docs/13-behavioral/ - Конфликты, разногласия и работа со стейкхолдерами: https://go.vbloher.org/docs/13-behavioral/conflicts/ - Как проходит senior-интервью: этапы, оценка, оффер: https://go.vbloher.org/docs/13-behavioral/interview-flow/ - Лидерство и менторство: https://go.vbloher.org/docs/13-behavioral/leadership-mentoring/ - Типовые поведенческие вопросы для Senior: https://go.vbloher.org/docs/13-behavioral/senior-questions/ > Модуль: Тестирование · Уровень: Middle+/Senior ## TL;DR В Go тестируемость строится на **интерфейсах**, объявленных на стороне потребителя (узких, в 1-3 метода), и **dependency injection** через конструкторы/поля структуры. Терминология: **стаб** возвращает заранее заданные ответы; **мок** дополнительно проверяет, как и сколько раз его вызвали (verify expectations); **fake** — упрощённая рабочая реализация (in-memory БД); **spy** — записывает вызовы для последующей проверки. Варианты: ручные моки (явные, читаемые, без зависимостей — идиоматичный дефолт для узких интерфейсов), `gomock` (кодогенерация, строгие expectations, контроль порядка), `testify/mock` (рефлексия, гибко, но рантайм-ошибки и многословно). Принцип Go: «accept interfaces, return structs», интерфейс определяет тот, кто его использует, а не тот, кто реализует. ## Теория ### Интерфейсы для тестируемости — на стороне потребителя Антипаттерн (из Java/C#): большой интерфейс рядом с реализацией. Идиома Go: потребитель объявляет ровно то подмножество, что ему нужно. ```go // package order — потребитель объявляет узкий интерфейс type PaymentGateway interface { Charge(ctx context.Context, amount Money, token string) (TxID, error) } type Service struct { pay PaymentGateway // зависимость инжектится } func NewService(pay PaymentGateway) *Service { return &Service{pay: pay} } func (s *Service) Checkout(ctx context.Context, o Order) error { _, err := s.pay.Charge(ctx, o.Total, o.Token) return err } ``` Реальный `stripe.Client` имеет десятки методов, но `order` зависит лишь от `Charge`. Это сужает поверхность мока и делает зависимости явными. ### Dependency Injection в Go DI в Go — это обычно просто передача зависимостей в конструктор/поле, без фреймворков: ```go svc := NewService(realGateway) // прод svc := NewService(&mockGateway{...}) // тест ``` Для крупных графов зависимостей — `google/wire` (compile-time codegen) или `uber/fx` (runtime). На собеседовании важнее показать, что DI — это про инверсию контроля и явные зависимости, а не про конкретный фреймворк. ### Ручные моки/стабы ```go type stubGateway struct { chargeFn func(ctx context.Context, amount Money, token string) (TxID, error) } func (s *stubGateway) Charge(ctx context.Context, amount Money, token string) (TxID, error) { return s.chargeFn(ctx, amount, token) } func TestCheckout_PaymentFails(t *testing.T) { svc := NewService(&stubGateway{ chargeFn: func(_ context.Context, _ Money, _ string) (TxID, error) { return "", errors.New("declined") }, }) if err := svc.Checkout(context.Background(), Order{}); err == nil { t.Fatal("expected error") } } ``` Паттерн «поле-функция» (`chargeFn`) — гибкий ручной мок: каждый тест задаёт поведение инлайн. Для verify добавляют счётчики/спайны: ```go type spyGateway struct { calls []chargeCall ret error } func (s *spyGateway) Charge(_ context.Context, a Money, tok string) (TxID, error) { s.calls = append(s.calls, chargeCall{a, tok}) return "tx1", s.ret } // в тесте: assert len(spy.calls)==1, spy.calls[0].amount == ... ``` Плюсы ручных моков: нулевые зависимости, читаемость, компилятор ловит расхождение сигнатур, полный контроль. Минусы: бойлерплейт для широких интерфейсов, ручная реализация verify. ### gomock (go.uber.org/mock — актуальный форк) Кодогенерация + строгие expectations. ```bash mockgen -source=gateway.go -destination=mocks/gateway.go -package=mocks ``` ```go func TestCheckout_gomock(t *testing.T) { ctrl := gomock.NewController(t) m := mocks.NewMockPaymentGateway(ctrl) m.EXPECT(). Charge(gomock.Any(), Money(100), "tok"). Return(TxID("tx1"), nil). Times(1) svc := NewService(m) _ = svc.Checkout(context.Background(), Order{Total: 100, Token: "tok"}) // ctrl автоматически проверит ожидания на t.Cleanup (в новых версиях) } ``` - `EXPECT()` задаёт ожидаемый вызов с матчерами аргументов и числом вызовов (`Times`, `AnyTimes`, `MinTimes`). - `gomock.InOrder(...)` контролирует порядок. - Незаматченные обязательные вызовы → fail. Неожиданные вызовы → немедленный fail. - Плюсы: строгая verification, контроль порядка, матчеры, генерация из интерфейса. Минусы: кодоген в pipeline, многословность, легко переспецифицировать тест (хрупкость к рефакторингу). ### testify/mock Рефлексивный мок без кодогенерации. ```go type MockGateway struct{ mock.Mock } func (m *MockGateway) Charge(ctx context.Context, a Money, tok string) (TxID, error) { args := m.Called(ctx, a, tok) return args.Get(0).(TxID), args.Error(1) } func TestCheckout_testify(t *testing.T) { m := new(MockGateway) m.On("Charge", mock.Anything, Money(100), "tok").Return(TxID("tx1"), nil) svc := NewService(m) _ = svc.Checkout(context.Background(), Order{Total: 100, Token: "tok"}) m.AssertExpectations(t) } ``` - Поведение задаётся через `.On("MethodName", args...).Return(...)`. - `AssertExpectations`, `AssertCalled`, `AssertNumberOfCalls`. - Плюсы: без кодогена, гибко, знакомо. Минусы: имена методов строками → опечатки и рассинхрон ловятся **в рантайме**, `args.Get(0).(T)` — type assertion без compile-time проверки, многословные реализации методов. ### Сравнение | | Ручные | gomock | testify/mock | |---|---|---|---| | Зависимости | нет | codegen tool | библиотека | | Проверка сигнатур | compile-time | compile-time (codegen) | runtime (строки) | | Verify expectations | руками | встроено, строго | встроено | | Контроль порядка | руками | `InOrder` | руками | | Бойлерплейт | средний (растёт с интерфейсом) | низкий (генерится) | высокий (методы руками) | | Хрупкость теста | низкая | высокая (переспецификация) | средняя | **Рекомендация (идиома Go):** узкий интерфейс (1-3 метода) → ручной мок. Широкий интерфейс или нужна строгая verification/порядок → gomock. testify/mock — если уже завязаны на testify-экосистему и не хотите codegen. ### Когда мок не нужен - **Fake вместо мока:** in-memory реализация репозитория часто лучше мока — тестирует через реальное поведение, не привязана к последовательности вызовов, переиспользуется. - **Чистые функции** не требуют моков вовсе. - **Не мокайте то, что не владеете** напрямую (сторонние типы) — оберните в свой узкий интерфейс и мокайте его. - **Не мокайте стандартную библиотеку/БД-драйвер** — используйте testcontainers/реальную зависимость для интеграционных тестов. ## Подводные камни / gotchas - **Over-mocking** превращает тест в зеркало реализации: проверяете, что код вызвал такие-то методы в таком порядке, а не что он даёт правильный результат. Рефакторинг ломает тесты при корректном поведении. - **testify/mock строковые имена** — рассинхрон с реальным методом ловится в рантайме, не компилятором. Переименовали метод — мок молча устарел. - **gomock переспецификация** — указали точные аргументы/`Times` там, где это неважно, → хрупкость. Используйте `gomock.Any()`/`AnyTimes()` для несущественного. - **Широкие интерфейсы** провоцируют мок-ад. Сужайте интерфейсы на стороне потребителя (ISP). - **Забыли verify** — `m.AssertExpectations(t)` / `ctrl.Finish()`. В новых gomock контроллер регистрируется через `t.Cleanup` автоматически, в старых нужен явный `defer ctrl.Finish()`. - **Мок возвращает не то по умолчанию** — незаданный вызов в testify паникует, в gomock — fail. Проверяйте контракты. - **Конкурентность:** моки с накоплением вызовов в срез не потокобезопасны — при тестировании конкурентного кода защищайте мьютексом. - **Интерфейс ради мока.** Не плодите интерфейсы только чтобы что-то замокать — это запах. Интерфейс должен иметь смысл в дизайне. ## Вопросы на собеседовании **В:** В чём разница между стабом, моком, fake и spy? **О:** Стаб отдаёт заранее заданные ответы. Мок дополнительно верифицирует взаимодействие (какие методы, с какими аргументами, сколько раз). Fake — упрощённая рабочая реализация (in-memory БД). Spy записывает вызовы для последующей проверки. Различие мок/стаб — в том, проверяем ли мы поведение (interaction) или только подменяем ответ (state). **В:** Почему в Go интерфейсы объявляют на стороне потребителя? **О:** Чтобы зависеть от минимального контракта (ISP), сузить поверхность мока и не тащить лишние методы. «Accept interfaces, return structs»: реализация возвращает конкретный тип, а потребитель объявляет узкий интерфейс под свои нужды. Это уменьшает связанность и упрощает тестирование. **В:** Когда предпочесть ручной мок, а когда gomock/testify? **О:** Узкий интерфейс (1-3 метода) — ручной мок: читаемо, без зависимостей, compile-time контроль сигнатур. Широкий интерфейс или нужна строгая verification и контроль порядка — gomock (кодоген, строгие expectations). testify/mock — если уже в testify-экосистеме и не хотим codegen, ценой рантайм-проверок по строковым именам. **В:** Чем опасен over-mocking? **О:** Тест начинает проверять реализацию, а не поведение: ассертит конкретную последовательность вызовов. Любой корректный рефакторинг ломает такие тесты, они дают ложные срабатывания и тормозят изменения. Часто лучше fake или проверка результата вместо взаимодействий. **В:** Какой главный недостаток testify/mock по сравнению с gomock? **О:** Имена методов задаются строками (`.On("Charge", ...)`) и возвраты через `args.Get(0).(T)` — рассинхрон с интерфейсом и неверные типы ловятся в рантайме, а не компилятором. gomock генерится из интерфейса и проверяется на этапе компиляции. **В:** Что такое DI в Go и нужен ли фреймворк? **О:** DI — передача зависимостей извне (через конструктор/поле) вместо создания внутри, для инверсии контроля и подмены в тестах. В Go обычно достаточно ручной передачи в конструктор. Для больших графов — wire (compile-time codegen) или fx (runtime), но это опционально. **В:** Когда мок не нужен и что использовать вместо него? **О:** Для чистых функций — ничего. Для репозиториев часто лучше fake (in-memory) — тестирует через реальное поведение и не хрупок к порядку вызовов. Для БД/внешних сервисов в интеграционных тестах — реальная зависимость через testcontainers. Сторонние типы оборачивают в свой узкий интерфейс и мокают его. **В:** Как тестировать код, зависящий от времени/рандома? **О:** Инжектить зависимость: интерфейс `Clock` с методом `Now()` (или функция `now func() time.Time`), источник случайности как `io.Reader`/`*rand.Rand`. В тесте подменять детерминированной реализацией. Не дёргать `time.Now()`/`rand` напрямую в логике. ## На что копают на senior+ - **Дизайн контрактов:** ISP, узкие интерфейсы на стороне потребителя, «accept interfaces return structs», отказ от интерфейсов-ради-мока. - **State vs interaction testing:** понимание, когда проверять результат (предпочтительно), а когда взаимодействие; вред over-mocking для рефакторинга. - **Fakes как первый выбор:** in-memory реализации, contract tests (один набор тестов против fake и реальной реализации). - **Тестируемость дизайна:** инъекция времени/рандома/UUID, гексагональная архитектура/порты-адаптеры, границы для моков. - **Trade-offs инструментов:** compile-time vs runtime безопасность, хрупкость переспецифицированных моков, цена кодогена в pipeline. - **Конкурентность:** потокобезопасность моков, верификация в конкурентных тестах, `-race`.