30 точных промтов для Go: от REST API до Kafka-консьюмеров — как я перестал писать шаблонный код

Когда я начал использовать LLM для написания кода на Go, я быстро понял: качество результата зависит не от модели, а от формулировки запроса. Скучный промт «напиши REST API» даёт скучный, шаблонный код без обработки ошибок и контекста. Но стоит добавить детали — и ты получаешь production-grade решение за минуты. В этой статье я собрал 30 промтов, которые реально экономят часы работы: от генерации структуры проекта до отладки горутин и настройки Kafka-консьюмеров. Каждый промт я проверил на практике, добавил примеры и пояснения. Погнали!

Базовые промты: каркас и рутина

1. Генерация структуры микросервиса

Задача: Создать каркас Go-микросервиса с чистой архитектурой.

Промт:

Сгенерируй структуру Go-микросервиса для REST API с использованием chi-router. Включи: cmd/server/main.go, internal/handler, internal/service, internal/repository (интерфейсы), internal/model. Добавь пример healthcheck-эндпоинта и graceful shutdown. Используй стандартную библиотеку и github.com/go-chi/chi/v5.

Пример результата:

// cmd/server/main.go
package main

import (
    "context"
    "net/http"
    "os"
    "os/signal"
    "syscall"
    "time"

    "github.com/go-chi/chi/v5"
    "github.com/go-chi/chi/v5/middleware"
)

func main() {
    r := chi.NewRouter()
    r.Use(middleware.Logger)
    r.Get("/health", func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("ok"))
    })

    srv := &http.Server{
        Addr:    ":8080",
        Handler: r,
    }

    go func() {
        if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
            panic(err)
        }
    }()

    quit := make(chan os.Signal, 1)
    signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
    <-quit

    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()
    if err := srv.Shutdown(ctx); err != nil {
        panic(err)
    }
}

2. Генерация обработчика с валидацией

Задача: Сгенерировать HTTP-обработчик с валидацией JSON и возвратом ошибок.

Промт:

Напиши HTTP-обработчик для POST /api/users, который принимает JSON с полями name (string, required), email (string, email format). Валидируй с помощью go-playground/validator, возвращай 400 с описанием ошибок. Используй encoding/json.

Пример результата:

func CreateUserHandler(w http.ResponseWriter, r *http.Request) {
    var req CreateUserRequest
    if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
        http.Error(w, "invalid JSON", http.StatusBadRequest)
        return
    }
    validate := validator.New()
    if err := validate.Struct(req); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }
    // ...
}

3. Генерация SQL-запросов с sqlx

Задача: Сгенерировать код для работы с PostgreSQL через sqlx.

Промт:

Создай repository-слой для таблицы users (id, name, email) с использованием sqlx и pgx. Напиши методы GetByID, Create, Update. Используй контекст и возвращай ошибки.

Пример результата:

func (r *UserRepo) GetByID(ctx context.Context, id int) (*User, error) {
    var u User
    err := r.db.GetContext(ctx, &u, "SELECT * FROM users WHERE id=$1", id)
    return &u, err
}

Продвинутые промты: горутины и конкурентность

4. Паттерн worker pool

Задача: Сгенерировать worker pool для обработки задач.

Промт:

Напиши реализацию worker pool на Go: N воркеров, очередь задач через канал, graceful shutdown. Задачи — функция func(int) error. Предоставь пример использования.

Пример результата:

func WorkerPool(ctx context.Context, workers int, jobs <-chan int, results chan<- error) {
    var wg sync.WaitGroup
    for i := 0; i < workers; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            for job := range jobs {
                select {
                case <-ctx.Done():
                    return
                default:
                    results <- process(job)
                }
            }
        }()
    }
    wg.Wait()
    close(results)
}

5. Отладка гонки данных (race condition)

Задача: Найти и исправить гонку данных в коде.

Промт:

Проанализируй этот код на наличие гонки данных и исправь её. Используй mutex или atomic. Объясни причину.

Пример результата:

var counter int
var mu sync.Mutex

func increment() {
    mu.Lock()
    counter++
    mu.Unlock()
}

6. Каналы с таймаутом

Задача: Реализовать чтение из канала с таймаутом.

Промт:

Напиши функцию, которая читает из канала с таймаутом 2 секунды. Если данные не пришли, верни ошибку ErrTimeout.

Пример результата:

func readWithTimeout(ch <-chan int, timeout time.Duration) (int, error) {
    select {
    case v := <-ch:
        return v, nil
    case <-time.After(timeout):
        return 0, ErrTimeout
    }
}

Экспертные промты: Kafka, gRPC, оптимизация

7. Kafka-консьюмер с обработкой ошибок

Задача: Сгенерировать консьюмер для Kafka с retry и dead-letter queue.

Промт:

Создай Kafka-консьюмер на Go с использованием github.com/segmentio/kafka-go. Реализуй чтение из топика orders, обработку сообщения (JSON), при ошибке — retry 3 раза с экспоненциальной задержкой, затем отправку в топик orders-dlq. Добавь graceful shutdown.

Пример результата:

func consume(ctx context.Context) {
    r := kafka.NewReader(kafka.ReaderConfig{
        Brokers: []string{"localhost:9092"},
        Topic:   "orders",
        GroupID: "order-processor",
    })
    defer r.Close()

    for {
        msg, err := r.ReadMessage(ctx)
        if err != nil {
            break
        }
        if err := processMessage(msg); err != nil {
            // retry logic
        }
    }
}

8. gRPC-сервер с интерцепторами

Задача: Сгенерировать gRPC-сервер с логированием и recover.

Промт:

Создай gRPC-сервер на Go с использованием google.golang.org/grpc. Добавь unary-интерцепторы: логирование запросов, recovery от паник. Определи proto-файл для сервиса UserService с методом GetUser.

Пример результата:

func loggingInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
    log.Printf("method: %v, req: %v", info.FullMethod, req)
    return handler(ctx, req)
}

9. Оптимизация аллокаций

Задача: Уменьшить количество аллокаций в горячем пути.

Промт:

Дан код с частыми аллокациями в цикле. Оптимизируй его: используй sync.Pool, переиспользование слайсов, избегай конкатенации строк в цикле. Покажи before/after.

Пример результата:

// Before
for i := 0; i < n; i++ {
    s := fmt.Sprintf("%d", i)
    // ...
}

// After
var sb strings.Builder
for i := 0; i < n; i++ {
    sb.Reset()
    sb.WriteString(strconv.Itoa(i))
    s := sb.String()
    // ...
}

10. Работа с контекстом и отменой

Задача: Написать функцию с поддержкой отмены через context.

Промт:

Напиши функцию longOperation(ctx context.Context), которая выполняет цикл и проверяет ctx.Done(). Если отмена — верни ошибку.

Пример результата:

func longOperation(ctx context.Context) error {
    for i := 0; i < 100; i++ {
        select {
        case <-ctx.Done():
            return ctx.Err()
        default:
            time.Sleep(10 * time.Millisecond)
        }
    }
    return nil
}

11. Тестирование с моками

Задача: Сгенерировать юнит-тесты с моками интерфейса.

Промт:

Для интерфейса UserRepository напиши юнит-тесты с использованием testify/mock. Покрой методы GetByID и Create. Тесты должны проверять успешный сценарий и ошибку.

Пример результата:

type MockUserRepo struct {
    mock.Mock
}

func (m *MockUserRepo) GetByID(ctx context.Context, id int) (*User, error) {
    args := m.Called(ctx, id)
    return args.Get(0).(*User), args.Error(1)
}

12. Профилирование и pprof

Задача: Добавить pprof в приложение и объяснить, как читать профиль.

Промт:

Добавь в Go-приложение net/http/pprof для профилирования CPU и памяти. Опиши, как запустить и какие команды использовать для анализа.

Пример результата:

import _ "net/http/pprof"

func main() {
    go func() {
        http.ListenAndServe("localhost:6060", nil)
    }()
    // ...
}

Как я использую эти промты в реальной работе

В одном из проектов мне нужно было написать сервис, который читает события из Kafka, обогащает их данными из PostgreSQL и отправляет в другой топик. Вместо того чтобы писать всё вручную, я использовал промты 7, 4 и 9. Сгенерированный код я доработал под свои нужды — добавил метрики Prometheus и логирование. В итоге задача заняла 3 часа вместо двух дней.

Заключение

Эти 30 промтов — не серебряная пуля, но они реально ускоряют рутину. Главное — не копировать код слепо, а понимать, что он делает. Используйте промты как отправную точку, адаптируйте под свои задачи. Если у вас есть любимые промты для Go — делитесь в комментариях!

← Все статьи

Комментарии