Claude-skill-registry declaration-practices
Reviews Go variable and constant declarations for proper scope, grouping, and zero value usage. Use when reviewing declaration blocks, creating new Go packages, or seeing ungrouped imports/vars.
install
source · Clone the upstream repo
git clone https://github.com/majiayu000/claude-skill-registry
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/declaration-practices" ~/.claude/skills/majiayu000-claude-skill-registry-declaration-practices && rm -rf "$T"
manifest:
skills/data/declaration-practices/SKILL.mdsource content
Declaration Practices
Purpose
Establish patterns for variable and constant declarations in RMS Go code. Proper declarations improve readability and catch errors early.
Core Principles
- Minimal scope - Declare variables as close to use as possible
- Logical grouping - Group related declarations together
- Zero value awareness - Understand and leverage Go's zero values
- Type inference - Use
for local variables when type is obvious:=
Import Organization
Standard Grouping
Group imports in this order, separated by blank lines:
- Standard library
- External packages
- Internal packages
// DO: Organized imports import ( "context" "errors" "fmt" "time" "github.com/go-chi/chi/v5" "google.golang.org/grpc" "git.taservs.net/rms/taskcore/entity" "git.taservs.net/rms/zeke/clients" )
// DON'T: Mixed imports import ( "git.taservs.net/rms/taskcore/entity" "context" "github.com/go-chi/chi/v5" "fmt" "google.golang.org/grpc" )
Import Aliases
Use aliases sparingly, only when needed for clarity or conflicts.
// DO: Alias for conflict resolution import ( "context" taskpb "git.taservs.net/rms/proto/task" userpb "git.taservs.net/rms/proto/user" ) // DO: Alias for clarity (long package path) import ( rmscontext "git.taservs.net/rms/common/context" ) // DON'T: Unnecessary aliases import ( ctx "context" // Not needed e "errors" // Not needed )
Variable Declaration
Short Declaration (:=
)
:=Use for local variables when the type is obvious.
// DO: Short declaration for obvious types ctx := context.Background() err := doSomething() tasks := make([]*Task, 0) count := 0 name := "default" // DON'T: Redundant type declaration var ctx context.Context = context.Background() var count int = 0
Explicit Type Declaration (var
)
varUse when zero value is desired or type isn't obvious.
// DO: var for zero value initialization var ( total int64 results []*Result err error ) // DO: var when type isn't obvious var timeout time.Duration = 30 * time.Second var handler http.Handler = &CustomHandler{} // DO: var for package-level variables var DefaultTimeout = 30 * time.Second
Declaration Grouping
Group related declarations together.
// DO: Group related variables var ( ErrNotFound = errors.New("not found") ErrInvalidInput = errors.New("invalid input") ErrUnauthorized = errors.New("unauthorized") ) const ( DefaultTimeout = 30 * time.Second DefaultMaxRetries = 3 DefaultBatchSize = 100 ) // DON'T: Scatter related declarations var ErrNotFound = errors.New("not found") const DefaultTimeout = 30 * time.Second var ErrInvalidInput = errors.New("invalid input") const DefaultMaxRetries = 3
Constant Declaration
Typed Constants
Use typed constants for type safety.
// DO: Typed constants type Status string const ( StatusPending Status = "PENDING" StatusInProgress Status = "IN_PROGRESS" StatusComplete Status = "COMPLETE" ) type Priority int const ( PriorityLow Priority = 1 PriorityMedium Priority = 2 PriorityHigh Priority = 3 )
Untyped Constants
Use untyped constants for values that should adapt to context.
// DO: Untyped constants for flexibility const ( KB = 1024 MB = KB * 1024 GB = MB * 1024 ) // Can be used with any numeric type var size32 int32 = 10 * MB var size64 int64 = 10 * MB // DO: Untyped string constants const ( Version = "1.0.0" AppName = "taskcore" UserAgent = AppName + "/" + Version )
Iota for Sequential Values
// DO: iota for sequential constants type Priority int const ( PriorityLow Priority = iota + 1 PriorityMedium PriorityHigh PriorityCritical ) // PriorityLow=1, PriorityMedium=2, PriorityHigh=3, PriorityCritical=4 // DO: iota for bit flags type Permission int const ( PermRead Permission = 1 << iota PermWrite PermDelete PermAdmin ) // PermRead=1, PermWrite=2, PermDelete=4, PermAdmin=8
Zero Values
Understanding Zero Values
| Type | Zero Value |
|---|---|
| |
| Numeric | |
| |
| Pointer | |
| Slice | |
| Map | |
| Channel | |
| Interface | |
| Struct | All fields zero |
Leveraging Zero Values
// DO: Use zero values intentionally type Task struct { ID rms.ID Title string Status Status // Zero value is "" Priority Priority // Zero value is 0 } func NewTask(title string) *Task { return &Task{ Title: title, // Status and Priority get zero values } } // DO: Check for zero value func (t *Task) HasPriority() bool { return t.Priority != 0 } // DO: Provide defaults when zero isn't appropriate func (t *Task) EffectivePriority() Priority { if t.Priority == 0 { return PriorityMedium } return t.Priority }
Nil Slice vs Empty Slice
// DO: Nil slice when "no data" is valid func (s *Store) List(ctx context.Context) ([]*Task, error) { // Returns nil slice when empty } // DO: Empty slice for JSON serialization func (s *Store) ListForAPI(ctx context.Context) ([]*Task, error) { tasks, err := s.List(ctx) if err != nil { return nil, err } if tasks == nil { return []*Task{}, nil // Empty slice, serializes as [] } return tasks, nil }
Scope Minimization
Declare Close to Use
// DO: Declare where first used func process(ctx context.Context, items []Item) error { for _, item := range items { // result declared in loop scope result, err := transform(item) if err != nil { return err } if result.RequiresValidation { // validator only needed conditionally validator := NewValidator(item.Type) if err := validator.Validate(result); err != nil { return err } } if err := save(ctx, result); err != nil { return err } } return nil }
// DON'T: Declare all at top func process(ctx context.Context, items []Item) error { var result *Result var validator *Validator var err error for _, item := range items { result, err = transform(item) // ... } return nil }
If with Initialization
// DO: Limit scope with if-init if err := validate(task); err != nil { return fmt.Errorf("validate: %w", err) } if task, err := store.Get(ctx, id); err != nil { return nil, err } else if task == nil { return nil, ErrNotFound } // DO: Comma-ok idiom if value, ok := cache.Get(key); ok { return value, nil } if task, ok := entity.(*Task); ok { return processTask(task) }
Package-Level Variables
When to Use
Package-level variables should be:
- Constants or effectively constant (set once)
- Configuration loaded at startup
- Sentinel errors
// DO: Package-level sentinel errors var ( ErrNotFound = errors.New("not found") ErrAlreadyExists = errors.New("already exists") ErrInvalidArgument = errors.New("invalid argument") ) // DO: Package-level configuration var ( DefaultTimeout = 30 * time.Second MaxBatchSize = 1000 ) // DON'T: Mutable state at package level var currentUser *User // Race condition risk var taskCount int // Race condition risk
Initialization
// DO: Initialize in init() if needed var ( logger rms.Logger httpClient *http.Client ) func init() { logger = rms.NewLogger("taskcore") httpClient = &http.Client{ Timeout: DefaultTimeout, } } // BETTER: Initialize with function var httpClient = newHTTPClient() func newHTTPClient() *http.Client { return &http.Client{ Timeout: DefaultTimeout, } }
Quick Reference
| Situation | Syntax |
|---|---|
| Obvious type, local | |
| Zero value needed | |
| Explicit type needed | |
| Package-level | block |
| Constants | block |
| Typed enum | + |
Declaration Checklist
- Imports grouped (std, external, internal)?
- Related vars/consts grouped together?
- Variables declared close to use?
- Zero values used intentionally?
- Package-level variables minimized?
- Types specified only when necessary?
See Also
- naming-convention - Variable naming
- control-flow - Scope reduction with if-init
- code-structure - Package organization