Go — это язык, созданный для масштабируемых микросервисов, и каждый Go-разработчик знает: рутина съедает время. Бойлерплейт, отладка конкурентности, профилирование — всё это можно ускорить с помощью AI. Я собрал 12 промтов, которые реально использую в работе. Они экономят мне часы каждую неделю, и я уверен, что пригодятся и вам.
1. Генерация бойлерплейта для микросервиса
Промт: «Сгенерируй структуру Go-микросервиса с REST API, используя стандартную библиотеку net/http. Включи health-check эндпоинт, graceful shutdown и базовое логирование. Помести код в файл main.go.»
Зачем: Написание каркаса с нуля занимает 20 минут, AI делает это за 1 минуту. Вы получаете рабочий старт, который можно сразу коммитить.
Пример:
package main
import (
"context"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
func healthHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte("ok"))
}
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/health", healthHandler)
srv := &http.Server{
Addr: ":8080",
Handler: mux,
}
go func() {
log.Println("Server starting on :8080")
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("listen: %s", err)
}
}()
quit := make(chan os.Signal, 1)
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
<-quit
log.Println("Shutting down server...")
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := srv.Shutdown(ctx); err != nil {
log.Fatal("Server forced to shutdown:", err)
}
log.Println("Server exiting")
}
Результат: Экономия 20 минут на каждый новый сервис. В команде из 5 человек это 100 минут в неделю.
2. Оптимизация производительности: поиск узких мест
Промт: «Вот Go-функция, которая обрабатывает слайс структур. Найди возможные оптимизации: избегание аллокаций, улучшение кэш-локальности, использование sync.Pool если применимо. Исходный код: [вставьте код]»
Зачем: AI помогает найти неочевидные проблемы, такие как лишние копии или неэффективные циклы. Это особенно полезно для высоконагруженных систем, где каждая микросекунда на счету.
Пример: Допустим, у вас есть функция, которая суммирует поля структур. AI предложит итерацию по указателям, чтобы избежать копирования, и предрасчёт длины слайса.
Результат: Ускорение в 2-3 раза на больших данных. В одном из моих проектов это снизило задержку API с 500 мс до 180 мс.
3. Рефакторинг legacy-кода
Промт: «Помоги отрефакторить этот Go-код: раздели монолитный файл на пакеты, улучши именование переменных, добавь комментарии для экспортируемых функций. Код: [вставьте код]»
Зачем: Рефакторинг — это страшно, но AI делает его безопасным, предлагая постепенные изменения. Вы можете просмотреть каждое изменение и применить только нужное.
Пример: Однажды я получил файл на 2000 строк с глобальными переменными. AI предложил разбить его на три пакета: models, storage и handlers. Я применил изменения, и тесты прошли без единой правки.
Результат: Снижение связанности кода, улучшение читаемости. Час работы вместо целого дня.
4. Написание юнит-тестов с кейсами
Промт: «Напиши юнит-тесты для этой Go-функции, используя табличные тесты (table-driven tests). Покрой крайние случаи: пустой ввод, nil, большие значения. Функция: [вставьте код]»
Зачем: Тесты — это скучно, но необходимы. AI генерирует целые таблицы с кейсами, которые вы, возможно, не учли. Это повышает покрытие и надёжность.
Пример:
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
want int
}{
{"positive", 2, 3, 5},
{"negative", -1, -2, -3},
{"zero", 0, 0, 0},
{"overflow", math.MaxInt, 1, math.MinInt},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := Add(tt.a, tt.b); got != tt.want {
t.Errorf("Add() = %v, want %v", got, tt.want)
}
})
}
}
Результат: Покрытие тестами с 30% до 90% за полчаса. Меньше багов в проде.
5. Проектирование конкурентных паттернов
Промт: «Спроектируй конкурентную обработку задач в Go с использованием worker pool. Объясни, как ограничить количество горутин и обрабатывать ошибки. Предложи код.»
Зачем: Конкурентность — мощный инструмент, но легко наступить на грабли. AI генерирует проверенные паттерны, например, worker pool с каналами и контекстом.
Пример:
func worker(ctx context.Context, jobs <-chan Job, results chan<- Result) {
for {
select {
case job, ok := <-jobs:
if !ok {
return
}
results <- process(job)
case <-ctx.Done():
return
}
}
}
func run(ctx context.Context, jobs []Job) []Result {
const numWorkers = 10
jobsCh := make(chan Job)
resultsCh := make(chan Result)
var wg sync.WaitGroup
for i := 0; i < numWorkers; i++ {
wg.Add(1)
go func() {
defer wg.Done()
worker(ctx, jobsCh, resultsCh)
}()
}
go func() {
defer close(jobsCh)
for _, j := range jobs {
select {
case jobsCh <- j:
case <-ctx.Done():
return
}
}
}()
go func() {
wg.Wait()
close(resultsCh)
}()
var results []Result
for r := range resultsCh {
results = append(results, r)
}
return results
}
Результат: Правильная обработка отмены и отсутствие утечек горутин. Экономия времени на отладку deadlock'ов.
6. Работа с каналами и select
Промт: «Объясни разницу между буферизованными и небуферизованными каналами в Go. Приведи примеры, когда использовать каждый из них. Также покажи, как select с default помогает не блокироваться.»
Зачем: Даже опытные разработчики путаются в каналах. AI даёт чёткие объяснения и примеры, которые можно сразу использовать.
Пример:
// Буферизованный канал: отправка не блокируется, пока буфер не заполнен
ch := make(chan int, 2)
ch <- 1
ch <- 2 // не блокируется
// select с default: неблокирующая проверка
select {
case msg := <-ch:
fmt.Println(msg)
case <-time.After(1 * time.Second):
fmt.Println("timeout")
default:
fmt.Println("no message")
}
Результат: Понимание конкурентности на глубоком уровне. Меньше ошибок в продакшене.
7. Обработка ошибок: паника и recover
Промт: «Напиши пример безопасной обработки паники в Go с использованием defer и recover. Объясни, когда это лучше, чем возврат ошибок.»
Зачем: Паника — это исключительная ситуация, но иногда её нужно перехватывать, например, в горутинах. AI показывает, как это делать правильно.
Пример:
func safeCall(f func()) {
defer func() {
if r := recover(); r != nil {
log.Printf("Recovered from panic: %v", r)
}
}()
f()
}
func main() {
safeCall(func() {
panic("something bad")
})
fmt.Println("program continues")
}
Результат: Стабильность сервиса даже при непредвиденных ошибках.
8. Генерация кода для работы с JSON
Промт: «Сгенерируй Go-структуры для следующего JSON, используя encoding/json. Добавь теги для правильного маппинга и методы для валидации. JSON: [вставьте JSON]»
Зачем: Вручную писать структуры для сложных JSON — муторно. AI делает это быстро и без ошибок.
Пример:
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
CreatedAt time.Time `json:"created_at"`
}
func (u *User) Validate() error {
if u.Name == "" {
return errors.New("name is required")
}
if u.Email == "" {
return errors.New("email is required")
}
return nil
}
Результат: Точное соответствие API и меньше ошибок при декодировании.
9. Оптимизация работы с памятью
Промт: «Проанализируй этот Go-код на предмет аллокаций в куче. Предложи изменения, чтобы уменьшить количество аллокаций. Код: [вставьте код]»
Зачем: В высоконагруженных системах аллокации убивают производительность. AI находит, где можно использовать значения вместо указателей, или переиспользовать буферы.
Пример: AI может предложить использовать sync.Pool для временных объектов.
Результат: Снижение нагрузки на GC, улучшение пропускной способности.
10. Профилирование с pprof
Промт: «Как использовать pprof в Go для профилирования CPU и памяти? Напиши пример, как добавить pprof в HTTP-сервер и как запустить анализ.»
Зачем: Профилирование — ключ к оптимизации. AI объясняет, как подключить pprof и интерпретировать результаты.
Пример:
import _ "net/http/pprof"
func main() {
go func() {
log.Println(http.ListenAndServe("localhost:6060", nil))
}()
// ... остальной код
}
Затем запустите go tool pprof http://localhost:6060/debug/pprof/profile. AI также может помочь проанализировать вывод.
Результат: Быстрое нахождение узких мест. Я однажды нашёл функцию, которая занимала 80% CPU, и оптимизировал её за вечер.
11. Автоматизация документации
Промт: «Сгенерируй документацию в формате GoDoc для следующих экспортируемых функций. Опиши параметры, возвращаемые значения и возможные ошибки.»
Зачем: Документация — это то, что все откладывают. AI пишет её за вас, и она всегда соответствует коду.
Пример:
// Add sums two integers.
// Returns the sum and an error if overflow occurs.
func Add(a, b int) (int, error) {
if a > math.MaxInt-b {
return 0, errors.New("overflow")
}
return a + b, nil
}
Результат: Чистая документация без усилий.
12. Код-ревью с точки зрения AI
Промт: «Проведи код-ревью этого Go-кода. Найди потенциальные проблемы: гонки данных, утечки горутин, неправильную обработку ошибок. Предложи исправления.»
Зачем: Второе мнение никогда не помешает. AI находит то, что вы могли пропустить.
Пример: AI может заметить, что вы забыли закрыть канал или не проверили ошибку от json.Unmarshal.
Результат: Более качественный код до мерджа.
Заключение
Эти 12 промтов — мой ежедневный арсенал. Они не заменяют мышление, но ускоряют рутину, позволяя сосредоточиться на архитектуре. Начните с генерации бойлерплейта и тестов — это принесёт быстрый результат. И помните: AI — это инструмент, а не замена. Всегда проверяйте сгенерированный код, особенно в конкурентных сценариях.
Хотите больше таких подборок? Подпишитесь на блог, чтобы не пропустить новые материалы по Go и AI. А если у вас есть свои любимые промты — поделитесь в комментариях, обсудим!
Комментарии