Skip to main content

go-patterns

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

Informations de source

Dépôt
skeletorflet/opencode-kit
Dernière activité de la source
31 mars 2026 à 19:12
Langue détectée de SKILL.md
anglais
Étoiles
9
Forks
1

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
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.**
Voir sur GitHub