From Microservices to Highload: 12 Go Prompts That Cut Our Backend Development Time by 2.5x

Introduction

If you're a Go developer, you know the drill: boilerplate code, repetitive error handling, and the endless back-and-forth of code review. But what if you could offload a significant chunk of that work to an AI? In this article, I'm sharing the 12 prompts that our team uses daily to slash backend development time by 2.5x. These aren't theoretical — they're battle-tested in production, handling everything from microservices to highload systems. Let's dive into the prompts that will transform your Go workflow.

1. Boilerplate Generator for Microservices

The Problem: Every new microservice requires the same scaffold: main.go, config, handlers, and middleware. Writing it manually is tedious and error-prone.

The Solution: A prompt that generates a complete, idiomatic Go microservice skeleton based on your specifications.

The Prompt:

Generate a minimal but production-ready Go microservice for a REST API. It should include:
- main.go with graceful shutdown
- config loading from environment variables
- HTTP handlers with request validation
- A simple middleware for logging and recovery
- Use the standard library's net/http package (no external frameworks)
- Include a health check endpoint at /health
Provide the code for each file with comments.

Example Output:

// main.go
package main

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

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/health", healthHandler)
    mux.HandleFunc("/api/data", dataHandler)

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

    go func() {
        if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
            log.Fatalf("listen: %s", err)
        }
    }()
    log.Println("Server started on :8080")

    // Graceful shutdown
    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")
}

func healthHandler(w http.ResponseWriter, r *http.Request) {
    w.WriteHeader(http.StatusOK)
    w.Write([]byte("OK"))
}

func dataHandler(w http.ResponseWriter, r *http.Request) {
    // Implement your handler logic
}

Why It Works: This prompt saves hours of boilerplate and ensures best practices like graceful shutdown are included from the start.

2. Error Handling Patterns

The Problem: Go's error handling is explicit but verbose. Developers often skip proper error wrapping or use panics incorrectly.

The Solution: A prompt to generate idiomatic error handling with context and wrapping.

The Prompt:

Given a Go function that performs a database query, write error handling that:
- Uses fmt.Errorf with the %w verb to wrap errors with context
- Uses errors.Is and errors.As for error inspection
- Logs the error with a structured logger (e.g., log/slog)
- Returns a custom error type with an HTTP status code mapping
Provide a complete example.

Example Output:

var ErrNotFound = errors.New("not found")

type AppError struct {
    Code    int
    Message string
    Err     error
}

func (e *AppError) Error() string {
    return fmt.Sprintf("code %d: %v", e.Code, e.Message)
}

func (e *AppError) Unwrap() error {
    return e.Err
}

func fetchUser(ctx context.Context, id int) (*User, error) {
    user, err := db.GetUser(ctx, id)
    if err != nil {
        if errors.Is(err, sql.ErrNoRows) {
            return nil, &AppError{Code: http.StatusNotFound, Message: "user not found", Err: ErrNotFound}
        }
        return nil, fmt.Errorf("fetch user %d: %w", id, err)
    }
    return user, nil
}

Why It Works: Consistent error handling across services improves debugging and API responsiveness.

3. Concurrency Patterns for Highload

The Problem: Highload systems need efficient concurrency — worker pools, rate limiting, and context cancellation.

The Solution: Generate battle-tested concurrency patterns with proper synchronization.

The Prompt:

Implement a worker pool in Go that processes jobs from a channel. The pool should:
- Use sync.WaitGroup to wait for all workers
- Support graceful shutdown via context cancellation
- Use a semaphore to limit concurrency
- Handle panics in workers gracefully
Provide a complete code example with comments.

Example Output:

func workerPool(ctx context.Context, jobs <-chan int, results chan<- int, workers int) {
    var wg sync.WaitGroup
    sem := make(chan struct{}, workers)

    for j := range jobs {
        select {
        case <-ctx.Done():
            return
        default:
        }

        sem <- struct{}{}
        wg.Add(1)
        go func(job int) {
            defer wg.Done()
            defer func() { <-sem }()
            defer func() {
                if r := recover(); r != nil {
                    log.Println("recovered from panic:", r)
                }
            }()

            result := process(job)
            results <- result
        }(j)
    }

    go func() {
        wg.Wait()
        close(results)
    }()
}

Why It Works: This pattern is essential for building resilient, high-throughput services.

4. SQL Query Optimization

The Problem: Inefficient SQL queries can cripple performance. Writing optimized queries is a skill.

The Solution: Use AI to analyze and rewrite queries with proper indexes and joins.

The Prompt:

Given the following SQL query that runs slowly, analyze it and provide an optimized version. Include explaination of why the original is slow and how your changes improve performance. Also suggest appropriate indexes.

SELECT * FROM orders WHERE customer_id = $1 ORDER BY created_at DESC LIMIT 20;

Example Output:

The original query may be slow if the orders table is large and lacks an index on (customer_id, created_at). The ORDER BY requires a sort operation.

Optimized query:
SELECT id, customer_id, total, created_at FROM orders WHERE customer_id = $1 ORDER BY created_at DESC LIMIT 20;

Recommended index:
CREATE INDEX idx_orders_customer_created ON orders (customer_id, created_at DESC);

The composite index allows the database to retrieve the rows in order without a separate sort, and the covering index reduces I/O.

Why It Works: This prompt helps both junior and senior devs improve database performance.

5. API Client Generation

The Problem: Writing clients for external APIs is repetitive and prone to errors.

The Solution: Generate a typed Go client for any REST API.

The Prompt:

Generate a Go client for the GitHub API v3. Include:
- Methods for fetching a user, listing repositories, and creating an issue
- Proper authentication via token
- Context support
- JSON marshaling/unmarshaling
- Error handling for non-2xx responses
Provide complete code with comments.

Why It Works: AI can generate the boilerplate HTTP logic, leaving you to focus on business logic.

6. Refactoring Legacy Code

The Problem: Legacy Go code is often messy, with globals and unhandled errors.

The Solution: Use AI to refactor while preserving behavior.

The Prompt:

Refactor the following Go code to improve readability and maintainability. Break down large functions, use meaningful names, add comments, and handle errors properly. Do not change the external behavior.

[Paste code]

Why It Works: This prompt is a lifesaver when dealing with inherited codebases.

7. Writing Unit Tests

The Problem: Developers often skip tests, leading to bugs.

The Solution: Generate comprehensive table-driven tests.

The Prompt:

Write table-driven tests in Go for the following function. Include edge cases, error cases, and use testify for assertions.

func Divide(a, b float64) (float64, error) {
    if b == 0 {
        return 0, errors.New("division by zero")
    }
    return a / b, nil
}

Example Output:

func TestDivide(t *testing.T) {
    tests := []struct {
        name    string
        a, b    float64
        want    float64
        wantErr bool
    }{
        {"positive", 10, 2, 5, false},
        {"negative result", -10, 2, -5, false},
        {"zero b", 10, 0, 0, true},
        {"decimal", 5, 2, 2.5, false},
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            got, err := Divide(tt.a, tt.b)
            if (err != nil) != tt.wantErr {
                t.Errorf("Divide() error = %v, wantErr %v", err, tt.wantErr)
                return
            }
            if err == nil && got != tt.want {
                t.Errorf("Divide() = %v, want %v", got, tt.want)
            }
        })
    }
}

Why It Works: This prompt encourages test-driven development and saves time.

8. Performance Profiling

The Problem: Identifying bottlenecks in Go code requires expertise.

The Solution: Get AI to suggest profiling tools and interpret results.

The Prompt:

Given the following Go function that processes a large slice, identify potential performance bottlenecks and suggest improvements. Also, recommend which profiling tools (e.g., pprof) to use and how to interpret results.

[Paste code]

Why It Works: AI can spot inefficient loops, allocations, and suggest optimizations.

9. Dockerfile Optimization

The Problem: Bloated Docker images slow deployment.

The Solution: Generate a multi-stage Dockerfile for Go applications.

The Prompt:

Write a multi-stage Dockerfile for a Go application that:
- Uses golang:1.22-alpine as the build stage
- Uses alpine:3.19 as the runtime stage
- Builds a statically linked binary with CGO_ENABLED=0
- Uses a non-root user
- Copies only the binary and necessary files
Provide comments explaining each step.

Example Output:

# Build stage
FROM golang:1.22-alpine AS build
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /app/server .

# Runtime stage
FROM alpine:3.19
RUN adduser -D -u 1000 appuser
USER appuser
WORKDIR /home/appuser
COPY --from=build /app/server .
EXPOSE 8080
CMD ["./server"]

Why It Works: This prompt ensures small, secure images.

10. gRPC Service Definition

The Problem: Writing .proto files and generating Go code from them is a multi-step process.

The Solution: Generate valid .proto definitions and usage examples.

The Prompt:

Create a .proto file for a gRPC service that manages a to-do list. Include:
- Messages for Task and TaskList
- RPCs for AddTask, ListTasks, and DeleteTask
- Use google.protobuf.Empty for the delete operation
- Use optional fields for updates
Provide the .proto and the corresponding Go code for the client and server stubs using protoc.

Why It Works: This prompt simplifies gRPC setup.

11. Middleware for Web Frameworks

The Problem: Writing middleware for authentication, logging, and CORS is repetitive.

The Solution: Generate middleware that integrates with popular frameworks.

The Prompt:

Write a middleware for the Gin framework that:
- Logs each request with method, path, status, and duration
- Recovers from panics and returns a 500 error
- Adds security headers
Provide the code and example usage.

Why It Works: This prompt gives you production-ready middleware in seconds.

12. Code Review Assistance

The Problem: Code reviews are time-consuming and often miss subtle issues.

The Solution: Use AI to review your code for common mistakes.

The Prompt:

Act as a senior Go developer. Review the following code for:
- Race conditions
- Goroutine leaks
- Improper error handling
- Performance issues
- Idiomatic usage
Provide a list of issues found and suggested fixes.

[Paste code]

Why It Works: This acts as a second pair of eyes, catching issues early.

Conclusion

These 12 prompts have become indispensable in our Go development workflow. They don't replace your expertise — they amplify it, letting you focus on architecture and business logic while AI handles the boilerplate. We've seen a 2.5x reduction in development time, from initial scaffold to production. Start integrating these prompts into your daily routine, and you'll soon see the difference. For more insights and tools, check out our blog at asibiont.com/blog. Happy coding!

← All posts

Comments