Go

Interfaces, Errors & Context

Julien Bisconti

Software Engineer / SRE

Google Cloud Platform icon

slides: bisconti.cloud

contact: g.dev/julien

qrcode link to Julien Bisconti contact information

Strong points

  • First class testing
  • First class concurrency
  • Fast compile times
  • Straightforward dependency management
  • backward compatibility guarantee

The Core Philosophy: “Less is More”

  • Simplicity & Readability: Code is read far more often than it is written.
  • Composition over Inheritance: Build complex things from simple, independent pieces.
  • Concurrency is a First-Class Citizen: Make it easy to do things in parallel.
  • Pragmatism: Focus on what works, not on theoretical purity.

Key Go Proverbs

“A little copying is better than a little dependency.”

“The bigger the interface, the weaker the abstraction.”

“Errors are values.”

Go proverbs

Interfaces: Implicit Satisfaction

An interface is a set of method signatures.

Rule: If your type has the methods, it fits the interface. No implements keyword needed.

(Structural Typing / Duck Typing)

Code Example: The io.Reader

// The interface
type Reader interface {
    Read(p []byte) (n int, err error)
}

// A function that accepts any Reader
func logData(r io.Reader) { io.Copy(os.Stdout, r) }

// Two different types can be passed to logData
var f *os.File
var s *strings.Reader

logData(f)
logData(s)

bytes.Buffer#Read

Example 1 & 2

Where Do Interfaces Belong?

“Accept Interfaces, Return Structs”

  • Don’t define interfaces in the package that provides the implementation.
  • Define interfaces in the package that uses the functionality.

Interfaces for Painless Testing

No Third-Party Mocking Libraries Needed!

// Interface defined by consumer
type UserStorer interface {
    GetUser(id int) (*User, error)
}

// Real implementation
type DB struct{ ... }
func (db *DB) GetUser(id int) (*User, error) {
    // ... real db logic
}

// Mock implementation for tests
type mockUserStorer struct{}
func (m *mockUserStorer) GetUser(id int) (*User, error) {
    return &User{ID: id, Name: "Mock User"}, nil
}

// In your test:
func TestGetUserEndpoint(t *testing.T) {
    mockDB := &mockUserStorer{}
    handler := NewHandler(mockDB) // Handler depends on UserStorer
    // ... test the handler
}

The Go Way of Testing

Simple, Opinionated, Effective

  1. go test is all you need.
  2. thing_test.go lives in the same package.
  3. “A little bit of copying is better than a little bit of dependency.”

Table-Driven Test Example

func TestAdd(t *testing.T) {
    testCases := []struct {
        name string
        a, b int
        want int
    }{
        {"positive numbers", 2, 3, 5},
        {"negative numbers", -1, -5, -6},
        {"zero", 5, 0, 5},
    }

    for _, tc := range testCases {
        t.Run(tc.name, func(t *testing.T) {
            got := Add(tc.a, tc.b)
            if got != tc.want {
                t.Errorf("got %d; want %d", got, tc.want)
            }
        })
    }
}

See also Generic interfaces

“Errors are values”

  • Go has no “try…catch”.

  • Functions that can fail return two things: the result and an error value.

    value, err := someFunction()
    
  • The error type is just an interface:

    type error interface { Error() string }
    

Read Go Blog

The “if err != nil” Pattern

f, err := os.Open("my_file.txt")
if err != nil {
    log.Fatalf("failed to open file: %v", err)
}
defer f.Close()

// ... do something with f ...
  • Clarity: The “happy path” is clear. Errors are handled immediately.
  • Robustness: Explicit checks make it harder to ignore errors.

Example 3

Tying It All Together

Philosophy of Simplicity

Small, Composable Interfaces

Explicit, Value-based Error Handling

Go’s features aren’t isolated; they are a cohesive system designed for clarity and reliability.

Context

The Lifeline of an Operation

context.Context is an interface.

Read Go Blog

Example 4

Resources

THANK YOU

and I'm sorry 🙏
If you had to maintain my code
I hope you learned more by maintaining it
than me by writing it

Slides made with Reveal.js and hugo-reveal

Julien Bisconti

Software Engineer / SRE

Google Cloud Platform icon

slides: bisconti.cloud

contact: g.dev/julien

qrcode link to Julien Bisconti contact information