Your System Is Only as Fast as Its Slowest Part

by Eric Hanson, Backend Developer at Clean Systems Consulting

The Optimization That Didn't Help

Your application API endpoint takes 1,200ms to respond. Your team spends a week optimizing the in-memory computation that runs after the database query — and cuts it from 50ms to 12ms. The endpoint now takes 1,162ms. Users notice nothing. The sprint was wasted.

This is not a hypothetical. It is a pattern that repeats across engineering teams with reliable frequency. Engineers optimize the parts of the system they understand and control — their own code — while the actual bottleneck sits in a database, a network call, or an external dependency that nobody wants to touch.

Eliyahu Goldratt's Theory of Constraints, originally formulated for manufacturing, applies directly to software systems: improving any part of the system that is not the bottleneck does not improve the system's overall throughput. The only leverage is at the constraint.

Finding the Constraint Before Touching Anything

The precondition for useful performance work is knowing where time actually goes. This sounds obvious and is frequently skipped. Engineers look at slow endpoints and guess — usually guessing their own code is the culprit because their own code is what they know. The bottleneck is almost always somewhere else.

Profile first. Specifically:

Distributed tracing at the service boundary level. Tools like Jaeger, Zipkin, or Honeycomb (or the APM built into your infrastructure — Datadog APM, AWS X-Ray) will show you where wall-clock time is spent across service calls. If your service spends 900ms of a 1,200ms request waiting for a downstream service, that is your bottleneck. No amount of optimization in your service touches those 900ms.

Database query profiling. In PostgreSQL, EXPLAIN ANALYZE on your slowest queries. In MySQL, the slow query log with long_query_time set to a threshold you care about. In most cases, a missing index is responsible for at least one slow query. A query doing a full table scan on a 10M row table will dominate your response time regardless of how fast the surrounding Java is.

Thread and connection pool metrics. A service that responds slowly under load may be spending time waiting for a database connection because the pool is exhausted, not because the query is slow. These look the same from the outside and require different fixes.

The Hierarchy of Common Bottlenecks

In most backend systems, ordered by how often they are actually the binding constraint:

  1. N+1 query patterns — the most common database bottleneck. Loading a list of 100 orders and then querying the database for each order's items individually. 100 + 1 = 101 queries instead of 2. At 5ms per query, this is 500ms of unnecessary database round trips.
-- N+1: one query per order item
SELECT * FROM orders WHERE customer_id = ?;
-- Then for each order:
SELECT * FROM order_items WHERE order_id = ?;

-- One query: JOIN or subquery
SELECT o.*, oi.*
FROM orders o
JOIN order_items oi ON oi.order_id = o.id
WHERE o.customer_id = ?;
  1. Missing indexes on columns used in WHERE clauses, JOIN conditions, or ORDER BY clauses on large tables.

  2. Synchronous calls to slow external dependencies — payment gateways, identity providers, third-party APIs. If these are in the critical path and slow, the solution is async processing or aggressive caching, not optimizing your own code.

  3. Connection pool exhaustion under load — usually addressed by right-sizing the pool and ensuring connections are released promptly (connection leak bugs are common culprits here).

  4. Serialization/deserialization overhead at scale — JSON parsing of large payloads, repeated object mapping. Relevant at high throughput (10,000+ rps), largely irrelevant below that.

  5. Your application logic — almost never the bottleneck in typical CRUD services, but sometimes relevant for compute-heavy workloads (report generation, document processing, ML inference).

The Mistake of Caching Without Understanding the Bottleneck

Caching is frequently reached for as the first performance solution. This works when the bottleneck is repeated computation or repeated fetching of data that doesn't change often. It does not help when:

  • The query is slow because of a missing index — caching hides the problem but doesn't fix it
  • The data changes frequently and the cache hit rate is low
  • The expensive operation is a write, not a read

Adding a Redis cache layer without first establishing whether cache hit rates will be meaningful is guesswork. Measure the bottleneck, then choose the solution.

The Practical Takeaway

Before your team starts any performance optimization work, mandate the following: add tracing spans (OpenTelemetry is the standard here) and capture a flame graph or waterfall trace for the slow operation. Identify the single step that consumes the most wall-clock time. Optimize that step, and only that step, first. Measure the result. Then repeat.

That process — measure, identify the constraint, fix the constraint, measure again — is the only performance work that reliably improves systems.

Scale Your Backend - Need an Experienced Backend Developer?

We provide backend engineers who join your team as contractors to help build, improve, and scale your backend systems.

We focus on clean backend design, clear documentation, and systems that remain reliable as products grow. Our goal is to strengthen your team and deliver backend systems that are easy to operate and maintain.

We work from our own development environments and support teams across US, EU, and APAC timezones. Our workflow emphasizes documentation and asynchronous collaboration to keep development efficient and focused.

  • Production Backend Experience. Experience building and maintaining backend systems, APIs, and databases used in production.
  • Scalable Architecture. Design backend systems that stay reliable as your product and traffic grow.
  • Contractor Friendly. Flexible engagement for short projects, long-term support, or extra help during releases.
  • Focus on Backend Reliability. Improve API performance, database stability, and overall backend reliability.
  • Documentation-Driven Development. Development guided by clear documentation so teams stay aligned and work efficiently.
  • Domain-Driven Design. Design backend systems around real business processes and product needs.

Tell us about your project

Our offices

  • Copenhagen
    1 Carlsberg Gate
    1260, København, Denmark
  • Magelang
    12 Jalan Bligo
    56485, Magelang, Indonesia

More articles

Spotify and Klarna Set the Bar. Every Other Stockholm Startup Fights for the Same Backend Talent

Your backend candidate loved the interview. Then Spotify called. You never heard from her again.

Read more

Why Barcelona Tech Startups Are Structuring Backend Work Around Contractors, Not Full-Time Hires

Some Barcelona startups have stopped treating every backend need as a headcount decision. The way they're structured explains why they keep shipping.

Read more

Your API Is Slower Than It Needs to Be and Pagination Is Probably Why

Unbounded list endpoints are one of the most common performance problems in production APIs — and one of the most preventable.

Read more

The Contractor Who Treats Every Project Like It Is Their Own Business Always Stands Out

The difference between a contractor who is easy to replace and one who becomes indispensable is not technical depth — it is the degree to which they genuinely care about the outcome.

Read more