DEV Community

Amitabh
Amitabh

Posted on Originally published at prepd.tech Fully Autonomous

How to Review and Push Back on AI-Generated Code and System Designs

AI assistants now write a large share of first drafts: functions, tests, even whole architecture proposals. That changes what makes an engineer valuable. Producing code is cheap. Knowing when the AI's answer is wrong, and saying so clearly, is the skill teams and interviewers are looking for.

It shows up in two places:

  • AI-assisted interview rounds. You get a codebase and an assistant. Accepting its first suggestion without checking is one of the most common ways to fail, because the round is designed to see whether you review its output.
  • Everyday work. Design reviews and code reviews increasingly start from an AI draft. The engineer who can say "this won't hold under load, here's why" is the one whose judgement gets trusted.

This guide gives you a checklist for both, the words to use when you push back, and two worked examples.

Why AI output needs a reviewer

Assistants are good at producing something that looks right. They are weaker at the parts that need context they don't have:

  • Your real constraints. Traffic, budget, team size and existing systems are rarely in the prompt, so the answer is generic.
  • Edge cases. Empty inputs, boundaries, concurrent calls and failures are where generated code most often breaks.
  • Trade-offs. An assistant will happily recommend a queue, a cache and five microservices without saying what each one costs.
  • Confidence. Wrong answers come in the same confident tone as right ones, including calls to library functions that don't exist.

None of this means "don't use AI". It means the human in the loop is doing the senior part of the job.

Checklist: reviewing AI-generated code

Run through these before you accept a suggestion:

  1. Does it solve the stated problem? Re-read the task, then the code. Assistants often solve a nearby, easier problem.
  2. Boundaries. What happens at 0, 1, the maximum, an empty list, a null, a duplicate? Off-by-one errors are the classic miss.
  3. Concurrency. Is shared state read and written without a lock or atomic operation? Two requests at once is the test case it didn't consider.
  4. Failure paths. What if the network call times out, the file is missing or the database rejects the write? Is the error swallowed?
  5. Does every API exist? Check unfamiliar methods and parameters against the docs. Invented functions compile in the AI's head, not in yours.
  6. Security. String-built SQL, unescaped user input, secrets in code, missing permission checks.
  7. Tests. Run them. If the AI wrote the tests too, check they assert the right thing and would actually fail on the bug you're worried about.
  8. Can you explain it? If you can't walk an interviewer or a teammate through it line by line, you haven't reviewed it.

Checklist: reviewing an AI-suggested system design

When an assistant proposes an architecture, ask:

  1. Which requirement does each component serve? Any box you can't tie to a requirement is a cost with no benefit.
  2. Where are the numbers? A design without rough traffic and storage estimates can't justify sharding, caching or a queue. Do a 2-minute estimate and see what survives.
  3. What's the consistency story? Is it fine for this data to be stale for a few seconds (likes, feeds) or not (payments, inventory)? Generic designs rarely say.
  4. What's the single point of failure? Load balancer, primary database, a single queue broker, one region.
  5. What happens under the hot case? A celebrity post, a flash sale, a viral link. Averages hide hot keys.
  6. What does it cost to run and operate? Five services and a streaming platform for a few hundred writes a second is a maintenance bill, not a scalability win.
  7. What's the simplest version that works? Start there, then add complexity only where a number or a requirement forces it.

How to push back without sounding difficult

The goal is to be specific, not contrarian. Name the risk, give the reason, offer an alternative:

  • "This works for the happy path. What happens if two requests update the same counter at once? I'd use an atomic increment here."
  • "Before we add Kafka, let's check the numbers: about 50 writes a second fits in one database with room to spare. I'd start with a simple table and a background job."
  • "This cache makes reads fast, but the price can be stale for up to an hour. For checkout I'd read from the database and cache only the product page."
  • "I don't think retryWithBackoff exists in this client. Let me check the docs before we rely on it."

In an interview, saying this out loud is exactly the signal: you used the assistant, and you stayed in charge.

Worked example 1: a rate limiter the AI got almost right

You ask for a token bucket rate limiter. The assistant returns clean code that refills tokens on every request based on elapsed time. Review it with the checklist:

  • Boundaries: it refills before checking the cap, so after a long idle period the bucket briefly holds more tokens than its capacity and allows a burst. Clamp after refilling.
  • Concurrency: the read-modify-write of the token count isn't atomic, so two simultaneous requests can both take the last token. Use a lock, or an atomic operation in the shared store.
  • Units: elapsed time is in milliseconds, the refill rate is per second. A factor of 1,000 hides in one line.

Three real bugs in code that looked finished. That's the review an interviewer wants to watch.

Worked example 2: an over-built design

Prompt: "Design the backend for a small team's internal polling app." The assistant proposes microservices for users, polls and votes, Kafka between them, Redis, and a NoSQL store.

Push back with numbers: a few hundred users, a few thousand votes a day, which is well under one write a second. One service and one relational database handle that easily, and a unique constraint on (poll, user) prevents double voting more reliably than any of the proposed parts. Keep the design simple and say what would make you add each component later (for example, a cache only if read latency becomes a problem).

How to practise

  1. Build the scaling intuition. Know what each common step fixes and what it breaks: load balancer, read replicas, cache. That's what lets you spot an over-built or under-built design quickly.
  2. Practise reviewing, not just writing. Take generated code and hunt for the bugs on purpose: boundaries, concurrency, units, failure paths.
  3. Say your reasoning out loud. Pushing back is a communication skill as much as a technical one.

Practise it

Originally published at prepd.tech. Disclosure: I'm building Prepd.

Top comments (0)