skills/0xbigboss/go-best-practices/SKILL.md
Provides Go patterns for type-first development with custom types, interfaces, functional options, and error handling. Must use when reading or writing Go files.
npx skillsauth add aiskillstore/marketplace go-best-practicesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Types define the contract before implementation. Follow this workflow:
Use Go's type system to prevent invalid states at compile time.
Structs for domain models:
// Define the data model first
type User struct {
ID UserID
Email string
Name string
CreatedAt time.Time
}
type CreateUserRequest struct {
Email string
Name string
}
// Functions follow from the types
func CreateUser(req CreateUserRequest) (*User, error) {
// implementation
}
Custom types for domain primitives:
// Distinct types prevent mixing up IDs
type UserID string
type OrderID string
func GetUser(id UserID) (*User, error) {
// Compiler prevents passing OrderID here
}
func NewUserID(raw string) UserID {
return UserID(raw)
}
// Methods attach behavior to the type
func (id UserID) String() string {
return string(id)
}
Interfaces for behavior contracts:
// Define what you need, not what you have
type Reader interface {
Read(p []byte) (n int, err error)
}
type UserRepository interface {
GetByID(ctx context.Context, id UserID) (*User, error)
Save(ctx context.Context, user *User) error
}
// Accept interfaces, return structs
func ProcessInput(r Reader) ([]byte, error) {
return io.ReadAll(r)
}
Enums with iota:
type Status int
const (
StatusActive Status = iota + 1
StatusInactive
StatusPending
)
func (s Status) String() string {
switch s {
case StatusActive:
return "active"
case StatusInactive:
return "inactive"
case StatusPending:
return "pending"
default:
return fmt.Sprintf("Status(%d)", s)
}
}
// Exhaustive handling in switch
func ProcessStatus(s Status) (string, error) {
switch s {
case StatusActive:
return "processing", nil
case StatusInactive:
return "skipped", nil
case StatusPending:
return "waiting", nil
default:
return "", fmt.Errorf("unhandled status: %v", s)
}
}
Functional options for flexible construction:
type ServerOption func(*Server)
func WithPort(port int) ServerOption {
return func(s *Server) {
s.port = port
}
}
func WithTimeout(d time.Duration) ServerOption {
return func(s *Server) {
s.timeout = d
}
}
func NewServer(opts ...ServerOption) *Server {
s := &Server{
port: 8080, // sensible defaults
timeout: 30 * time.Second,
}
for _, opt := range opts {
opt(s)
}
return s
}
// Usage: NewServer(WithPort(3000), WithTimeout(time.Minute))
Embed for composition:
type Timestamps struct {
CreatedAt time.Time
UpdatedAt time.Time
}
type User struct {
Timestamps // embedded - User has CreatedAt, UpdatedAt
ID UserID
Email string
}
Prefer smaller files within packages: one type or concern per file. Split when a file handles multiple unrelated types or exceeds ~300 lines. Keep tests in _test.go files alongside implementation. Package boundaries define the API; internal organization is flexible.
sort.Slice, iterators).fmt.Errorf and %w for wrapping. This preserves the error chain for debugging.switch statements; include a default case that returns an error. Exhaustive handling prevents silent bugs.context.Context to external calls with explicit timeouts. Runaway requests cause cascading failures.panic for truly unrecoverable situations; prefer returning errors. Panics crash the program.Explicit failure for unimplemented logic:
func buildWidget(widgetType string) (*Widget, error) {
return nil, fmt.Errorf("buildWidget not implemented for type: %s", widgetType)
}
Wrap errors with context to preserve the chain:
out, err := client.Do(ctx, req)
if err != nil {
return nil, fmt.Errorf("fetch widget failed: %w", err)
}
return out, nil
Exhaustive switch with default error:
func processStatus(status string) (string, error) {
switch status {
case "active":
return "processing", nil
case "inactive":
return "skipped", nil
default:
return "", fmt.Errorf("unhandled status: %s", status)
}
}
Structured logging with slog:
import "log/slog"
var log = slog.With("component", "widgets")
func createWidget(name string) (*Widget, error) {
log.Debug("creating widget", "name", name)
widget := &Widget{Name: name}
log.Debug("created widget", "id", widget.ID)
return widget, nil
}
os.Getenv scattered throughout code.Typed config struct:
type Config struct {
Port int
DatabaseURL string
APIKey string
Env string
}
func LoadConfig() (*Config, error) {
dbURL := os.Getenv("DATABASE_URL")
if dbURL == "" {
return nil, fmt.Errorf("DATABASE_URL is required")
}
apiKey := os.Getenv("API_KEY")
if apiKey == "" {
return nil, fmt.Errorf("API_KEY is required")
}
port := 3000
if p := os.Getenv("PORT"); p != "" {
var err error
port, err = strconv.Atoi(p)
if err != nil {
return nil, fmt.Errorf("invalid PORT: %w", err)
}
}
return &Config{
Port: port,
DatabaseURL: dbURL,
APIKey: apiKey,
Env: getEnvOrDefault("ENV", "development"),
}, nil
}
development
Apple Human Interface Guidelines for content display components. Use this skill when the user asks about charts component, collection view, image view, web view, color well, image well, activity view, lockup, data visualization, content display, displaying images, rendering web content, color pickers, or presenting collections of items in Apple apps. Also use when the user says how should I display charts, what's the best way to show images, should I use a web view, how do I build a grid of items, what component shows media, or how do I present a share sheet. Cross-references: hig-foundations for color/typography/accessibility, hig-patterns for data visualization patterns, hig-components-layout for structural containers, hig-platforms for platform-specific component behavior.
tools
Automate HelpDesk tasks via Rube MCP (Composio): list tickets, manage views, use canned responses, and configure custom fields. Always search tools first for current schemas.
testing
Expert Haskell engineer specializing in advanced type systems, pure functional design, and high-reliability software. Use PROACTIVELY for type-level programming, concurrency, and architecture guidance.
tools
GraphQL gives clients exactly the data they need - no more, no less. One endpoint, typed schema, introspection. But the flexibility that makes it powerful also makes it dangerous. Without proper controls, clients can craft queries that bring down your server. This skill covers schema design, resolvers, DataLoader for N+1 prevention, federation for microservices, and client integration with Apollo/urql. Key insight: GraphQL is a contract. The schema is the API documentation. Design it carefully.