Performance Considerations
Performance is not a feature you add.
It is a property that emerges from design choices.
In Plumego, performance work follows a strict rule:
Measure first, optimize second, and never trade clarity for unproven gains.
This document explains how to reason about performance in Plumego systems
without drifting into premature optimization or hidden complexity.
What Plumego Optimizes For by Default
Plumego’s core design already optimizes for several important properties:
- Minimal abstraction overhead
- Zero reflection
- No runtime dependency injection
- Deterministic control flow
- Direct use of
net/http
This means:
- Baseline overhead is low
- Performance characteristics are predictable
- There are no “framework black boxes”
Before optimizing, understand what is already cheap.
The Real Sources of Slowness
In real Plumego systems, performance issues almost always come from:
- Network I/O (databases, services)
- Serialization and deserialization
- Allocation pressure
- Lock contention
- Unbounded concurrency
- Inefficient algorithms
Framework overhead is rarely the bottleneck.
Optimizing Plumego itself is usually the wrong target.
Measure Before You Optimize
Never optimize based on intuition alone.
Always start with:
- Latency percentiles (p50 / p95 / p99)
- Throughput under load
- CPU profiles
- Memory profiles
- Allocation profiles
Use standard Go tools:
pprofgo test -bench- Load generators (
wrk,hey,k6)
If you cannot explain where time is going,
you are not ready to optimize.
Understanding the Request Cost Breakdown
A typical request cost looks like:
HTTP parsing
→ Middleware execution
→ Routing
→ Handler logic
→ I/O (DB / network)
→ Serialization
→ Response write
In Plumego:
- Middleware and routing overhead are minimal
- Handler logic and I/O dominate
Focus optimization efforts accordingly.
Middleware and Performance
Middleware cost is linear with chain length.
Guidelines:
- Keep middleware short and single-purpose
- Avoid allocations inside middleware
- Avoid heavy logic in global middleware
- Push expensive checks to scoped middleware
Do not stack middleware “just in case”.
Each one runs on every request in its scope.
Allocation Awareness
Go performance often hinges on allocation behavior.
Common sources of unnecessary allocations:
- Repeated map creation
- Unbounded
fmt.Sprintf - Interface conversions
- JSON encoding of large structs
- Temporary slices in hot paths
Mitigation strategies:
- Reuse buffers where appropriate
- Prefer structured logging over string formatting
- Avoid premature generalization
- Use value types thoughtfully
Never sacrifice readability for micro-optimizations
unless profiling proves it necessary.
Context Usage and Performance
Plumego Context is lightweight by design.
However:
- Storing large objects in Context increases GC pressure
- Using Context as a cache increases allocation churn
Best practices:
- Store small, immutable metadata only
- Avoid putting domain entities in Context
- Treat Context as read-mostly
Context misuse is a common hidden cost.
Handler Design and Hot Paths
Handlers sit on hot paths.
Recommendations:
- Parse input once
- Validate early
- Fail fast
- Avoid deep call stacks in handlers
- Delegate heavy logic to usecases
Handlers should be predictable and thin.
JSON Serialization Costs
JSON is often the largest cost after I/O.
Consider:
- Reducing payload size
- Avoiding unnecessary fields
- Using streaming encoders for large responses
- Caching serialized representations when safe
Plumego does not impose serialization choices,
so you remain in full control.
Concurrency and Backpressure
High throughput without backpressure leads to collapse.
Key considerations:
- Limit concurrent outbound calls
- Use worker pools for expensive operations
- Apply timeouts everywhere
- Prefer bounded queues over unbounded goroutines
Concurrency is not free.
Plumego deliberately does not hide concurrency from you.
Performance and Multi-Service Systems
In multi-service setups:
- Network latency dominates
- Serialization costs multiply
- Tail latency compounds
Rules of thumb:
- Minimize synchronous call chains
- Avoid chatty APIs
- Batch when possible
- Fail fast on downstream issues
Framework-level optimizations cannot fix architectural latency.
When Custom Optimization Is Justified
Optimization is justified when:
- A measurable bottleneck exists
- The bottleneck affects user experience or cost
- The fix is localized
- The impact is understood
Optimization is not justified to:
- Match synthetic benchmarks
- Compete on microseconds
- Preempt hypothetical scale
Avoiding Performance Anti-Patterns
Premature Optimization
The fastest code to maintain is the code you did not complicate.
Hiding Performance Tricks
Hidden caches, implicit retries, and background goroutines
make performance unpredictable.
Framework-Level Over-Optimization
Optimizing Plumego internals rarely moves the needle
and often increases maintenance cost.
Performance as a Continuous Process
Performance is not a one-time task.
Recommended cadence:
- Measure regularly
- Re-evaluate assumptions
- Remove outdated optimizations
- Document performance decisions
Clarity must survive optimization.
Summary
In Plumego:
- Performance is explicit
- Bottlenecks are measurable
- Optimizations are intentional
- Clarity is preserved
- Architecture matters more than micro-tuning
Plumego gives you a transparent execution model —
use that transparency before reaching for cleverness.
Next
Two natural continuations from performance are:
→ Advanced / Background Processing
For work that should not block requests.
→ Advanced / API Versioning
For evolving interfaces without breaking clients.