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!
Comments