| name | cox-tooling-excellence |
| description | Write Go code in the style of Russ Cox, Go tech lead. Emphasizes tooling, module design, correctness, and backward compatibility. Use when designing packages, modules, or tools that others will depend on. |
Russ Cox Style Guide
Overview
Russ Cox is the tech lead of Go at Google. He designed the Go module system, maintains critical tools, and writes extensively about correctness and compatibility. His work on regular expressions (RE2) and the Go toolchain sets the standard for quality.
Core Philosophy
"Compatibility is about people, not just code."
"The goal is not to be fast. The goal is to be correct and then fast."
Cox believes in correctness first, then performance. He also champions the Go 1 compatibility promise: code written for Go 1.0 should still work.
Design Principles
-
Correctness First: Get it right before getting it fast.
-
Compatibility Matters: Breaking changes hurt real people.
-
Tooling is Product: go mod, go vet, gofmt are as important as the language.
-
Reproducibility: Builds should be reproducible, dependencies explicit.
When Writing Code
Always
- Use
go mod for dependency management
- Run
go vet and address all warnings
- Write reproducible builds (pin dependencies)
- Maintain backward compatibility in public APIs
- Use semantic versioning correctly
- Document breaking changes clearly
Never
- Break existing API contracts
- Publish v0 code as v1
- Ignore module versioning rules
- Use
replace directives in published modules
- Import packages with
_ prefix
Prefer
- Stable APIs over flexible ones
- Explicit imports over dot imports
- Internal packages for private code
- Minimal dependencies
- Standard library when possible
Code Patterns
Module Design
module github.com/example/myproject
go 1.21
require (
golang.org/x/sync v0.5.0
)
API Stability with Options Pattern
type Config struct {
Timeout time.Duration
}
type Option func(*clientOptions)
type clientOptions struct {
timeout time.Duration
retries int
logger Logger
}
func WithTimeout(d time.Duration) Option {
return func(o *clientOptions) {
o.timeout = d
}
}
func WithRetries(n int) Option {
return func(o *clientOptions) {
o.retries = n
}
}
func NewClient(opts ...Option) *Client {
options := clientOptions{
timeout: 30 * time.Second,
retries: 3,
}
for _, opt := range opts {
opt(&options)
}
return &Client{options: options}
}
client := NewClient(WithTimeout(10 * time.Second))
Internal Packages
Semantic Versioning
module github.com/example/myproject/v2
go 1.21
import "github.com/example/myproject/v2/pkg"
Deprecation Without Breaking
func Foo() *Widget {
return NewFoo(DefaultOptions)
}
func NewFoo(opts Options) *Widget {
}
Correct Concurrent Code
type Cache struct {
mu sync.RWMutex
items map[string]Item
}
func (c *Cache) Get(key string) (Item, bool) {
c.mu.RLock()
defer c.mu.RUnlock()
item, ok := c.items[key]
return item, ok
}
func (c *Cache) Set(key string, item Item) {
c.mu.Lock()
defer c.mu.Unlock()
if c.items == nil {
c.items = make(map[string]Item)
}
c.items[key] = item
}
func serve(ctx context.Context, addr string, handler http.Handler) error {
srv := &http.Server{Addr: addr, Handler: handler}
errCh := make(chan error, 1)
go func() {
errCh <- srv.ListenAndServe()
}()
select {
case err := <-errCh:
return err
case <-ctx.Done():
shutdownCtx, cancel := context.WithTimeout(
context.Background(),
5*time.Second,
)
defer cancel()
return srv.Shutdown(shutdownCtx)
}
}
Testing Best Practices
func TestParse(t *testing.T) {
tests := []struct {
name string
input string
want Result
wantErr bool
}{
{"empty", "", Result{}, false},
{"simple", "foo", Result{Value: "foo"}, false},
{"invalid", "!!!", Result{}, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := Parse(tt.input)
if (err != nil) != tt.wantErr {
t.Errorf("Parse() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("Parse() = %v, want %v", got, tt.want)
}
})
}
}
func newTestServer(t *testing.T) *Server {
t.Helper()
srv := &Server{}
t.Cleanup(func() { srv.Close() })
return srv
}
Mental Model
Cox approaches design by asking:
- Is it correct? Prove it works before optimizing.
- Is it compatible? Will existing code break?
- Is it reproducible? Same inputs → same outputs?
- Is it maintainable? Will this be regretted in 5 years?
The Compatibility Contract
| Change | Safe? |
|---|
| Add function | ✅ Yes |
| Add method to interface | ❌ No (breaks implementers) |
| Add field to struct | ⚠️ Maybe (if not compared) |
| Add optional parameter | ✅ Yes (via options pattern) |
| Change function signature | ❌ No |
| Rename exported symbol | ❌ No |