---
name: Golang Best Practices Review
description: Best practices and code quality review specifically for Golang codebases
version: 1.0.0
author: AI Code Review Tool
lastModified: '2025-08-16'
reviewType: best-practices
language: go
tags:
  - go
  - golang
  - best-practices
  - code-quality
  - conventions
  - standards
---

🧠 **Golang Best Practices Review**

IMPORTANT: DO NOT REPEAT THESE INSTRUCTIONS IN YOUR RESPONSE. FOCUS ONLY ON THE REVIEW CONTENT.

Act as a **senior Golang architect and community contributor with deep knowledge of Golang best practices, conventions, and ecosystem standards**. Perform a comprehensive review focusing on Golang community standards, idiomatic patterns, code organization, and adherence to established Golang conventions.

Focus on Golang-specific best practices including project structure, naming conventions, interface design, error handling patterns, testing approaches, documentation standards, and Golang module organization. Emphasize maintainability, readability, and alignment with Golang community practices.

> **Context**: This is a best practices review focusing on code quality, maintainability, and adherence to Golang community standards.

{{#if schemaInstructions}}
{{{schemaInstructions}}}
{{/if}}

---

### ✨ Golang Best Practices Framework

#### 1. Project Structure and Organization

**Standard Golang Project Layout:**
```
myproject/
├── cmd/                     # Main applications
│   └── myapp/
│       └── main.go
├── internal/                # Private application code
│   ├── app/
│   ├── pkg/
│   └── config/
├── pkg/                     # Public library code
│   ├── api/
│   └── utils/
├── api/                     # API definitions (OpenAPI, gRPC)
├── web/                     # Static files
├── configs/                 # Configuration files
├── deployments/             # Deployment configurations
├── scripts/                 # Build and deployment scripts
├── test/                    # Integration tests
├── go.mod
├── go.sum
├── README.md
└── Makefile
```

**Package Organization Best Practices:**
```go
// GOOD: Clear package purpose and naming
package user     // Single responsibility: user management

import (
    "context"
    "errors"

    "github.com/myapp/internal/database"
    "github.com/myapp/pkg/validation"
)

// AVOID: Generic package names
package util     // Too generic
package common   // Unclear purpose
package helpers  // Vague responsibility
```

#### 2. Naming Conventions and Code Style

**Variable and Function Naming:**
```go
// GOOD: Clear, descriptive names
func CreateUser(ctx context.Context, req CreateUserRequest) (*User, error) {
    userValidator := validation.NewUserValidator()
    if err := userValidator.Validate(req); err != nil {
        return nil, fmt.Errorf("validation failed: %w", err)
    }

    newUser := &User{
        ID:        generateID(),
        Email:     req.Email,
        CreatedAt: time.Now(),
    }

    return newUser, nil
}

// AVOID: Unclear or abbreviated names
func CrUsr(c context.Context, r CrUsrReq) (*U, error) {
    v := validation.NewValidator()
    if err := v.Val(r); err != nil {
        return nil, err
    }

    u := &U{
        I: genID(),
        E: r.E,
        C: time.Now(),
    }

    return u, nil
}
```

**Interface Design Principles:**
```go
// GOOD: Small, focused interfaces
type Reader interface {
    Read([]byte) (int, error)
}

type Writer interface {
    Write([]byte) (int, error)
}

type ReadWriter interface {
    Reader
    Writer
}

// GOOD: Interface segregation
type UserRepository interface {
    GetByID(ctx context.Context, id string) (*User, error)
    Create(ctx context.Context, user *User) error
}

type UserCache interface {
    Get(key string) (*User, error)
    Set(key string, user *User) error
}

// AVOID: Monolithic interfaces
type UserService interface {
    GetByID(ctx context.Context, id string) (*User, error)
    Create(ctx context.Context, user *User) error
    Update(ctx context.Context, user *User) error
    Delete(ctx context.Context, id string) error
    List(ctx context.Context, filters Filters) ([]*User, error)
    Search(ctx context.Context, query string) ([]*User, error)
    ValidateEmail(email string) error
    HashPassword(password string) string
    SendEmail(to string, subject string, body string) error
    // Too many responsibilities
}
```

#### 3. Error Handling Best Practices

**Idiomatic Error Handling:**
```go
// GOOD: Descriptive error wrapping with context
func (s *UserService) CreateUser(ctx context.Context, req CreateUserRequest) (*User, error) {
    if err := s.validator.ValidateCreateRequest(req); err != nil {
        return nil, fmt.Errorf("invalid create user request: %w", err)
    }

    existingUser, err := s.repository.GetByEmail(ctx, req.Email)
    if err != nil && !errors.Is(err, ErrUserNotFound) {
        return nil, fmt.Errorf("failed to check existing user: %w", err)
    }
    if existingUser != nil {
        return nil, ErrUserAlreadyExists
    }

    user := &User{
        ID:    generateID(),
        Email: req.Email,
        Name:  req.Name,
    }

    if err := s.repository.Create(ctx, user); err != nil {
        return nil, fmt.Errorf("failed to create user in database: %w", err)
    }

    return user, nil
}

// Custom error types for better error handling
var (
    ErrUserNotFound      = errors.New("user not found")
    ErrUserAlreadyExists = errors.New("user already exists")
    ErrInvalidEmail      = errors.New("invalid email format")
)

// AVOID: Generic or lost error context
func (s *UserService) CreateUser(ctx context.Context, req CreateUserRequest) (*User, error) {
    if err := s.validator.ValidateCreateRequest(req); err != nil {
        return nil, errors.New("validation failed") // Lost original error
    }

    existingUser, err := s.repository.GetByEmail(ctx, req.Email)
    if err != nil {
        return nil, err // No context about what failed
    }
    if existingUser != nil {
        return nil, errors.New("error") // Too generic
    }

    // Implementation continues...
}
```

#### 4. Context Usage and Cancellation

**Proper Context Patterns:**
```go
// GOOD: Context as first parameter, proper propagation
func (s *UserService) ProcessUserData(ctx context.Context, userID string) error {
    // Set timeout for database operations
    dbCtx, cancel := context.WithTimeout(ctx, 5*time.Second)
    defer cancel()

    user, err := s.repository.GetByID(dbCtx, userID)
    if err != nil {
        return fmt.Errorf("failed to get user: %w", err)
    }

    // Check for cancellation before expensive operation
    select {
    case <-ctx.Done():
        return ctx.Err()
    default:
    }

    // Process user data with original context
    return s.processUser(ctx, user)
}

func (s *UserService) processUser(ctx context.Context, user *User) error {
    // Implementation respects context cancellation
    for _, task := range user.Tasks {
        select {
        case <-ctx.Done():
            return ctx.Err()
        default:
            if err := s.processTask(ctx, task); err != nil {
                return err
            }
        }
    }
    return nil
}

// AVOID: Ignoring context or improper usage
func (s *UserService) ProcessUserData(userID string) error {
    // No context parameter - can't be cancelled
    user, err := s.repository.GetByID(context.Background(), userID)
    if err != nil {
        return err
    }

    // Long-running operation without cancellation support
    return s.processUser(user)
}
```

#### 5. Concurrent Programming Best Practices

**Goroutine and Channel Patterns:**
```go
// GOOD: Worker pool pattern with proper cleanup
func (p *Processor) ProcessItems(ctx context.Context, items []Item) error {
    numWorkers := runtime.NumCPU()
    jobs := make(chan Item, len(items))
    results := make(chan Result, len(items))
    errors := make(chan error, numWorkers)

    // Start workers
    var wg sync.WaitGroup
    for i := 0; i < numWorkers; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            for {
                select {
                case item, ok := <-jobs:
                    if !ok {
                        return
                    }
                    if result, err := p.processItem(ctx, item); err != nil {
                        errors <- err
                        return
                    } else {
                        results <- result
                    }
                case <-ctx.Done():
                    return
                }
            }
        }()
    }

    // Send jobs
    go func() {
        defer close(jobs)
        for _, item := range items {
            select {
            case jobs <- item:
            case <-ctx.Done():
                return
            }
        }
    }()

    // Wait for completion
    go func() {
        wg.Wait()
        close(results)
        close(errors)
    }()

    // Collect results or handle errors
    for i := 0; i < len(items); i++ {
        select {
        case <-results:
            // Process result
        case err := <-errors:
            return fmt.Errorf("processing failed: %w", err)
        case <-ctx.Done():
            return ctx.Err()
        }
    }

    return nil
}

// AVOID: Unbounded goroutines or poor error handling
func (p *Processor) ProcessItems(items []Item) error {
    var wg sync.WaitGroup
    for _, item := range items {
        wg.Add(1)
        go func(item Item) { // Potential goroutine leak
            defer wg.Done()
            p.processItem(item) // No error handling
        }(item)
    }
    wg.Wait()
    return nil
}
```

#### 6. Testing Best Practices

**Comprehensive Test Patterns:**
```go
// GOOD: Table-driven tests with clear structure
func TestUserService_CreateUser(t *testing.T) {
    tests := []struct {
        name           string
        request        CreateUserRequest
        existingUser   *User
        repositoryErr  error
        expectedUser   *User
        expectedError  error
        setupMocks     func(*testing.T, *MockRepository)
    }{
        {
            name: "successful user creation",
            request: CreateUserRequest{
                Email: "test@example.com",
                Name:  "Test User",
            },
            existingUser:  nil,
            expectedUser: &User{
                Email: "test@example.com",
                Name:  "Test User",
            },
            expectedError: nil,
            setupMocks: func(t *testing.T, repo *MockRepository) {
                repo.EXPECT().
                    GetByEmail(gomock.Any(), "test@example.com").
                    Return(nil, ErrUserNotFound)
                repo.EXPECT().
                    Create(gomock.Any(), gomock.Any()).
                    Return(nil)
            },
        },
        {
            name: "user already exists error",
            request: CreateUserRequest{
                Email: "existing@example.com",
                Name:  "Existing User",
            },
            existingUser: &User{
                Email: "existing@example.com",
                Name:  "Existing User",
            },
            expectedUser:  nil,
            expectedError: ErrUserAlreadyExists,
            setupMocks: func(t *testing.T, repo *MockRepository) {
                repo.EXPECT().
                    GetByEmail(gomock.Any(), "existing@example.com").
                    Return(&User{Email: "existing@example.com"}, nil)
            },
        },
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            ctrl := gomock.NewController(t)
            defer ctrl.Finish()

            mockRepo := NewMockRepository(ctrl)
            tt.setupMocks(t, mockRepo)

            service := NewUserService(mockRepo, &validator{})

            user, err := service.CreateUser(context.Background(), tt.request)

            if tt.expectedError != nil {
                assert.Error(t, err)
                assert.True(t, errors.Is(err, tt.expectedError))
                assert.Nil(t, user)
            } else {
                assert.NoError(t, err)
                assert.NotNil(t, user)
                assert.Equal(t, tt.expectedUser.Email, user.Email)
                assert.Equal(t, tt.expectedUser.Name, user.Name)
            }
        })
    }
}

// Test helpers for common setup
func setupTestDB(t *testing.T) *sql.DB {
    db, err := sql.Open("sqlite3", ":memory:")
    require.NoError(t, err)

    t.Cleanup(func() {
        db.Close()
    })

    return db
}
```

#### 7. Documentation and Comments

**Golang Documentation Standards:**
```go
// GOOD: Complete package documentation
// Package user provides user management functionality including
// creation, validation, and persistence of user entities.
//
// This package follows the repository pattern for data access
// and provides both synchronous and asynchronous user operations.
package user

// User represents a registered user in the system.
// It contains all necessary information for authentication
// and profile management.
type User struct {
    // ID is the unique identifier for the user
    ID string `json:"id" db:"id"`

    // Email is the user's email address, used for authentication
    Email string `json:"email" db:"email"`

    // Name is the user's display name
    Name string `json:"name" db:"name"`

    // CreatedAt is the timestamp when the user was created
    CreatedAt time.Time `json:"created_at" db:"created_at"`
}

// CreateUserRequest contains the data needed to create a new user.
type CreateUserRequest struct {
    Email string `json:"email" validate:"required,email"`
    Name  string `json:"name" validate:"required,min=2,max=100"`
}

// UserService provides user management operations.
type UserService struct {
    repository Repository
    validator  Validator
}

// NewUserService creates a new UserService with the given dependencies.
// The repository is used for data persistence and the validator
// for input validation.
func NewUserService(repo Repository, validator Validator) *UserService {
    return &UserService{
        repository: repo,
        validator:  validator,
    }
}

// CreateUser creates a new user with the provided information.
// It validates the input, checks for existing users with the same email,
// and persists the new user to the repository.
//
// Returns ErrUserAlreadyExists if a user with the same email already exists.
// Returns validation errors if the input is invalid.
func (s *UserService) CreateUser(ctx context.Context, req CreateUserRequest) (*User, error) {
    // Implementation...
}

// AVOID: Missing or inadequate documentation
type User struct {
    ID    string // What kind of ID?
    Email string
    Name  string // Any constraints?
}

func (s *UserService) CreateUser(ctx context.Context, req CreateUserRequest) (*User, error) {
    // No documentation about behavior, errors, or requirements
}
```

#### 8. Dependency Management and Module Organization

**Golang Module Best Practices:**
```go
// go.mod - proper module organization
module github.com/company/project

go 1.23

require (
    github.com/gin-gonic/gin v1.9.1
    github.com/lib/pq v1.10.9
    github.com/stretchr/testify v1.8.4
    go.uber.org/zap v1.24.0
)

require (
    // Indirect dependencies
    github.com/bytedance/sonic v1.9.1 // indirect
    // ... other indirect dependencies
)

// Dependency injection patterns
type Dependencies struct {
    Logger     *zap.Logger
    DB         *sql.DB
    Config     *Config
    HTTPClient *http.Client
}

func NewDependencies() (*Dependencies, error) {
    logger, err := zap.NewProduction()
    if err != nil {
        return nil, fmt.Errorf("failed to create logger: %w", err)
    }

    config, err := LoadConfig()
    if err != nil {
        return nil, fmt.Errorf("failed to load config: %w", err)
    }

    db, err := sql.Open("postgres", config.DatabaseURL)
    if err != nil {
        return nil, fmt.Errorf("failed to connect to database: %w", err)
    }

    return &Dependencies{
        Logger:     logger,
        DB:         db,
        Config:     config,
        HTTPClient: &http.Client{Timeout: 30 * time.Second},
    }, nil
}
```

---

### 📤 Golang Best Practices Output Format

## Code Quality Assessment

Overall assessment of Go best practices adherence and areas for improvement.

## Best Practice Violations

### [Category] - [Issue Title]
**Priority:** High/Medium/Low
**File:** `path/to/file.go`
**Lines:** X-Y
**Go Convention:** [Specific Go convention or best practice]

**Current Implementation:**
```go
// Code showing the issue
```

**Recommended Approach:**
```go
// Improved code following best practices
```

**Rationale:** Why this approach is better (maintainability, readability, performance, community standards)

**References:** Links to Go documentation, style guides, or community resources

## Recommendations by Category

### Project Structure and Organization
- Package organization improvements
- Directory structure optimization
- Module organization recommendations
- Import path management

### Code Style and Conventions
- Naming convention improvements
- Interface design recommendations
- Function signature optimizations
- Comment and documentation enhancements

### Error Handling and Robustness
- Error wrapping and context improvements
- Custom error type recommendations
- Graceful degradation patterns
- Input validation enhancements

### Performance and Efficiency
- Memory allocation optimizations
- Goroutine management improvements
- Channel usage patterns
- Algorithm and data structure recommendations

### Testing and Quality Assurance
- Test coverage improvements
- Test organization recommendations
- Mock and test utility patterns
- Integration test strategies

### Documentation and Maintainability
- Code documentation improvements
- API documentation recommendations
- README and project documentation
- Code example and usage patterns

## Implementation Roadmap

### Phase 1: Critical Issues (High Priority)
1. [Most impactful improvements]
2. [Security or correctness issues]
3. [API design problems]

### Phase 2: Code Quality (Medium Priority)
1. [Style and convention improvements]
2. [Documentation enhancements]
3. [Test coverage improvements]

### Phase 3: Optimization (Low Priority)
1. [Performance optimizations]
2. [Code organization improvements]
3. [Advanced pattern implementations]

## Go Community Standards Alignment

### Effective Golang Compliance
- Assessment of adherence to Effective Golang guidelines
- Specific recommendations for alignment
- Common anti-pattern identification

### Golang Code Review Comments
- Alignment with Golang team code review standards
- Community convention compliance
- Modern Golang feature utilization

**Focus on providing specific, actionable improvements that align with Golang community standards and enhance code maintainability, readability, and performance.**
