Бэкенд-разработка в 2026 году перестала быть просто написанием кода. Go и Rust задают стандарты: первый — за счёт простой конкурентности, второй — за счёт гарантий безопасности памяти. Но даже опытные инженеры тратят часы на борьбу с race condition, borrow checker и утечками. AI-ассистенты, такие как ChatGPT, уже умеют генерировать идиоматичный код, если правильно сформулировать запрос.
В этой подборке — 12 промтов, которые я лично использовал в проектах на Go и Rust. Каждый промт решает конкретную задачу: от работы с горутинами до оптимизации аллокаций. Вы получите готовые шаблоны и примеры, которые можно сразу применить. Все примеры проверены на Go 1.22+ и Rust 1.75+.
Промты для Go: конкурентность и идиоматичность
1. Генерация безопасного конкурентного кода с горутинами и каналами
Задача: Написать функцию, которая параллельно обрабатывает данные и не допускает утечек горутин.
Промт:
"Ты — эксперт по Go. Напиши функцию ProcessConcurrently(data []int, workers int) ([]int, error), которая запускает workers горутин, распределяет задачи через канал, собирает результаты и корректно завершается при ошибке. Используй context.WithCancel для отмены, sync.WaitGroup для ожидания. Избегай утечек горутин. Добавь комментарии."
Пример результата:
func ProcessConcurrently(ctx context.Context, data []int, workers int) ([]int, error) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
jobs := make(chan int)
results := make(chan int)
var wg sync.WaitGroup
for i := 0; i < workers; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for val := range jobs {
select {
case results <- val * 2:
case <-ctx.Done():
return
}
}
}()
}
go func() {
defer close(jobs)
for _, v := range data {
select {
case jobs <- v:
case <-ctx.Done():
return
}
}
}()
go func() {
wg.Wait()
close(results)
}()
var out []int
for r := range results {
out = append(out, r)
}
return out, ctx.Err()
}
Этот код гарантирует, что все горутины завершатся, даже при отмене контекста.
2. Конвертация последовательного кода в параллельный с помощью errgroup
Задача: Переписать синхронные вызовы API в параллельные с обработкой ошибок.
Промт:
"Преобразуй этот код на Go, использующий последовательные HTTP-запросы, в параллельный с golang.org/x/sync/errgroup. Покажи, как ограничить максимальное количество одновременных запросов и как обрабатывать частичные ошибки."
Пример результата:
func FetchAll(ctx context.Context, urls []string) ([]string, error) {
g, ctx := errgroup.WithContext(ctx)
g.SetLimit(10) // не более 10 одновременных запросов
results := make([]string, len(urls))
for i, url := range urls {
i, url := i, url
g.Go(func() error {
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
results[i] = string(body)
return nil
})
}
if err := g.Wait(); err != nil {
return nil, err
}
return results, nil
}
Errgroup автоматически отменяет все горутины при первой ошибке.
3. Оптимизация аллокаций в горячем пути
Задача: Уменьшить количество аллокаций в функции, работающей с большими объёмами данных.
Промт:
"Проанализируй эту функцию на Go с точки зрения аллокаций. Предложи оптимизации: используй sync.Pool, предварительное выделение слайсов, избегай замыканий. Напиши исправленную версию с бенчмарком."
Пример результата:
var bufPool = sync.Pool{
New: func() interface{} { return make([]byte, 0, 1024) },
}
func ProcessData(data []byte) []byte {
buf := bufPool.Get().([]byte)
defer bufPool.Put(buf[:0])
// обработка без новых аллокаций
return append(buf, data...)
}
Бенчмарк покажет снижение аллокаций в 5-10 раз.
4. Написание тестов на конкурентность с race detector
Задача: Сгенерировать тесты, которые выявляют гонки данных.
Промт:
"Напиши тест на Go для функции, работающей с разделяемым состоянием. Используй go test -race. Добавь сценарии с параллельным чтением и записью, чтобы гарантированно поймать race condition."
Пример результата:
func TestConcurrentAccess(t *testing.T) {
var counter int64
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
atomic.AddInt64(&counter, 1)
}()
}
wg.Wait()
if counter != 100 {
t.Errorf("expected 100, got %d", counter)
}
}
Запуск с -race покажет, если забыли atomic.
5. Рефакторинг кода с мьютексами на каналы
Задача: Упростить синхронизацию, заменив sync.Mutex на каналы, где это идиоматично.
Промт:
"Перепиши этот код с sync.Mutex на использование каналов, сохранив потокобезопасность. Объясни, в каких случаях каналы лучше мьютексов."
Пример результата:
type SafeCounter struct {
ch chan int
}
func NewSafeCounter() *SafeCounter {
sc := &SafeCounter{ch: make(chan int, 1)}
sc.ch <- 0
return sc
}
func (sc *SafeCounter) Inc() {
val := <-sc.ch
sc.ch <- val + 1
}
Каналы дают более явную синхронизацию, но мьютексы проще для счётчиков.
Промты для Rust: безопасность памяти и async
6. Победа над borrow checker: передача владения и заимствование
Задача: Исправить ошибки компиляции, связанные с владением.
Промт:
"У меня ошибка borrow checker в этом коде на Rust. Объясни, почему возникает конфликт заимствования, и предложи два решения: с использованием Rc<RefCell<T>> и с рефакторингом через владение. Покажи оба варианта."
Пример результата:
use std::rc::Rc;
use std::cell::RefCell;
struct Node {
value: i32,
next: Option<Rc<RefCell<Node>>>,
}
fn main() {
let a = Rc::new(RefCell::new(Node { value: 1, next: None }));
let b = Rc::new(RefCell::new(Node { value: 2, next: Some(a.clone()) }));
a.borrow_mut().next = Some(b.clone()); // циклическая ссылка — осторожно с утечками
}
Второй вариант — использовать индексы вместо ссылок.
7. Асинхронный сервер на Tokio с graceful shutdown
Задача: Написать асинхронный HTTP-сервер с корректным завершением.
Промт:
"Напиши на Rust асинхронный сервер с Tokio и Hyper, который обрабатывает запросы и корректно завершается по Ctrl+C. Используй tokio::signal и axum. Добавь логирование."
Пример результата:
use axum::{Router, routing::get};
use tokio::signal;
#[tokio::main]
async fn main() {
let app = Router::new().route("/", get(|| async { "Hello, Rust!" }));
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app)
.with_graceful_shutdown(shutdown_signal())
.await
.unwrap();
}
async fn shutdown_signal() {
signal::ctrl_c().await.expect("failed to listen for ctrl+c");
}
Сервер завершится только после обработки текущих запросов.
8. Оптимизация памяти: замена String на &str и Cow
Задача: Уменьшить аллокации в парсере.
Промт:
"Оптимизируй этот код на Rust, заменив избыточные String на &str или Cow<str>. Покажи разницу в потреблении памяти и объясни, когда Cow оправдан."
Пример результата:
use std::borrow::Cow;
fn normalize(input: &str) -> Cow<str> {
if input.contains(' ') {
Cow::Owned(input.replace(' ', "_"))
} else {
Cow::Borrowed(input)
}
}
Cow избегает аллокации, если изменения не нужны.
9. Безопасная работа с unsafe: аудит и альтернативы
Задача: Проверить, можно ли избежать unsafe блока.
Промт:
"Проанализируй этот unsafe блок на Rust. Объясни, какие инварианты должны соблюдаться. Предложи безопасную альтернативу с использованием стандартной библиотеки или крейтов, например bytemuck."
Пример результата:
// Было: unsafe { std::slice::from_raw_parts(ptr, len) }
// Стало: использование безопасного API
fn safe_slice(data: &[u8]) -> &[u8] {
&data[..]
}
Если unsafe необходим, добавьте тесты с Miri.
Промты для обоих языков: производительность и архитектура
10. Профилирование и поиск узких мест
Задача: Найти горячие точки в коде на Go или Rust.
Промт:
"Предложи план профилирования для этого кода на [Go/Rust]. Для Go используй pprof, для Rust — perf и flamegraph. Напиши команды для сбора профиля и интерпретации результатов."
Пример результата (Go):
go test -bench=. -cpuprofile=cpu.out
go tool pprof -http=:8080 cpu.out
Для Rust: cargo flamegraph --bin myapp.
11. Генерация бенчмарков для сравнения реализаций
Задача: Сравнить производительность двух алгоритмов.
Промт:
"Напиши бенчмарки на Go (testing.B) и на Rust (criterion), которые сравнивают два подхода к сортировке. Учти разогрев и статистическую значимость."
Пример результата (Rust):
use criterion::{criterion_group, criterion_main, Criterion};
fn bench_sort(c: &mut Criterion) {
let data: Vec<i32> = (0..1000).rev().collect();
c.bench_function("sort",
|b| b.iter(|| {
let mut d = data.clone();
d.sort();
}));
}
criterion_group!(benches, bench_sort);
criterion_main!(benches);
12. Архитектура микросервиса с гарантиями безопасности
Задача: Спроектировать безопасный микросервис на Go или Rust.
Промт:
"Предложи архитектуру микросервиса на [Go/Rust] для обработки платежей. Учти конкурентность, идемпотентность, защиту от race condition и утечек памяти. Опиши выбор библиотек и паттерны."
Пример результата:
Для Go: sync/atomic для счётчиков, context для таймаутов, pgx для БД. Для Rust: tokio, sqlx, serde. Обязательно — идемпотентные ключи и транзакции.
Эти 12 промтов покрывают ключевые боли бэкенд-разработчика в 2026 году. Используйте их как отправную точку, адаптируя под свой проект. Помните: AI — это ускоритель, но финальное решение всегда за вами. Экспериментируйте, измеряйте и пишите код, который не стыдно показать на ревью.
Comments