skip to content
Sandip's Blog
Table of Contents

1. Interfaces (the heart of Go)

  • Implicit satisfaction (structural typing)
  • Small interfaces (io.Reader, io.Writer, fmt.Stringer, error)
  • “Accept interfaces, return structs”
  • Define interfaces on the consumer side
  • Empty interface / any, type assertions, type switches
  • Interface internals: (type, value) pair
  • The nil interface gotcha: an interface holding a nil pointer is not nil
  • Embedding interfaces, composition over inheritance

Visual: implicit interface satisfaction

classDiagram
  class Reader {
    <<interface>>
    Read(p []byte) (n int, err error)
  }
  class File
  class Buffer
  class HTTPBody
  Reader <|.. File : implicit
  Reader <|.. Buffer : implicit
  Reader <|.. HTTPBody : implicit

No implements keyword: any type with the right methods satisfies the interface.

2. Error handling

  • error is just an interface
  • fmt.Errorf("...: %w", err) wrapping
  • errors.Is, errors.As, errors.Join, errors.Unwrap
  • Sentinel errors vs custom error types
  • Don’t ignore errors; don’t log and return the same error
  • panic / recover: only for truly unrecoverable states or package boundaries
  • Adding context to errors as they bubble up

Visual: error wrapping chain

flowchart LR
  A["handler error<br/>'create user: ...'"] -->|"%w"| B["service error<br/>'insert row: ...'"]
  B -->|"%w"| C["driver error<br/>sql.ErrNoRows"]
  A -. "errors.Is(err, sql.ErrNoRows)" .-> C

errors.Is and errors.As walk this chain for you.

3. Generics (Go 1.18+)

  • Type parameters and constraints
  • any, comparable, cmp.Ordered, custom constraint interfaces
  • Generic functions and generic types
  • Type inference
  • When NOT to use generics (prefer interfaces or plain code first)
  • Packages: slices, maps, cmp

4. Packages and modules

  • go mod init, go.mod, go.sum
  • Semantic versioning, go get, go mod tidy, go mod vendor
  • Major version suffix (/v2)
  • internal/ packages
  • Exported vs unexported (capitalization)
  • Package naming: short, lowercase, no underscores
  • Avoiding import cycles
  • Workspaces (go.work)
  • Standard project layout (don’t over-engineer): cmd/, internal/, pkg/ (optional)

5. Idioms to internalize

  • Functional options pattern
  • Constructor functions (NewX)
  • Make the zero value useful
  • Early return, avoid deep nesting
  • Table-driven design
  • iota enums plus String() method
  • Embedding for delegation
  • Method values and method expressions

6. Reflection and unsafe (awareness level)

  • reflect.TypeOf, reflect.ValueOf: know what it can do and why it is slow
  • Struct tags and how encoding/json uses them
  • unsafe exists; know to avoid it

7. Iterators (Go 1.23+)

  • iter.Seq, iter.Seq2
  • Range-over-func
  • slices.Collect, maps.Keys

Practice

  • Write a generic Stack[T], Set[T comparable], and Map/Filter/Reduce
  • Build a custom error type hierarchy with errors.Is/As
  • Implement your own io.Reader that transforms data (e.g. uppercase)
  • Create a library with the functional options pattern

Previous: Go Mastery 1: Fundamentals Revision
Next: Go Mastery 3: Concurrency Done Right

Back to the roadmap