Skip to main content

go-patterns

Go (Golang) development principles and decision-making. Modern Go 1.22+ patterns, concurrency, project structure, API design.

Datos de origen

Repositorio
skeletorflet/opencode-kit
Última actividad en el origen
31 de marzo de 2026 a las 19:12
Idioma detectado de SKILL.md
inglés
Estrellas
9
Forks
1

Opciones de instalación

De forma predeterminada está seleccionado el prompt que primero revisa el origen. Puedes cambiar a un comando directo o descargar una copia local.

Revisa los archivos de origen

Lee SKILL.md y los archivos complementarios que muestra SkillsMP antes de decidir si quieres instalarlo.

Mostrando SKILL.md

SKILL.md
Instrucciones de origen · Vista previa de solo lectura
name
go-patterns
description
Go (Golang) development principles and decision-making. Modern Go 1.22+ patterns, concurrency, project structure, API design.
# Go Patterns - Modern Go 1.22+ > Go development principles and decision-making. > **Learn to THINK, not copy-paste patterns.** --- ## ⚠️ How to Use This Skill This skill teaches **decision-making principles** for Go development. - ASK user for use case (API, CLI, Microservice, Worker) - Choose Go idioms, not Java/Python patterns - Don't assume async if not needed (Go is already concurrent) --- ## 1. Framework Selection (Go) ### Decision Tree ``` What are you building? │ ├── HTTP API / REST │ ├── Gin (most popular, fast) │ ├── Chi (minimalist, Go idioms) │ ├── Fiber (Echo-compatible, fast) │ └── Echo (full-featured) │ ├── gRPC / Microservices │ ├── gRPC (Google) │ └── Connect (Buf) │ ├── CLI Tool │ ├── Cobra (complete CLI framework) │ ├── Kingpin (flags only) │ └── Cli (simple) │ ├── Background Worker │ └── Asynq (Redis-based) │ └── Machinery (Celery-like) │ └── Full-stack Web │ └── Go doesn't do full-stack; use templ + HTMX └── Go templates + HTMX ``` ### Comparison Table | Factor | Gin | Chi | Echo | Fiber | |--------|-----|-----|------|-------| | **Performance** | Very High | High | High | Very High | | **Routing** | Tree-based | Middleware | Flexible | Express-like | | **Learning Curve** | Low | Low | Low | Medium | | **Middleware** | Many available | Chain-based | Rich | Many | | **Best For** | Production APIs | Clean APIs | Full-featured | Speed | --- ## 2. Go Modules & Project Structure ### Standard Module Structure ``` myproject/ ├── go.mod ├── go.sum ├── cmd/ │ └── myapp/ │ └── main.go ├── internal/ │ ├── handler/ │ ├── service/ │ ├── repository/ │ └── middleware/ ├── pkg/ │ └── utils/ ├── api/ │ └── openapi.yaml ├── configs/ ├── migrations/ └── tests/ ``` ### Go 1.22+ Routing Patterns ```go // New Go 1.22 routing (built-in) func SetupRoutes(r *http.ServeMux) { r.HandleFunc("GET /users", handler.ListUsers) r.HandleFunc("POST /users", handler.CreateUser) r.HandleFunc("GET /users/{id}", handler.GetUser) r.HandleFunc("PUT /users/{id}", handler.UpdateUser) r.HandleFunc("DELETE /users/{id}", handler.DeleteUser) } ``` --- ## 3. Concurrency Patterns ### Go Idioms vs Other Languages ``` Go's philosophy (DON'T): ├── Don't use goroutines when not needed ├── Don't use channels for simple syncs (use sync.Mutex) ├── Don't over-engineer with patterns from other languages └── Don't abuse "go run" for everything Go's philosophy (DO): ├── Use goroutines for I/O-bound operations ├── Use channels for communication, not shared memory ├── Keep it simple - clear > clever └── Let Go handle the concurrency, don't fight it ``` ### Common Patterns ```go // WaitGroup for multiple goroutines var wg sync.WaitGroup for _, task := range tasks { wg.Add(1) go func(t Task) { defer wg.Done() process(t) }(task) } wg.Wait() // Context for cancellation func Handler(w http.ResponseWriter, r *http.Request) { ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second) defer cancel() result, err := doWork(ctx, r.URL.Query()) if err != nil { http.Error(w, err.Error(), 500) return } json.NewEncoder(w).Encode(result) } // Channel for streaming func StreamUsers(w http.ResponseWriter, r *http.Request) { flusher, ok := w.(http.Flusher) if !ok { return } w.Header().Set("Content-Type", "text/event-stream") w.Header().Set("Cache-Control", "no-cache") w.Header().Set("Connection", "keep-alive") for user := range userChan { fmt.Fprintf(w, "data: %s\n\n", user) flusher.Flush() } } ``` --- ## 4. Error Handling ### Go Idiomatic Error Handling ```go // DON'T: Wrap everything with large stack traces // DO: Simple, actionable errors // Pattern 1: Sentinel errors var ( ErrNotFound = errors.New("not found") ErrUnauthorized = errors.New("unauthorized") ) // Pattern 2: Custom error types type ValidationError struct { Field string Message string } func (e *ValidationError) Error() string { return fmt.Sprintf("%s: %s", e.Field, e.Message) } // Pattern 3: Error wrapping (Go 1.13+) if err != nil { return fmt.Errorf("failed to get user %d: %w", userID, err) } // Using errors.Is / errors.As if errors.Is(err, ErrNotFound) { // Handle not found } if errors.As(err, &validationErr) { // Handle validation error } ``` --- ## 5. Database Patterns ### ORMs & SQL | Solution | Best For | Notes | |----------|----------|-------| | **GORM** | Full ORM | Rich features, popular | | **Ent** | Type-safe queries | Code generation, GraphQL | | **sqlx** | Raw SQL + struct mapping | Lightweight, fast | | **Squirrel** | Query builder | Flexible | | **Kitex** | gRPC + DB | When using gRPC | ### Pattern: Repository ```go type UserRepository interface { FindByID(ctx context.Context, id int) (*User, error) FindAll(ctx context.Context) ([]User, error) Create(ctx context.Context, user *User) error Update(ctx context.Context, user *User) error Delete(ctx context.Context, id int) error } type PostgresUserRepo struct { db *sqlx.DB } func (r *PostgresUserRepo) FindByID(ctx context.Context, id int) (*User, error) { var user User err := r.db.GetContext(ctx, &user, "SELECT * FROM users WHERE id = $1", id) if errors.Is(err, sql.ErrNoRows) { return nil, ErrNotFound } return &user, err } ``` --- ## 6. Testing Patterns ### Test Structure ```go // Table-driven tests func TestCalculateArea(t *testing.T) { tests := []struct { name string width float64 height float64 expected float64 }{ {"square", 10, 10, 100}, {"rectangle", 5, 10, 50}, {"zero", 0, 10, 0}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { result := CalculateArea(tt.width, tt.height) if result != tt.expected { t.Errorf("expected %.2f, got %.2f", tt.expected, result) } }) } } // Mocking interfaces type UserRepository interface { FindByID(ctx context.Context, id int) (*User, error) } type MockUserRepo struct { mock.Mock } func (m *MockUserRepo) FindByID(ctx context.Context, id int) (*User, error) { args := m.Called(ctx, id) if args.Get(0) == nil { return nil, args.Error(1) } return args.Get(0).(*User), args.Error(1) } ``` ### Testing Tools | Tool | Purpose | |------|---------| | `testify` | Assertions, mocking | | `gocheck` | More testing features | | `ginkgo` | BDD testing | | `goconvey` | BDD with assertion sugar | | `monkey` | Runtime patching (for tough cases) | --- ## 7. Configuration ### Best Practices ```go // Use Viper for config import "github.com/spf13/viper" func LoadConfig() (*Config, error) { viper.SetConfigName("config") viper.SetConfigType("yaml") viper.AddConfigPath(".") viper.AddConfigPath("/etc/app/") if err := viper.ReadInConfig(); err != nil { return nil, err } var config Config if err := viper.Unmarshal(&config); err != nil { return nil, err } return &config, nil } // Or use standard library for simple cases type Config struct { DatabaseURL string `env:"DATABASE_URL"` Port string `env:"PORT" default:"8080"` } ``` --- ## 8. Middleware Patterns ### HTTP Middleware ```go // Function middleware func Logger(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { start := time.Now() next.ServeHTTP(w, r) log.Printf("%s %s %v", r.Method, r.URL.Path, time.Since(start)) }) } // Chain example r := chi.NewRouter() r.Use(Logger) r.Use(Recovery) r.Use(Auth) r.Route("/api", func(r chi.Router) { r.Use(RateLimit) r.Mount("/users", users.Routes()) }) ``` --- ## 9. Decision Checklist Before implementing: - [ ] **Chosen right HTTP framework for use case?** - [ ] **Go idioms used (not Java/Python patterns)?** - [ ] **Error handling is idiomatic?** - [ ] **Repository pattern for DB access?** - [ ] **Context used for timeouts/cancellation?** - [ ] **Proper concurrency (not over-engineered)?** - [ ] **Testing with table-driven tests?** --- ## ❌ Anti-Patterns to Avoid ### ❌ DON'T: - Use goroutines for CPU-bound work (use worker pool) - Create custom mutex when sync package suffices - Use frameworks when net/http is enough - Skip error handling ("if err != nil { return }") - Use global variables - Panic for expected errors ### ✅ DO: - Go 1.22+ routing with http.ServeMux - Context for timeout/cancellation - Interfaces for dependency injection - Think about Go idioms, not other languages - Keep it simple and clear --- > **Remember:** Go is about simplicity and clarity. > Don't bring patterns from Java/Python/Ruby. > **Think in Go.**
Ver en GitHub