Why I stopped optimizing things that didn't matter
Web
A hard lesson in system performance: optimizing a component in isolation is a trap. Why I learned to ignore micro-optimizations and focus on the entire request path.
I can still picture the dashboard. We’d spent a week fine-tuning a prompt chain for a new agentic system, shaving nearly 400 milliseconds off its response time. The token count was down, the logic was tighter, and the model inference was visibly quicker. We felt that familiar surge of pride that comes from polishing a complex component until it shines. And yet, the user-facing latency was still stubbornly high.
Our beautiful optimization didn't matter at all.

The Modern Trap: Optimizing the Agent, Ignoring the Pipeline
It’s deeply satisfying to optimize a self-contained puzzle. An LLM agent, a complex algorithm, a single function—these are tangible problems with measurable outcomes right in front of us. This is the comfort zone for builders: a local problem we can solve with pure logic and cleverness. But it's also a dangerous trap, because while we're polishing a small, elegant gear, we’re ignoring the rusty, high-latency chain that drives the whole machine.
After our failed optimization, a full end-to-end trace told a humbling story. Our finely-tuned agent was a small fraction of the total time. The real culprit was the Retrieval-Augmented Generation (RAG) pipeline feeding it context. It was making three sequential, blocking calls to a vector database, followed by another network hop to a document summarization service. The agent was spending nearly four seconds just waiting for its inputs. Our 400-millisecond improvement was trying to bail out the ocean with a teaspoon.

The Ghost of Amdahl's Law
This experience was a modern replay of a very old lesson. Decades ago, computer scientist Gene Amdahl formulated what became Amdahl's Law, a principle that quantifies the speedup you can get by improving just one part of a system. The takeaway is brutal: if a component only accounts for 10% of the total time, even making it infinitely fast will only improve the whole system by 10%. My agent was that 10% component.
It’s the same wisdom behind Donald Knuth’s famous warning in his 1974 paper, "Structured Programming with go to Statements," that "premature optimization is the root of all evil." We often misinterpret this to mean "never optimize." What Knuth argued for was optimizing with knowledge. Don't guess. Find the actual 90% problem before you touch the 10% that feels more interesting.
Where Latency Hides in Modern Systems
In the composite systems we build today—fusing software, data, and AI—the bottleneck has almost entirely moved to the boundaries. It’s not in the CPU-bound loops; it’s in the I/O. It’s in the seams between components.
In an agentic workflow, the biggest offenders are rarely the model's "thinking" time. The latency hides in:
- Network Round Trips: Every call to a vector database, an external API, or another microservice adds tens or hundreds of milliseconds. Chains of these calls add up to seconds.
- Data Serialization: Moving large context windows or complex JSON payloads between services involves parsing and serialization costs that are often invisible but significant.
- "Cold Starts": Serverless functions or container-based services that need to spin up on demand can introduce massive, unpredictable latency spikes.
- Disk I/O: The "boring" part of reading from object storage or a traditional database is frequently the slowest step in any data-intensive pipeline.
The system doesn’t care how clever your agent is. It only feels the total time spent waiting for all these steps to complete.
From Micro-Benchmarks to System-Level Traces
The only antidote is to measure the entire, end-to-end request lifecycle. The flame graph from our OpenTelemetry trace was the tool that finally exposed the truth. Instead of generic lists of tools, my rule is simple: use a distributed tracing system that can follow a single request as it hops from the first API call, through the orchestrator, to the data stores, into the agent, and back out again.
Pioneers of this discipline, like Brendan Gregg, have built a career on making these system-wide bottlenecks visible. The goal is to find the longest bar in the chart. That’s it. You apply your craftsmanship there, on the biggest source of delay, not the most intellectually satisfying one.
But Sometimes, the Microseconds Matter
To be intellectually honest, this principle isn't universal. There are domains where micro-optimization is the entire game. If you're writing code for a game engine's rendering loop, a high-frequency trading algorithm, or the core of a widely-used data processing library like Arrow or pandas, every nanosecond counts. In those contexts, the component *is* the system, and its performance defines the product.
But for most of us building enterprise systems, our work is primarily about plumbing—connecting powerful components across network boundaries. Our job is architecture, and the highest leverage is in the layout of the pipes, not the polish of the faucets.
Architecting for the Whole Path
This mindset fundamentally changed how I approach architecture. I stopped asking "how can I make this agent faster?" and started asking "where will this system spend its time waiting?" It pushes me toward patterns that reduce round trips, like batching API calls or using more intelligent data caching. It favors a simple, "boring" design that minimizes I/O over a complex, clever one that optimizes a single component.
Before you dive in to refactor that next function or fine-tune that prompt, stop. Zoom out. Find a way to measure the whole system, from the user's first click to the final token. The real bottleneck is waiting for you, and it’s almost never where you think it is.