DEV Community

Sergey Dobrov
Sergey Dobrov

Posted on

The Best Engineers Can Move Between Abstraction Layers

One pattern I’ve noticed over the years: the strongest engineers can move between abstraction layers almost effortlessly.

They write high-level code comfortably — but when something behaves strangely, they instinctively descend a few layers, reason about what’s happening underneath, and come back with a fix.

Here’s a simple thought experiment.

Ask someone why Python code using dense numeric arrays is much faster than similar logic written with regular Python objects.

A surface-level answer is:

“Because NumPy is written in C.”

A deeper answer mentions:

  • contiguous memory
  • cache locality
  • pointer indirection
  • object metadata overhead
  • how CPUs actually operate on memory

That explanation travels from Python syntax down to memory layout and hardware behavior — and back.

That ability to move across layers isn’t academic. It shows up in very ordinary work.

A Very Ordinary API Problem

Recently I was integrating with an external REST API that was painfully slow.

It returned paginated results and also reported the total number of matching records. The task was straightforward: fetch everything.

The original implementation used broad filters over the entire time range and fetched page by page with large page sizes.

At the HTTP layer, that approach makes sense:

  • Fewer requests
  • Larger pages
  • Simpler control flow
  • “Minimize round trips”

It feels efficient. But performance was terrible.

Instead of tweaking page size or adding concurrency, I asked a different question:

— Why is the API returning total count?

— That likely means a COUNT(*) somewhere. And pagination with LIMIT … OFFSET … usually means something else:

To serve page N, the database must scan and discard the previous N × page_size rows.

So with broad filters over a large time range, each successive page becomes more expensive than the previous one.

At the REST layer, everything looked clean.

Underneath, it was probably:

REST
→ controller
→ SQL with COUNT(*)
LIMIT/OFFSET
→ large scans and discarded rows

So instead of fetching everything broadly, I changed the access pattern.

Fetch day by day:

  • Smaller slices.
  • Better index selectivity.
  • Much smaller offsets.
  • Less discarded work.

Result: roughly a 10× speedup.

  • No access to their database.
  • No vendor escalation.
  • No architectural rewrite.

Just switching layers mentally, adjusting the shape of the query, and moving back up.

Why This Matters

Most of our daily work lives at high levels of abstraction: frameworks, APIs, cloud services.

And that’s good — that’s where productivity lives.

But performance issues, strange behavior, and cost explosions rarely originate at the same layer where they surface.

The engineers who consistently deliver under pressure are usually the ones who can descend a few layers, reason about what’s actually happening, and then come back with a pragmatic fix.

Not because they love low-level code.

But because they’re not confined to a single abstraction.

And this becomes even more important as more code is generated for us and more infrastructure is abstracted away. When AI writes the boilerplate and platforms hide the machinery, the differentiator isn’t how quickly you can produce code — it’s how well you understand what happens underneath it.

That ability to move across layers becomes rarer.

And that skill compounds.

Top comments (0)