Skip to main content

golang

Use when building Go backend services, implementing goroutines/channels, handling errors idiomatically, writing tests with testify, or following Go best practices for APIs/CLI tools.

معلومات المصدر

المستودع
MadAppGang/claude-code
آخر نشاط في المصدر
٢٠ يناير ٢٠٢٦ في ٠٨:١٦
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٢٨٤
التفرعات
٢٥

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
golang
version
2.0.0
description
Use when building Go backend services, implementing goroutines/channels, handling errors idiomatically, writing tests with testify, or following Go best practices for APIs/CLI tools.
keywords
["Go","Golang","concurrency","goroutines","channels","error handling","testing","backend","API"]
plugin
dev
updated
2026-01-20T00:00:00.000Z
# Go Development Best Practices **Version**: 2.0.0 **Purpose**: Comprehensive Go development patterns covering idioms, error handling, concurrency, testing, and quality **Scope**: Backend development with Go - API services, CLI tools, system software **Prerequisites**: Basic Go syntax knowledge ## Overview Go (Golang) is designed for simplicity, explicit error handling, and safe concurrent programming. This skill covers production-ready patterns validated by the Go community, official documentation, and industry standards (Uber Engineering, Google). **Core Philosophy**: - **Simplicity**: "Clear is better than clever" - favor readable code over abstractions - **Explicit over implicit**: No exceptions, no hidden control flow, visible errors - **Composition over inheritance**: Interfaces and embedding, not class hierarchies - **Built-in concurrency**: Goroutines and channels as first-class primitives - **Tooling-first**: Format, vet, test, and benchmark built into the language **Key Design Principles**: 1. Small interfaces (1-3 methods ideal) 2. Consumer-side interface placement 3. Error values, not exceptions 4. Happy path at left margin 5. Goroutines must have explicit termination --- ## 1. Idiomatic Go Patterns ### 1.1 Naming Conventions **Package Names**: ```go // ✅ GOOD: Package names are single lowercase identifiers // Import path: "net/url" → package name: url // Import path: "encoding/json" → package name: json package url // from "net/url" package json // from "encoding/json" package strings // ❌ BAD package urls // No plural package encodingjson // Don't smash words together package stringutils // Too verbose ``` **Getters and Setters**: ```go type Account struct { balance int } // ✅ GOOD: No "Get" prefix func (a *Account) Balance() int { return a.balance } func (a *Account) SetBalance(amount int) { a.balance = amount } // ❌ BAD: Java-style getters func (a *Account) GetBalance() int { return a.balance } ``` **Error Variables**: ```go // Exported sentinel errors (capitalized) var ErrNotFound = errors.New("not found") var ErrTimeout = errors.New("timeout") // Unexported internal errors (lowercase) var errInternal = errors.New("internal error") ``` **Interface Naming**: ```go // ✅ GOOD: Short, descriptive type Reader interface { Read(p []byte) (n int, err error) } type Writer interface { Write(p []byte) (n int, err error) } // ❌ BAD: Verbose or unclear type DataReader interface { ... } type IReader interface { ... } // No "I" prefix ``` --- ### 1.2 Interface Design - "The Bigger the Interface, the Weaker the Abstraction" **Core Principle**: Small, consumer-side interfaces provide maximum flexibility. **Single-Method Interfaces** (Ideal): ```go // Standard library examples type Reader interface { Read(p []byte) (n int, err error) } type Writer interface { Write(p []byte) (n int, err error) } type Closer interface { Close() error } // Compose interfaces type ReadCloser interface { Reader Closer } ``` **Consumer-Side Interface Placement**: ```go // ❌ WRONG: Producer defines interface package store type CustomerStorage interface { StoreCustomer(Customer) error GetCustomer(string) (Customer, error) UpdateCustomer(Customer) error // 10+ methods... } type PostgresStore struct {} func (s *PostgresStore) StoreCustomer(...) { ... } // ✅ CORRECT: Consumer defines what it needs package client type customerGetter interface { GetCustomer(string) (store.Customer, error) } func ProcessCustomer(cg customerGetter) { customer, _ := cg.GetCustomer("123") // Only depends on GetCustomer method } ``` **Return Concrete Types, Accept Interfaces** (Postel's Law): ```go // ✅ GOOD func NewStore() *PostgresStore { return &PostgresStore{} } func Process(storage CustomerStorage) error { // Accepts interface } // ❌ BAD: Returning interface func NewStore() CustomerStorage { return &PostgresStore{} } ``` **When to Create Interfaces**: - Multiple implementations exist or are planned - Need for testing (mocking dependencies) - Decoupling packages - **NOT for**: Single implementation with no testing need --- ### 1.3 Happy Path Left, Early Returns **Core Principle**: Align success path to left margin, handle errors first. ```go // ❌ BAD: Deep nesting func join(s1, s2 string, max int) (string, error) { if s1 == "" { return "", errors.New("s1 is empty") } else { if s2 == "" { return "", errors.New("s2 is empty") } else { concat, err := concatenate(s1, s2) if err != nil { return "", err } else { if len(concat) > max { return concat[:max], nil } else { return concat, nil } } } } } // ✅ GOOD: Happy path aligned left func join(s1, s2 string, max int) (string, error) { if s1 == "" { return "", errors.New("s1 is empty") } if s2 == "" { return "", errors.New("s2 is empty") } concat, err := concatenate(s1, s2) if err != nil { return "", err } if len(concat) > max { return concat[:max], nil } return concat, nil } ``` **Guidelines**: - Maximum 3-4 levels of nesting - Omit `else` blocks when `if` returns - Handle errors immediately - Keep normal flow at lowest indentation --- ### 1.4 Composition Over Inheritance **Type Embedding** (Struct Composition): ```go // Embedding for method promotion type Logger struct { *log.Logger prefix string } func NewLogger(prefix string) *Logger { return &Logger{ Logger: log.New(os.Stdout, "", 0), prefix: prefix, } } // Logger methods automatically available logger := NewLogger("APP") logger.Println("message") // Calls embedded log.Logger.Println ``` **Interface Composition**: ```go type Reader interface { Read(p []byte) (n int, err error) } type Closer interface { Close() error } // Compose interfaces type ReadCloser interface { Reader Closer } ``` **Warning**: Avoid embedding in public APIs: ```go // ❌ BAD: Exposes implementation details type MyHandler struct { http.Handler // Leaks all Handler methods } // ✅ GOOD: Explicit delegation type MyHandler struct { handler http.Handler } func (h *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Custom logic h.handler.ServeHTTP(w, r) } ``` --- ### 1.5 Key Go Idioms **Defer for Cleanup**: ```go func processFile(path string) error { f, err := os.Open(path) if err != nil { return err } defer f.Close() // Guaranteed cleanup // Multiple returns, all close file if condition { return nil // File closed } return process(f) // File closed } // Mutex pattern func (c *Counter) Increment() { c.mu.Lock() defer c.mu.Unlock() c.value++ // All paths unlock } ``` **Critical Rule**: Call `defer` AFTER checking error: ```go // ❌ WRONG defer f.Close() // f is nil if Open failed f, err := os.Open(path) // ✅ CORRECT f, err := os.Open(path) if err != nil { return err } defer f.Close() ``` **Multiple Return Values**: ```go // (value, error) - Standard error handling func GetUser(id string) (*User, error) { // ... } // (value, bool) - "comma ok" idiom value, ok := myMap[key] if !ok { // key not found } result, ok := someValue.(TargetType) if !ok { // type assertion failed } data, ok := <-channel if !ok { // channel closed } ``` **Blank Identifier `_`**: ```go // Ignore unwanted values _, err := os.Open(filename) // Compile-time interface check var _ http.Handler = (*MyHandler)(nil) // Import for side effects import _ "net/http/pprof" ``` **Useful Zero Values**: ```go // sync.Mutex - ready to use var mu sync.Mutex mu.Lock() // Works immediately // bytes.Buffer - valid empty buffer var buf bytes.Buffer buf.WriteString("hello") // No initialization needed // Slices - safe to read var s []int fmt.Println(len(s)) // 0 (safe) ``` --- ## 2. Error Handling ### 2.1 Error Wrapping with %w (Go 1.13+) **Core Pattern**: Wrap errors with context using `fmt.Errorf` and `%w`. ```go func processFile(path string) error { file, err := os.Open(path) if err != nil { // Wrap with context using %w return fmt.Errorf("failed to open file %s: %w", path, err) } defer file.Close() data, err := io.ReadAll(file) if err != nil { return fmt.Errorf("failed to read file %s: %w", path, err) } return processData(data) } // Result when error bubbles up: // "failed to initialize: failed to open file config.json: open config.json: no such file or directory" ``` **Checking Wrapped Errors**: ```go // errors.Is - Check for specific error in chain if errors.Is(err, os.ErrNotExist) { fmt.Println("File doesn't exist") } // errors.As - Extract specific error type var pathErr *os.PathError if errors.As(err, &pathErr) { fmt.Printf("Path error on: %s\n", pathErr.Path) } ``` **Critical**: Use `%w`, NOT `%v`: ```go // ❌ WRONG: Breaks error chain return fmt.Errorf("failed: %v", err) // ✅ CORRECT: Preserves chain return fmt.Errorf("failed: %w", err) ``` --- ### 2.2 Sentinel Errors vs Custom Error Types **Sentinel Errors** (Package-Level Variables): ```go package db var ( ErrConnectionFailed = errors.New("database connection failed") ErrRecordNotFound = errors.New("record not found") ErrDuplicateKey = errors.New("duplicate key violation") ) func GetUser(id int) (*User, error) { // ... if notFound { return nil, ErrRecordNotFound } return user, nil } // Caller checks with errors.Is user, err := db.GetUser(123) if errors.Is(err, db.ErrRecordNotFound) { // Handle not found } ``` **Custom Error Types** (Rich Context): ```go type ValidationError struct { Field string Value interface{} Message string } func (e *ValidationError) Error() string { return fmt.Sprintf("validation failed for field '%s': %s (value: %v)", e.Field, e.Message, e.Value) } func validateAge(age int) error { if age < 0 { return &ValidationError{ Field: "age", Value: age, Message: "must be non-negative", } } return nil } // Caller extracts rich information if err := validateAge(-5); err != nil { var valErr *ValidationError if errors.As(err, &valErr) { fmt.Printf("Field: %s, Value: %v\n", valErr.Field, valErr.Value) } } ``` **Decision Guide**: - **Sentinel errors**: Simple, global error conditions - **Custom types**: Errors needing structured data or methods **Important**: Use pointer receivers for error types: ```go // ✅ CORRECT: Pointer receiver func (e *ValidationError) Error() string { ... } // ❌ WRONG: Value receiver (breaks errors.As) func (e ValidationError) Error() string { ... } ``` ---
عرض على GitHub
ملف SKILL.md هذا كبير جدا، لذلك يعرض SkillsMP القسم الاول فقط هنا. عرض على GitHub