Implementing gRPC Best Practices

1. Following Naming Conventions

ElementConvention
Packagelower.snake.v1
ServicePascalCase + "Service"
MethodVerbNoun (GetUser, ListUsers)
MessagePascalCase; RequestNameRequest / ResponseNameResponse
Fieldlower_snake_case
Enum valueUPPER_SNAKE; first = UNSPECIFIED = 0

2. Versioning APIs Properly

RuleDetail
Version in packageuser.v1 not URL
Breaking changeBump major (v2)
Stable interfaceAvoid breaking even minor

3. Designing Idempotent Methods

PatternDetail
Get / ListNaturally idempotent
CreateUse idempotency key
UpdateUse field mask + ETag
DeleteIdempotent — second call returns NOT_FOUND or OK

4. Using Appropriate RPC Type

ChoiceWhen
UnarySimple request/response
Server streamLarge or open-ended result set
Client streamUploads, batched writes
Bidi streamReal-time / interactive

5. Setting Proper Deadlines

RuleDetail
Always setClient side, every call
PropagatePass ctx into downstream calls
Budget allocationSub-call deadline < remaining

6. Handling Errors Properly

RuleDetail
Use canonical codesDon't overload INTERNAL
Rich detailsErrorInfo, BadRequest, RetryInfo
Never leak internalsMap errors at boundary

7. Documenting Services

WhereDetail
Proto commentsAbove service / method / message / field
Generated docsprotoc-gen-doc, buf.build registry
ExamplesInclude sample requests & responses

8. Monitoring Services

SignalDetail
RED metricsRate, Errors, Duration
SLI/SLOAvailability + latency target per method
AlertingMulti-window multi-burn-rate

9. Testing Thoroughly

LayerDetail
UnitService methods in isolation
Integrationbufconn + real deps
ContractProto compat across versions
Loadghz / k6 against staging

10. Securing Communications

DefaultDetail
TLS everywhereEven internal mesh
mTLS for service-to-serviceMutual identity
Rotate keys/certsAutomate via cert-manager / SPIRE

11. Implementing Graceful Shutdown

Example: Signal-driven shutdown

sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
<-sig
h.Shutdown()                                     // mark health NOT_SERVING
time.Sleep(2 * time.Second)                      // let LB notice
done := make(chan struct{})
go func() { srv.GracefulStop(); close(done) }()
select {
case <-done:
case <-time.After(30 * time.Second):
    srv.Stop()
}

12. Reviewing Code Regularly

PracticeDetail
Proto reviewRequired for any .proto change
Backward compat checkbuf breaking in CI
Lintbuf lint enforces style
Security reviewFor auth, crypto, input validation changes
Performance reviewFor new streaming or hot-path RPCs