Inside the Mind of a Go and Rust AI Pair Programmer: 17 Battle-Tested Prompts for Concurrency, Memory Safety, and Surviving Production

Проверено на актуальных версиях: Go 1.25, Rust 1.83. Все примеры кода компилируются. Ссылки ведут на официальную документацию.

Каждый Go-разработчик хотя бы раз ловил fatal error: all goroutines are asleep - deadlock! в три часа ночи. Каждый Rust-разработчик хотя бы раз смотрел на error[E0502]: cannot borrow ... as mutable и задавался вопросом, не проще ли вернуться на C. Проблема не в языке — проблема в том, что мы решаем сложные задачи в одиночку, перечитывая документацию и Stack Overflow.

По данным Stack Overflow Developer Survey 2024, Rust пятый год подряд признаётся самым любимым языком (83% разработчиков хотят продолжать на нём), а Go стабильно входит в топ-10 по популярности. При этом оба языка имеют высокий порог входа в специфических областях: конкурентность в Go и система владения в Rust.

Эта подборка — не про «попроси ИИ написать код». Это набор промтов для реальных инженерных задач: отладка гонок, безопасная работа с памятью, оптимизация pprof-профилей. Каждый промт проверен на практике, каждый содержит конкретный пример и объяснение, для какой задачи он подходит.


1. Генерация gRPC-сервиса на Go с конкурентной обработкой

Задача: Создать gRPC-сервис с worker pool, который обрабатывает тысячи запросов в секунду и корректно завершается.

Промт:

Напиши gRPC-сервис на Go 1.25 с использованием google.golang.org/grpc.
Требования:
1. Метод Process(stream Request) returns (stream Response) — двунаправленный стриминг.
2. Worker pool из N воркеров (N = runtime.NumCPU()).
3. Graceful shutdown через context.Context и signal.NotifyContext.
4. Метрики Prometheus: количество обработанных запросов, latency histogram.
5. Обработка ошибок через status.Error(codes.X, msg).
Покажи полный код: proto-файл, server.go, main.go. Добавь комментарии, объясняющие, почему выбран sync.WaitGroup, а не errgroup.

Почему работает: Модель явно указывает версию, библиотеки и архитектурные решения. Без этого ИИ выдаст устаревший код с grpc.WithInsecure() (deprecated в пользу insecure.NewCredentials()).

Пример вывода: ИИ сгенерирует worker pool через канал jobs := make(chan Request, 100) и sync.WaitGroup. Для graceful shutdown использует signal.NotifyContext(context.Background(), os.Interrupt). Согласно официальному примеру gRPC-Go (github.com/grpc/grpc-go/tree/master/examples/features/gracefulstop), это корректный паттерн.


2. Детектор гонок: анализ race detector output

Задача: Race detector нашёл гонку, но вывод на 200 строк непонятен.

Промт:

Вот вывод go test -race ./...:
[вставь лог]

Объясни:
1. Какие две горутины конкурируют и за какой ресурс.
2. Почему это гонка (какие строки кода нарушают happens-before).
3. Предложи три варианта исправления: через sync.Mutex, через atomic, через канал.
4. Для каждого варианта укажи trade-off по производительности.
5. Напиши тест, который гарантированно воспроизводит гонку до фикса.

Практический кейс: Классическая гонка — инкремент счётчика в HTTP-хендлере. counter++ не атомарен: компилятор генерирует LOAD, ADD, STORE. Race detector покажет адреса двух горутин. ИИ объяснит, что sync/atomic.AddInt64(&counter, 1) решает проблему, но если счётчиков много — лучше sync.Mutex или шардирование по CPU через runtime.NumCPU().

Ссылка: Официальная документация — go.dev/doc/articles/race_detector.


3. Rust: разбор ошибок borrow checker с контекстом

Задача: Компилятор выдаёт E0502, E0499, E0597 — и непонятно, как реструктурировать код.

Промт:

Я пишу на Rust 1.83. Компилятор выдаёт ошибку:
[вставь полный вывод cargo check]

Вот мой код:
[вставь код]

Объясни:
1. Почему правило владения нарушено — на уровне модели памяти, а не «потому что компилятор».
2. Как переписать с использованием Rc<RefCell<T>>, Arc<Mutex<T>> или перепроектированием структур.
3. Какой вариант идиоматичнее для многопоточного сервиса.
4. Покажи финальный код, который компилируется.

Пример: Ошибка E0502 возникает, когда вы берёте &mut vec, пока существует &vec. ИИ объяснит концепцию non-lexical lifetimes (NLL), введённую в Rust 2018, и предложит переписать через split_at_mut или индексы вместо ссылок.

Ссылка: Полный список ошибок — doc.rust-lang.org/error_codes/error-index.html.


4. Оптимизация по pprof: от профиля до патча

Задача: Сервис на Go тормозит, есть CPU-профиль, но непонятно, что оптимизировать.

Промт:

Вот вывод go tool pprof -top -cum ./bin/server cpu.prof:
[вставь топ-30 строк]

Проанализируй:
1. Какая функция — горячая точка и почему (аллокации, блокировки, syscalls).
2. Предложи 3 конкретных изменения с ожидаемым эффектом.
3. Покажи diff-патч для самого горячего места.
4. Как проверить эффект через benchstat (укажи команду).

Практический кейс: Часто горячая точка — runtime.mapaccess2 из-за частых чтений из map без шардирования. Решение: sync.Map (для read-heavy) или шардированный map по hash(key) % N. По бенчмаркам из Go blog (go.dev/blog/maps), sync.Map выигрывает при соотношении read/write выше 9:1.


5. Промт для написания property-based тестов

Задача: Юнит-тесты покрывают 3 случая, а баги живут в 300-м.

Промт:

Напиши property-based тесты для функции [вставь сигнатуру] на Go с использованием github.com/leanovate/gopter или testing/quick.
Свойства для проверки:
1. Идемпотентность: f(f(x)) == f(x).
2. Коммутативность: f(a, b) == f(b, a).
3. Инвариант: len(f(x)) <= len(x).
Сгенерируй 1000 кейсов, включая граничные (пустая строка, nil, максимальный int64).
Добавь shrinker для минимизации контрпримеров.

Почему ценно: Property-based тестирование находит edge cases, которые не приходят в голову. Для Rust используйте proptest (docs.rs/proptest) или quickcheck. ИИ сгенерирует shrinker, который сократит падающий ввод до минимального.


6. Рефакторинг Go-кода: от спагетти к чистой архитектуре

Задача: Есть 800-строчный main.go, нужно разбить на слои.

Промт:

Вот файл main.go на Go (800 строк, вставлен ниже).
Разбей его по принципам Clean Architecture:
- domain/ — бизнес-логика, без зависимостей.
- usecase/ — оркестрация.
- infrastructure/ — база данных, HTTP-клиенты.
- delivery/ — HTTP/gRPC-хендлеры.

Для каждого пакета:
1. Покажи интерфейсы на границах.
2. Укажи, как избежать циклических импортов.
3. Напиши go.mod с новыми путями.
4. Покажи пример DI через wire (github.com/google/wire).

Лайфхак: Попросите ИИ сначала нарисовать граф зависимостей в текстовом виде (Mermaid), потом — писать код. Это снижает вероятность циклических импортов, о которых Go сообщит ошибкой import cycle not allowed.


7. Rust: async/await с tokio — от блокирующего к неблокирующему

Задача: Есть синхронный код на Rust, нужно перевести на tokio.

Промт:

Переведи этот синхронный код на Rust в асинхронный с tokio 1.x:
[вставь код]

Требования:
1. Используй tokio::spawn для параллельных задач.
2. Замени blocking I/O на tokio::fs, tokio::net.
3. Если есть CPU-bound задачи — оберни в tokio::task::spawn_blocking.
4. Покажи, как ограничить concurrency через tokio::sync::Semaphore.
5. Объясни, чем tokio::spawn отличается от std::thread::spawn по стоимости.

Критично: ИИ часто забывает про spawn_blocking для CPU-bound кода, из-за чего tokio-рантайм блокируется. По документации tokio (tokio.rs/tokio/tutorial/spawning), блокировка воркера дольше 10-100 мкс деградирует throughput.


8. Промт для подготовки к собеседованию

Задача: Собеседование в компанию, где пишут на Go (например, из списка go.dev/solutions/#case-studies).

Промт:

Ты — senior Go-инженер, проводящий собеседование в [компания].
Задай мне 5 вопросов уровня Middle+ по темам:
1. Каналы: разница между буферизованным и небуферизованным, deadlock-сценарии.
2. sync.Pool: когда использовать, какие подводные камни.
3. Планировщик GMP: как горутины мапятся на OS-потоки.
4. Escape analysis: что уходит в heap, что в stack.
5. Контекст: отмена, дедлайны, распространение значений.

После каждого моего ответа:
- Оцени по шкале 1-5 с обоснованием.
- Укажи, что я упустил.
- Дай эталонный ответ.

Почему работает: Ролевая модель + конкретные темы + критерии оценки. Для Rust замените темы на: lifetimes, Send/Sync, Pin, zero-cost abstractions, unsafe-инварианты.


9. Промт для миграции с Go на Rust (или наоборот)

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

Промт:

Вот сервис на Go (вставь код): HTTP API + PostgreSQL + Redis.
Переведи его на Rust с использованием axum, sqlx, redis-rs.

Для каждой части:
1. Покажи эквивалент на Rust.
2. Объясни, где Rust требует иного подхода (ownership, error handling через Result вместо error).
3. Укажи, какие места станут быстрее, а какие — медленнее (например, async runtime overhead).
4. Напиши Cargo.toml с точными версиями.

Практический нюанс: Go-шный err != nil превращается в Result<T, E> с оператором ?. ИИ должен сгенерировать thiserror для доменных ошибок и anyhow для прикладного слоя — это стандарт из Rust API Guidelines (rust-lang.github.io/api-guidelines).


10. Промт для бенчмарков и сравнения с конкурентами

Задача: Доказать, что ваш сервис быстрее аналога.

Промт:

Напиши бенчмарк для Go-функции [имя] с использованием testing.B.
Требования:
1. Используй b.ResetTimer() перед замером.
2. Запусти с -benchmem для аллокаций.
3. Сравни 3 реализации: наивную, с sync.Pool, с предвыделенным буфером.
4. Покажи вывод benchstat с p-value.
5. Объясни, почему вариант с sync.Pool может быть медленнее для мелких объектов.

Источник: Официальный гайд по бенчмаркам — pkg.go.dev/testing#hdr-Benchmarks. Помните: sync.Pool эффективен при частых аллокациях крупных объектов; для мелких overhead может превысить выгоду.


11. Промт для документации и godoc/clippy

Задача: Код работает, но документации нет — а команда растёт.

Промт:

Добавь godoc-комментарии к этому Go-пакету (вставь код).
Требования:
1. Каждая экспортируемая функция — комментарий, начинающийся с её имени.
2. Примеры в формате Example_FunctionName для godoc.
3. Укажи edge cases в комментариях.
4. Для Rust — добавь #[doc] и doctest-примеры (cargo test --doc).

Ссылка: Стиль комментариев — go.dev/doc/comment. Для Rust — doc.rust-lang.org/rustdoc/how-to-write-documentation.html.


12. Промт для code review: ищем то, что пропустил человек

Задача: PR на 500 строк, глаза замылились.

Промт:

Сделай code review этого PR на Go (вставь diff):
1. Найди потенциальные гонки (проверь все обращения к shared state).
2. Укажи места, где error не обработан или обработан неверно.
3. Проверь утечки горутин (горутина, которая никогда не завершится).
4. Оцени обработку context: не теряется ли отмена.
5. Для Rust — проверь unsafe-блоки и Send/Sync-инварианты.
Выведи таблицей: файл, строка, проблема, серьёзность (critical/major/minor), фикс.

Почему ценно: ИИ не устаёт и не пропускает defer resp.Body.Close(). Но помните: это вспомогательный инструмент, финальное решение — за человеком.


Итог

Промты — это не замена инженерному мышлению, а ускоритель. Go и Rust наказывают за невнимательность: горутина без выхода утечёт память, а unsafe без инвариантов — это UB. Но если правильно сформулировать задачу, ИИ берёт на себя рутину: boilerplate, разбор ошибок компилятора, генерацию тестов, первичный review.

Возьмите 2-3 промта из подборки и примените на текущем проекте. Начните с того, что болит больше всего: race detector или borrow checker. Через неделю вы заметите, что тратите меньше времени на отладку и больше — на архитектуру. А если хотите системно прокачать Go и Rust — посмотрите курсы на asibiont.com: там есть треки по бэкенд-разработке и системному программированию, где эти темы разбираются с реальными проектами.

← All posts

Comments