Files
teamai-test/.teamai/skills/common/golang-naming/references/functions-methods.md
T

4.0 KiB

Functions, Methods & Options

Functions and Methods

Functions returning a value are named like nouns (what they return). Functions performing actions are named like verbs (what they do).

// Noun-like: returns something
func UserName() string { ... }
func DefaultConfig() Config { ... }

// Verb-like: performs an action
func WriteFile(name string, data []byte) error { ... }
func SendNotification(user *User) error { ... }

NEVER repeat the package name in function names:

// Good: users call http.Get(), not http.HTTPGet()
package http
func Get(url string) (*Response, error)

// Bad: stutters at the call site
package http
func HTTPGet(url string) (*Response, error)

Functions that accept a format string and variadic args (like fmt.Sprintf) MUST end with f:

// Good
func Errorf(format string, args ...any) error
func Wrapf(err error, format string, args ...any) error
func Logf(format string, args ...any)

// Bad
func Error(format string, args ...any) error    // looks like it takes a plain string
func WrapError(err error, format string, args ...any) error

Getters and Setters

Getters MUST NOT use the Get prefix. The getter is simply the field name, capitalized.

// Good
func (u *User) Name() string        { return u.name }
func (u *User) SetName(name string)  { u.name = name }

// Bad
func (u *User) GetName() string      { return u.name }

Only use Get when the underlying concept inherently uses "get" (e.g., HTTP GET). For expensive or blocking operations, use Fetch or Compute to signal that the call is not trivial.

Exception — boolean predicates keep the Is/Has/Can prefix. The no-Get rule applies to value getters, not boolean predicates. A method returning bool SHOULD use Is/Has/Can to read naturally as a question — this follows the standard library pattern (reflect.Type.IsVariadic(), net.IP.IsLoopback(), big.Int.IsInt64()).

// Good — boolean predicate keeps Is prefix
func (s *Server) IsHealthy() bool   { return s.healthy }

// Good — value getter omits Get prefix
func (s *Server) Port() int         { return s.port }

// Good — richer return type, bare name is fine (different semantics)
func (s *Server) Healthy() (HealthStatus, error)

// Bad — bare adjective for bool is ambiguous
func (s *Server) Healthy() bool     { return s.healthy }

// Bad — Get prefix on value getter is redundant
func (s *Server) GetPort() int      { return s.port }

Constructors

Name constructors New when the package exports a single primary type, or NewTypeName when there are multiple types.

// Single primary type — New is unambiguous
package ring
func New(size int) *Ring

// Multiple types — qualify with the type name
package http
func NewRequest(method, url string, body io.Reader) (*Request, error)
func NewServeMux() *ServeMux

Named Return Values

Named return values SHOULD only be used when it improves readability — typically when multiple return values have the same type, or when the names serve as documentation.

// Good — names clarify which int64 is which
func Copy(dst Writer, src Reader) (written int64, err error)
func ScanBytes(data []byte, atEOF bool) (advance int, token []byte, err error)

// Good — single error return, no name needed
func Write(p []byte) (int, error)

// Bad — names add no clarity
func Read(p []byte) (bytes int, e error)  // "bytes" shadows the package, "e" is non-standard

NEVER use named returns just to enable bare return — bare returns hurt readability in anything but the shortest functions.

Functional Options Pattern

When a constructor has 3+ optional parameters that may grow, use the functional options pattern for clean, extensible APIs.

  • Struct: ServerOptions, ClientOptions (not Opts, Params, Settings, Config)
  • Function type: ServerOption (singular, not plural)
  • With* functions: WithPort(), WithTimeout(), WithLogger()
  • Factory: DefaultServerOptions()