Go — язык, который завоевал сердца разработчиков бэкенда и инфраструктуры. Простота, высокая производительность и встроенная поддержка конкурентности делают его идеальным для микросервисов, REST API и CLI-утилит. Но даже опытные Go-разработчики тратят часы на шаблонный код, настройку роутинга и отладку. Я собрал 15 промтов, которые помогут вам ускорить разработку: от генерации каркаса микросервиса до оптимизации производительности. Каждый промт проверен на практике; примеры кода можно сразу адаптировать под свой проект.
Базовые промты: каркас и инструменты
1. Генерация структуры микросервиса с Graceful Shutdown
Задача: Создать минимальный микросервис, который корректно обрабатывает сигналы завершения.
Промт: "Напиши на Go микросервис на net/http с graceful shutdown, логами через slog и хендлером /healthz. Используй сигналы SIGINT и SIGTERM."
Результат:
package main
import (
"context"
"log/slog"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("ok"))
})
srv := &http.Server{Addr: ":8080", Handler: mux}
go func() {
slog.Info("Server started on :8080")
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
slog.Error("Server error", "err", err)
}
}()
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
slog.Info("Shutting down...")
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
slog.Error("Shutdown failed", "err", err)
}
slog.Info("Server exited")
}
Пояснение: Промт даёт готовый шаблон, который можно вставить в main.go. Используется стандартный пакет slog (Go 1.21+), что исключает лишние зависимости.
2. Настройка роутера chi с middleware
Задача: Подключить популярный роутер chi с логированием и CORS.
Промт: "Создай Go-приложение с роутером chi, добавь middleware для логирования запросов (через chi middleware) и CORS через rs/cors. Хендлеры: GET /api/v1/users и POST /api/v1/users."
Результат:
package main
import (
"encoding/json"
"net/http"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/rs/cors"
)
func main() {
r := chi.NewRouter()
r.Use(middleware.Logger)
r.Use(middleware.Recoverer)
c := cors.New(cors.Options{AllowedOrigins: []string{"*"}})
handler := c.Handler(r)
r.Get("/api/v1/users", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("list users"))
})
r.Post("/api/v1/users", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("create user"))
})
http.ListenAndServe(":3000", handler)
}
Пояснение: chi — один из самых популярных роутеров в Go. Промт сразу даёт работающий пример с двумя самыми часто используемыми middleware.
Промты для API и микросервисов
3. CRUD для сущности с in-memory хранилищем
Задача: Реализовать полноценный CRUD для модели User без БД.
Промт: "Напиши на Go REST API для управления пользователями (ID, Name, Email) с in-memory хранилищем. Используй mux, JSON, методы GET, POST, PUT, DELETE. Добавь валидацию: email не пустой, name не короче 2 символов."
Результат: Код объёмный, поэтому приведу ключевые фрагменты. Структура:
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
}
type Store struct {
mu sync.RWMutex
users map[int]User
nextID int
}
Хендлеры используют json.NewEncoder и json.NewDecoder. Валидация проверяется перед записью.
Пояснение: Этот промт закрывает 80% задач по написанию простого CRUD. В реальном проекте хранилище заменяется на PostgreSQL или MongoDB, но логика хендлеров остаётся той же.
4. Работа с PostgreSQL через database/sql и sqlx
Задача: Подключить БД и выполнить запрос с транзакцией.
Промт: "Напиши Go-код, который подключается к PostgreSQL через database/sql и lib/pq, создаёт таблицу users (id serial, name text) и вставляет 3 записи в транзакции с откатом при ошибке. Используй sqlx для сканирования в struct."
Результат:
db, err := sqlx.Connect("postgres", os.Getenv("DATABASE_URL"))
if err != nil {
log.Fatal(err)
}
tx := db.MustBegin()
tx.MustExec("CREATE TABLE IF NOT EXISTS users (id serial primary key, name text)")
tx.MustExec("INSERT INTO users (name) VALUES ($1)", "Alice")
// ...
tx.Commit()
Пояснение: sqlx расширяет database/sql, позволяя сканировать строки прямо в структуры. Промт явно указывает использовать транзакции — это стандарт промышленной разработки.
5. gRPC-сервер и клиент для сервиса User
Задача: Создать gRPC эндпоинт для получения пользователя.
Промт: "Сгенерируй .proto файл с сервисом UserService (rpc GetUser(UserRequest) returns (UserResponse)). Напиши серверную часть на Go, которая возвращает тестового пользователя, и клиент, который вызывает этот метод."
Результат:
syntax = "proto3";
package user;
message UserRequest { int32 id = 1; }
message UserResponse { string name = 1; string email = 2; }
service UserService { rpc GetUser(UserRequest) returns (UserResponse); }
Сервер реализует интерфейс pb.UserServiceServer, клиент подключается через grpc.Dial.
Пояснение: gRPC — стандарт для межсервисного взаимодействия в микросервисной архитектуре. Промт даёт шаблон, который легко расширить до полноценного сервиса.
6. Graceful Shutdown для gRPC сервера
Задача: Добавить корректное завершение gRPC сервера.
Промт: "Дополни gRPC сервер из предыдущего примера graceful shutdown с помощью signal.Notify. Используй Ghttp.Server и его GracefulStop()."
Результат:
func main() {
lis, _ := net.Listen("tcp", ":50051")
s := grpc.NewServer()
pb.RegisterUserServiceServer(s, &server{})
// канал для сигналов
go func() {
sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
<-sig
slog.Info("Shutting down gRPC server...")
s.GracefulStop()
}()
slog.Info("gRPC server listening on :50051")
if err := s.Serve(lis); err != nil {
log.Fatal(err)
}
}
Пояснение: Без graceful shutdown при рестарте контейнера теряются активные запросы. Промт подходит для продакшн-нагрузки.
7. Конфигурация через viper с переменными окружения
Задача: Загрузить конфиг из YAML и переменных окружения.
Промт: "Используя viper, загрузи конфигурацию приложения: порт, строку подключения к БД, уровень логов. Сначала читай config.yaml, затем переменные окружения (с префиксом APP_). Реализуй struct Config с тегами mapstructure."
Результат:
var Config struct {
Port string `mapstructure:"port"`
DB string `mapstructure:"database_url"`
LogLevel string `mapstructure:"log_level"`
}
viper.SetConfigName("config")
viper.SetConfigType("yaml")
viper.AddConfigPath(".")
viper.AutomaticEnv()
viper.SetEnvPrefix("APP")
viper.BindEnv("port", "APP_PORT")
if err := viper.ReadInConfig(); err == nil {
viper.Unmarshal(&Config)
}
Пояснение: Viper — стандарт де-факто для конфигурации в Go. Промт показывает паттерн 12-factor app: конфиг из переменных окружения переопределяет YAML.
Промты для CLI-утилит
8. CLI-утилита с cobra и pflag
Задача: Создать утилиту с командами и флагами.
Промт: "Создай CLI на cobra с командой greet, флагом --name (default "world") и --uppercase. Выведи приветствие, и если --uppercase задан, то в верхнем регистре."
Результат:
var rootCmd = &cobra.Command{Use: "hello", Run: func(cmd *cobra.Command, args []string) {
name, _ := cmd.Flags().GetString("name")
upper, _ := cmd.Flags().GetBool("uppercase")
greeting := fmt.Sprintf("Hello, %s!", name)
if upper {
greeting = strings.ToUpper(greeting)
}
fmt.Println(greeting)
}}
rootCmd.Flags().String("name", "world", "name to greet")
rootCmd.Flags().Bool("uppercase", false, "uppercase output")
Пояснение: Cobra используется в Kubernetes, Docker и Hugo. Промт даёт шаблон, который легко расширить до многоуровневого CLI.
9. Прогресс-бар для обработки файлов
Задача: Показать прогресс при чтении большого файла.
Промт: "Напиши утилиту на Go, которая читает большой текстовый файл построчно и выводит прогресс в процентах в стиле progress bar. Используй пакет cheggaaa/pb/v3. Обновляй прогресс каждые 100 строк."
Результат:
import "github.com/cheggaaa/pb/v3"
func main() {
file := os.Args[1]
fi, _ := os.Stat(file)
count := countLines(file) // подсчёт строк
bar := pb.StartNew(count)
// ... в цикле чтения: bar.Increment()
bar.Finish()
}
Пояснение: Библиотека pb — одна из самых популярных для прогресс-баров. Промт подходит для утилит миграции, бэкапа или анализа логов.
10. Работа с HTTP-запросами из CLI
Задача: Утилита, которая делает HTTP-запрос и выводит результат.
Промт: "Создай CLI-утилиту curl-like: принимает URL, метод (GET/POST), --data (body), --header (один или несколько). Используй pflag и net/http. Выведи статус код и тело ответа."
Результат:
url, _ := cmd.Flags().GetString("url")
method, _ := cmd.Flags().GetString("method")
data, _ := cmd.Flags().GetString("data")
req, _ := http.NewRequest(method, url, strings.NewReader(data))
resp, _ := http.DefaultClient.Do(req)
body, _ := ioutil.ReadAll(resp.Body)
fmt.Printf("Status: %s\nBody: %s", resp.Status, string(body))
Пояснение: Утилита полезна для быстрого тестирования API. В реальности можно добавить таймаут, сохранение в файл и цветной вывод.
Продвинутые промты: производительность и тестирование
11. Benchmark для HTTP-хендлера
Задача: Написать бенчмарк для хендлера, который парсит JSON.
Промт: "Напиши Go-бенчмарк для HTTP-хендлера POST /api/v1/user, который принимает JSON ({name, email}) и возвращает 201. Используй httptest.NewRecorder и testing.B. Запусти бенчмарк с b.ReportAllocs()."
Результат:
func BenchmarkCreateUser(b *testing.B) {
payload := `{"name":"Alice","email":"alice@example.com"}`
req := httptest.NewRequest("POST", "/api/v1/user", strings.NewReader(payload))
w := httptest.NewRecorder()
for i := 0; i < b.N; i++ {
createUserHandler(w, req)
}
}
Пояснение: httptest — стандартный инструмент для тестирования. Промт учит измерять не только скорость, но и количество аллокаций.
12. Конкурентная обработка задач через worker pool
Задача: Обработать список URL параллельно с ограничением.
Промт: "Реализуй worker pool на Go для скачивания 100 URL. Используй каналы, sync.WaitGroup и ограничь число горутин = 10. Выведи результаты (размер ответа)."
Результат:
urls := loadURLs() // list of 100 URLs
numWorkers := 10
jobs := make(chan string, len(urls))
results := make(chan int, len(urls))
for w := 0; w < numWorkers; w++ {
go worker(jobs, results)
}
for _, u := range urls {
jobs <- u
}
close(jobs)
// читаем результаты
Пояснение: Пул воркеров — классический паттерн для утилит, которые парсят сайты, конвертируют изображения или шлют уведомления.
13. Unit-тесты с моками через testify
Задача: Протестировать сервис, который зависит от внешнего API.
Промт: "Напиши интерфейс APIClient с методом GetUser(id int) (User, error). Реализуй сервис UserService, который вызывает этот метод. Создай мок с testify/mock и напиши unit-тест, который проверяет, что сервис возвращает ошибку, если клиент вернул ошибку."
Результат:
type MockAPIClient struct {
mock.Mock
}
func (m *MockAPIClient) GetUser(id int) (User, error) {
args := m.Called(id)
return args.Get(0).(User), args.Error(1)
}
func TestUserService_GetUser_Error(t *testing.T) {
mockClient := new(MockAPIClient)
mockClient.On("GetUser", 1).Return(User{}, errors.New("not found"))
svc := NewUserService(mockClient)
_, err := svc.GetUser(1)
assert.Error(t, err)
}
Пояснение: testify — must-have библиотека для тестирования. Промт показывает, как изолировать внешние зависимости.
14. Graceful shutdown для HTTPS с TLS
Задача: Микросервис с HTTPS и корректным завершением.
Промт: "Дополни первый промт: добавь TLS сертификаты (самоподписанные) и переключи сервер на https.ListenAndServeTLS. Graceful shutdown должен закрывать и TLS-соединения."
Результат:
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
}
srv.TLSConfig = tlsConfig
// в go-рутине: srv.ListenAndServeTLS("cert.pem", "key.pem")
// Shutdown остаётся тем же
Пояснение: В продакшене TLS обязателен. Промт показывает, что graceful shutdown работает одинаково для HTTP и HTTPS.
15. Логирование структурированных логов в JSON
Задача: Настроить логгер slog для вывода JSON в stdout с уровнем debug.
Промт: "Настрой slog в Go так, чтобы логи выводились в формате JSON с полями level, message, time. Установи уровень DEBUG. Добавь несколько логов разного уровня с контекстными атрибутами."
Результат:
logger := slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelDebug}))
slog.SetDefault(logger)
slog.Debug("starting", "module", "api", "port", 8080)
slog.Info("server started")
slog.Error("failed to connect", "err", err)
Пояснение: JSON-логи легко парсятся системами вроде ELK. Промт рекомендуется включать в любой микросервис.
Заключение
15 промтов — это лишь вершина айсберга. Go настолько лаконичен, что хороший промт может сэкономить часы рутинного кодинга. Попробуйте адаптировать эти примеры под свой проект: замените in-memory на реальную БД, добавьте метрики через Prometheus, прикрутите автоматическую документацию через swaggo.
Если вы только начинаете с Go — начните с первых двух промтов. Если уже пишете микросервисы — обратите внимание на бенчмарки и тесты. А для CLI-утилит промты 8-10 дадут готовый каркас.
Сохраните эту статью в закладки — и в следующий раз, когда вам понадобится написать очередной микросервис на Go, просто скопируйте нужный промт в ChatGPT или Claude. Работа пойдёт быстрее.
Комментарии