Go Development Environment Best Practices Core Principles Reproducible Builds : Lock Go versions, dependencies, and toolchains Fast Feedback Loops : Hot reloading, instant testing, and rapid iteration Cross-Platform Consistency : Works identically on macOS, Linux, and Windows Security First : Secure dependency management and supply chain integrity Performance Optimized : Fast compilation, efficient tooling, and minimal overhead Environment Setup Go Version Management # Install g (Go version manager)
curl -sSL https://git.io/g-install | sh -s
# Install latest Go
g install latest
# Use specific version for project
g use 1 .21.5
# Verify installation
go version
Project Structure my-go-project/
├── cmd/ # Application entry points
│ ├── server/
│ │ └── main.go
│ └── worker/
│ └── main.go
├── internal/ # Private application code
│ ├── api/
│ ├── config/
│ └── service/
├── pkg/ # Public library code
│ ├── client/
│ └── utils/
├── api/ # API definitions
│ └── openapi.yaml
├── scripts/ # Build and deployment scripts
├── testdata/ # Test fixtures
├── go.mod
├── go.sum
├── Makefile
├── .golangci.yml
├── .gitignore
└── README.md
# Install essential Go tools
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
go install github.com/air-verse/air@latest
go install github.com/golang/mock/mockgen@latest
go install github.com/swaggo/swag/cmd/swag@latest
go install github.com/cosmtrek/air@latest
go install github.com/securecodewarrior/gosec/v2/cmd/gosec@latest
Development Workflow Hot Reloading with Air # .air.toml
root = "."
testdata_dir = "testdata"
tmp_dir = "tmp"
[build]
args_bin = []
bin = "./tmp/main"
cmd = "go build -o ./tmp/main ./cmd/server"
delay = 1000
exclude_dir = ["assets", "tmp", "vendor", "testdata"]
exclude_file = []
exclude_regex = ["_test.go"]
exclude_unchanged = false
follow_symlink = false
full_bin = ""
include_dir = []
include_ext = ["go", "tpl", "tmpl", "html"]
include_file = []
kill_delay = "0s"
log = "build-errors.log"
poll = false
poll_interval = 0
rerun = false
rerun_delay = 500
send_interrupt = false
stop_on_root = false
[color]
app = ""
build = "yellow"
main = "magenta"
runner = "green"
watcher = "cyan"
[log]
main_only = false
time = false
[misc]
clean_on_exit = false
[screen]
clear_on_rebuild = false
keep_scroll = true
Linting Configuration # .golangci.yml
run :
timeout : 5m
issues-exit-code : 1
tests : true
skip-dirs :
- vendor
- testdata
skip-files :
- ".*\\.pb\\.go$"
linters-settings :
gocyclo :
min-complexity : 15
goconst :
min-len : 3
min-occurrences : 3
gocritic :
enabled-tags :
- diagnostic
- experimental
- opinionated
- performance
- style
govet :
check-shadowing : true
gosec :
severity : medium
confidence : medium
misspell :
locale : US
lll :
line-length : 120
funlen :
lines : 100
statements : 50
gocognit :
min-complexity : 20
linters :
enable :
- bodyclose
- deadcode
- depguard
- dogsled
- dupl
- errcheck
- exportloopref
- exhaustive
- funlen
- gochecknoinits
- goconst
- gocritic
- gocyclo
- gofmt
- goimports
- gomnd
- goprintffuncname
- gosec
- gosimple
- govet
- ineffassign
- lll
- misspell
- nakedret
- noctx
- nolintlint
- rowserrcheck
- staticcheck
- structcheck
- stylecheck
- typecheck
- unconvert
- unparam
- unused
- varcheck
- whitespace
issues :
exclude-rules :
- path : _test\.go
linters :
- gomnd
- funlen
- goconst
Testing Configuration // internal/testing/testutil.go
package testing
import (
"context"
"database/sql"
"testing"
"time"
"github.com/DATA-DOG/go-sqlmock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// TestDB creates a mock database for testing
func TestDB ( t * testing . T ) ( * sql . DB , sqlmock . Sqlmock ) {
db , mock , err := sqlmock . New ()
require . NoError ( t , err )
t . Cleanup ( func () {
db . Close ()
})
return db , mock
}
// TestContext creates a test context with timeout
func TestContext ( t * testing . T ) context . Context {
ctx , cancel := context . WithTimeout ( context . Background (), 30 * time . Second )
t . Cleanup ( cancel )
return ctx
}
// AssertNoError is a helper for common error assertions
func AssertNoError ( t * testing . T , err error ) {
t . Helper ()
assert . NoError ( t , err )
}
// AssertError is a helper for error assertions
func AssertError ( t * testing . T , err error ) {
t . Helper ()
assert . Error ( t , err )
}
Build and Deployment Makefile # Makefile
.PHONY : help build test lint clean docker
# Default target
help : ## Show this help message
@echo "Available targets:"
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $( MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}'
# Build targets
build : ## Build the application
@echo "Building application..."
go build -o bin/server ./cmd/server
go build -o bin/worker ./cmd/worker
build-linux : ## Build for Linux
@echo "Building for Linux..."
GOOS = linux GOARCH = amd64 go build -o bin/server-linux ./cmd/server
GOOS = linux GOARCH = amd64 go build -o bin/worker-linux ./cmd/worker
# Testing
test : ## Run tests
@echo "Running tests..."
go test -v -race -coverprofile= coverage.out ./...
test-coverage : ## Run tests with coverage
@echo "Running tests with coverage..."
go test -v -race -coverprofile= coverage.out ./...
go tool cover -html= coverage.out -o coverage.html
benchmark : ## Run benchmarks
@echo "Running benchmarks..."
go test -bench= . -benchmem ./...
# Linting
lint : ## Run linters
@echo "Running linters..."
golangci-lint run
lint-fix : ## Run linters with auto-fix
@echo "Running linters with auto-fix..."
golangci-lint run --fix
# Security
security : ## Run security checks
@echo "Running security checks..."
gosec ./...
# Development
dev : ## Start development server with hot reload
@echo "Starting development server..."
air
# Docker
docker : ## Build Docker image
@echo "Building Docker image..."
docker build -t my-go-app:latest .
docker-run : ## Run Docker container
@echo "Running Docker container..."
docker run -p 8080 :8080 my-go-app:latest
# Cleanup
clean : ## Clean build artifacts
@echo "Cleaning build artifacts..."
rm -rf bin/
rm -f coverage.out coverage.html
go clean
# Dependencies
deps : ## Download dependencies
@echo "Downloading dependencies..."
go mod download
go mod tidy
deps-update : ## Update dependencies
@echo "Updating dependencies..."
go get -u ./...
go mod tidy
# Code generation
generate : ## Generate code
@echo "Generating code..."
go generate ./...
# Documentation
docs : ## Generate documentation
@echo "Generating documentation..."
swag init -g cmd/server/main.go -o api/docs
Docker Configuration # Dockerfile
# Build stage
FROM golang:1.21-alpine AS builder
WORKDIR /app
# Install build dependencies
RUN apk add --no-cache git ca-certificates tzdata
# Copy go mod files
COPY go.mod go.sum ./
# Download dependencies
RUN go mod download
# Copy source code
COPY . .
# Build the application
RUN CGO_ENABLED = 0 GOOS = linux go build -a -installsuffix cgo -o main ./cmd/server
# Final stage
FROM alpine:latest
# Install ca-certificates for HTTPS
RUN apk --no-cache add ca-certificates tzdata
WORKDIR /root/
# Copy the binary from builder stage
COPY --from= builder /app/main .
# Expose port
EXPOSE 8080
# Run the application
CMD [ "./main" ]
Multi-stage Docker Build # Dockerfile.multi
# Build stage
FROM golang:1.21-alpine AS builder
WORKDIR /app
# Install build dependencies
RUN apk add --no-cache git ca-certificates tzdata
# Copy go mod files
COPY go.mod go.sum ./
# Download dependencies
RUN go mod download
# Copy source code
COPY . .
# Build the application
RUN CGO_ENABLED = 0 GOOS = linux go build -a -installsuffix cgo -o main ./cmd/server
# Test stage
FROM builder AS tester
# Run tests
RUN go test -v -race -coverprofile= coverage.out ./...
# Final stage
FROM alpine:latest
# Install ca-certificates for HTTPS
RUN apk --no-cache add ca-certificates tzdata
WORKDIR /root/
# Copy the binary from builder stage
COPY --from= builder /app/main .
# Expose port
EXPOSE 8080
# Run the application
CMD [ "./main" ]
CI/CD Pipeline GitHub Actions # .github/workflows/ci.yml
name : CI
on :
push :
branches : [ main , develop ]
pull_request :
branches : [ main ]
jobs :
test :
runs-on : ubuntu-latest
steps :
- uses : actions/checkout@v3
- name : Set up Go
uses : actions/setup-go@v4
with :
go-version : '1.21'
- name : Cache Go modules
uses : actions/cache@v3
with :
path : ~/go/pkg/mod
key : ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
restore-keys : |
${{ runner.os }}-go-
- name : Download dependencies
run : go mod download
- name : Verify dependencies
run : go mod verify
- name : Run tests
run : go test -v -race -coverprofile=coverage.out ./...
- name : Upload coverage to Codecov
uses : codecov/codecov-action@v3
with :
file : ./coverage.out
- name : Run linters
uses : golangci/golangci-lint-action@v3
with :
version : latest
- name : Run security checks
uses : securecodewarrior/github-action-gosec@master
with :
args : './...'
- name : Build
run : go build -o bin/server ./cmd/server
- name : Build Docker image
run : docker build -t my-go-app:${{ github.sha }} .
Profiling Configuration // cmd/server/main.go
package main
import (
"log"
"net/http"
_ "net/http/pprof"
"os"
"os/signal"
"syscall"
)
func main () {
// Enable pprof endpoints
go func () {
log . Println ( "Starting pprof server on :6060" )
log . Println ( http . ListenAndServe ( "localhost:6060" , nil ))
}()
// Graceful shutdown
c := make ( chan os . Signal , 1 )
signal . Notify ( c , os . Interrupt , syscall . SIGTERM )
// Start your application
// ...
<- c
log . Println ( "Shutting down gracefully..." )
}
Benchmarking // internal/service/benchmark_test.go
package service
import (
"testing"
)
func BenchmarkProcessData ( b * testing . B ) {
service := NewService ()
data := generateTestData ( 1000 )
b . ResetTimer ()
for i := 0 ; i < b . N ; i ++ {
service . ProcessData ( data )
}
}
func BenchmarkConcurrentProcess ( b * testing . B ) {
service := NewService ()
data := generateTestData ( 1000 )
b . ResetTimer ()
b . RunParallel ( func ( pb * testing . PB ) {
for pb . Next () {
service . ProcessData ( data )
}
})
}
Security Best Practices Dependency Security # Check for vulnerabilities
go list -json -deps ./... | nancy sleuth
# Update dependencies
go get -u ./...
go mod tidy
# Audit dependencies
gosec ./...
Secure Configuration // internal/config/config.go
package config
import (
"os"
"strconv"
"time"
)
type Config struct {
Server ServerConfig
Database DatabaseConfig
Security SecurityConfig
}
type ServerConfig struct {
Port string
ReadTimeout time . Duration
WriteTimeout time . Duration
}
type DatabaseConfig struct {
Host string
Port int
Username string
Password string
SSLMode string
}
type SecurityConfig struct {
JWTSecret string
BcryptCost int
RateLimitRPS int
}
func Load () ( * Config , error ) {
return & Config {
Server : ServerConfig {
Port : getEnv ( "SERVER_PORT" , "8080" ),
ReadTimeout : getDuration ( "SERVER_READ_TIMEOUT" , 30 * time . Second ),
WriteTimeout : getDuration ( "SERVER_WRITE_TIMEOUT" , 30 * time . Second ),
},
Database : DatabaseConfig {
Host : getEnv ( "DB_HOST" , "localhost" ),
Port : getInt ( "DB_PORT" , 5432 ),
Username : getEnv ( "DB_USERNAME" , "postgres" ),
Password : getEnv ( "DB_PASSWORD" , "" ),
SSLMode : getEnv ( "DB_SSL_MODE" , "require" ),
},
Security : SecurityConfig {
JWTSecret : getEnv ( "JWT_SECRET" , "" ),
BcryptCost : getInt ( "BCRYPT_COST" , 12 ),
RateLimitRPS : getInt ( "RATE_LIMIT_RPS" , 100 ),
},
}, nil
}
func getEnv ( key , defaultValue string ) string {
if value := os . Getenv ( key ); value != "" {
return value
}
return defaultValue
}
func getInt ( key string , defaultValue int ) int {
if value := os . Getenv ( key ); value != "" {
if intValue , err := strconv . Atoi ( value ); err == nil {
return intValue
}
}
return defaultValue
}
func getDuration ( key string , defaultValue time . Duration ) time . Duration {
if value := os . Getenv ( key ); value != "" {
if duration , err := time . ParseDuration ( value ); err == nil {
return duration
}
}
return defaultValue
}
TL;DR Runbook Quick Start # 1. Install Go version manager
curl -sSL https://git.io/g-install | sh -s
# 2. Install latest Go
g install latest
# 3. Install essential tools
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
go install github.com/air-verse/air@latest
# 4. Create new project
mkdir my-go-project && cd my-go-project
go mod init github.com/username/my-go-project
# 5. Start development
air
Essential Commands # Development
make dev # Start with hot reload
make test # Run tests
make lint # Run linters
make build # Build application
# Production
make docker # Build Docker image
make security # Run security checks
make benchmark # Run benchmarks