What Mid-Level Developers Get Wrong About System Design

by Eric Hanson, Backend Developer at Clean Systems Consulting

The Pattern Is Consistent

Sit in enough system design reviews and the mid-level developer pattern becomes recognizable. They understand the components — load balancers, databases, caches, queues. They can describe how each one works. But their designs tend toward one of two failure modes: they either over-complicate (reaching for Kafka and microservices for a problem a single service with a good schema would handle), or they under-specify (correct at the box-and-arrow level but silent on the details that determine whether the design actually works).

Neither failure is about lack of effort or intelligence. Both are about a mental model that hasn't yet shifted from "how do I build features" to "how do I design systems that hold up."

The Over-Complication Failure

The trigger is usually a genuine desire to demonstrate technical breadth. A mid-level developer asked to design a URL shortener produces a microservices architecture: a URL ingestion service, a redirect service, an analytics service, a cache invalidation service, all connected by Kafka topics. Each service has its own database.

This is not wrong in the sense that it wouldn't work. It's wrong in the sense that it's solving a problem that doesn't exist yet with machinery that requires significant operational complexity. A URL shortener at 10,000 redirects per day is a single PostgreSQL table and a service that reads from it, with a Redis cache in front of the hot rows. The microservices design is appropriate at 10M redirects per day with a team of 20 engineers. Presenting the latter for the former is a category error.

The question to train yourself to ask first: what is the actual scale requirement? What does "large" mean here, specifically? The answer should constrain the design, not inspire it.

The Under-Specification Failure

The opposite mode: a mid-level developer produces a clean, simple architecture diagram and stops there. Load balancer, service, database. Correct in outline. Missing everything that determines whether it works in production.

The specific gaps that appear most often:

No discussion of data modeling: The design says "store orders in a database." It doesn't address: what indexes does the orders table need? How will you query orders by customer, by date range, by status simultaneously? What happens to query performance when the table has 100M rows?

No discussion of failure modes: What happens when the database is slow? What happens when a third-party payment API is unreachable? The design shows the happy path. Production is the unhappy paths.

No discussion of consistency requirements: Two services both need to read and write to the user's account balance. The design doesn't say which operations need strong consistency, what the isolation level is, or how race conditions are handled.

Scale assumptions unstated: "This handles traffic" — what traffic? The design that works at 100 req/sec and the design that works at 100,000 req/sec look very different. If you don't state the assumption, you can't evaluate the design.

The Correct Mental Model

Good system design starts with requirements, not with components. Specifically:

  1. Functional requirements: What does the system do? Not how — what.
  2. Non-functional requirements: What are the performance, consistency, availability, and durability requirements? Stated as numbers: "99.9% availability," "p99 latency under 200ms," "no data loss on payment events."
  3. Scale estimates: How many users, how many requests per second, how much data? Order-of-magnitude estimates are sufficient. They determine which components are necessary.
  4. Bottlenecks and tradeoffs: Given the requirements, where are the likely bottlenecks? What tradeoffs are you making?

Most mid-level developers skip steps 2 and 3 and jump to step 4 — or worse, jump straight to drawing boxes.

The Specific Things to Practice

Ask "how many?" before drawing anything. Practice estimating: at 1M users with 10 active per second each making 3 API calls, what's my req/sec? What does my database read/write ratio look like? How much storage do I need per year?

Practice designing the data model before the service architecture. The data model is frequently the hardest part of system design and the one that's most expensive to change. Getting the schema right — the indexes, the relationships, the partitioning strategy — is more important than whether you have one service or five.

Practice stating failure modes explicitly. For every external dependency in your design: what happens when it's unavailable for 5 seconds? 5 minutes? What's the user experience in each case?

The Practical Takeaway

Before your next system design session, write down three things in order: the specific scale numbers you're designing for, the consistency requirement for the most critical data in the system, and what happens to user-facing operations if the database is unavailable for 60 seconds. If you can answer all three before opening a design tool, you're thinking like a systems engineer. If you can't, start there.

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

How to Say No to a Client Request Without Losing the Relationship

Saying no is a skill. Done poorly, it creates conflict. Done well, it builds respect and keeps the working relationship intact.

Read more

When the Client Forgets to Pay You (or Pretends They Did)

It’s awkward, frustrating, and more common than you think. Handling unpaid invoices gracefully can save relationships—and your sanity.

Read more

The Real Cost of a Senior Backend Developer — Full-Time vs Contractor vs Async Remote

The offer letter number is the smallest part of what a backend hire actually costs. Here's what the full comparison looks like across three models.

Read more

How to Design APIs That Survive Version Changes

APIs don’t break all at once. They slowly drift until something snaps. Good design isn’t about avoiding change — it’s about surviving it.

Read more