Handling Technical Disagreements on Go Teams
Facilitation patterns for idioms vs frameworks debates.
Search across all documentation pages
Facilitation patterns for idioms vs frameworks debates.
Go teams argue about the right kind of things: stdlib versus routers, generics versus interfaces, monolith versus modules, errgroup versus channels.
Healthy disagreement improves designs.
Unfacilitated disagreement becomes incompatible services and bitter review threads.
Technical disagreements on Go teams usually involve trade-offs between simplicity, velocity, and operational familiarity.
Facilitation means making options explicit, scoring against agreed criteria, assigning a decision owner, and recording outcomes in ADRs or team standards.
The goal is not unanimous enthusiasm.
It is disagree and commit with a review date when data may change the call.
Quick-reference recipe card - copy-paste ready.
## Technical decision: <topic>
Options:
1. ...
2. ...
Criteria (weighted):
- operability
- team familiarity
- compile/deploy time
- consistency with ADR index
Decision owner: @name
Deadline: <date>
Fallback review: <quarter>When to reach for this:
Two seniors disagree on worker concurrency: channels vs errgroup.
## Decision record (meeting output)
Topic: ingest worker orchestration
Options:
A) errgroup + SetLimit
B) worker pool channel + fixed goroutines
Criteria scores (1-5):
| Criterion | A | B |
|-----------|---|---|
| Shutdown clarity | 5 | 3 |
| Team familiarity | 4 | 4 |
| Testability | 5 | 4 |
Decision: A for new ingest worker; B remains in legacy billing until ADR 0031 superseded
Owner: @tl
Review: after Q3 load test// Agreed reference snippet for option A
g, ctx := errgroup.WithContext(ctx)
g.SetLimit(8)
for _, job := range batch {
g.Go(func() error { return process(ctx, job) })
}
return g.Wait()What this demonstrates:
| Debate | Underlying tension | Facilitation tip |
|---|---|---|
| stdlib vs chi/gin | Consistency vs DX | Org default + documented exceptions |
| generics vs interfaces | Clarity vs abstraction | Prototype both on same API sketch |
| monolith vs micro-module | Compile speed vs autonomy | Measure tag churn before split |
| sync vs async worker | Latency vs complexity | Load test before choosing channels |
| slog vs zap | Stdlib vs ecosystem | Pick per observability ADR |
// When debating error libraries, anchor on stdlib first
if errors.Is(err, ErrNotFound) {
return mapNotFound()
}depguard banned imports).| Alternative | Use When | Don't Use When |
|---|---|---|
| Spike both options | Evidence thin | Decision blocks multiple teams weeks |
| Escalate to architect council | Cross-org impact | Squad-local handler style |
| Default to stdlib minimalism | No data, equal scores | Framework clearly saves weeks |
| Defer decision | Low impact fork | Production concurrency choice |
Tech lead for squad scope; staff/platform for cross-cutting defaults; engineering director for policy exceptions.
One focused session plus async doc comments - usually under one week for squad decisions.
Pick org default (often stdlib simplicity) and set review date after next benchmark or launch.
Yes in ADR notes - helps future reviewers understand context without reopening fight.
Move to decision doc thread; keep Slack for facts, not polls that bypass criteria.
When decision affects SLOs, security posture, or multiple teams' module graphs.
Only with superseding ADR approved by platform owner - not local README exceptions.
Measure outcomes: incident count, review time, onboarding weeks - not slogans.
Welcome criteria input; decision owner still decides with leveling-appropriate scope.
Use criteria scoring over raw votes - popularity misses operability constraints.
Bring new data to review date or file superseding ADR with migration plan.
No - block on security, data loss, or race risks regardless of process outcome.
Stack versions: This page was written for Go 1.26.x (Green Tea GC default, go fix modernizers - verify patch at build), chi (latest - verify at build), gin (latest - verify at build), echo (latest - verify at build), google.golang.org/grpc (latest - verify at build), sigs.k8s.io/controller-runtime (latest - verify at build), kubebuilder (latest - verify at build), tinygo (latest - verify board targets at build), wazero (latest - verify at build), and golangci-lint (latest - verify linter set at build).
Reviewed by Chris St. John·Last updated Jul 16, 2026