Skip to main content

Engineering practices

How to Assess System Design Skills in a Senior Software Engineer Interview

Run a useful senior system design interview with a realistic CSV import exercise, practical follow-up questions, example answers, and an evidence-based scorecard.

Written by Aminul Islam Alvi12 min read

A candidate draws an API gateway, a queue, a cache, and six services. The boxes look familiar. The arrows make sense. Then you ask what happens if a worker crashes halfway through a job.

“The queue retries it.”

That might be the beginning of a good answer. It is not the end of one.

What has already been written? Can the same work run twice? What does the customer see while the job is recovering? Which failure would wake someone up at two in the morning?

Those questions reveal more about senior engineering judgement than the number of components on a whiteboard. A useful system design interview helps you see how someone makes decisions when requirements are incomplete and failures are ordinary.

Here is a practical way to run that interview. The example is a customer CSV import service for a SaaS product. It is small enough to discuss in an hour and rich enough to expose real design choices.

Decide what you are measuring

Before choosing a question, write down the work the person will actually own.

For a senior application engineer, I would usually assess six things: clarifying requirements, choosing boundaries, protecting data, handling failure, operating the system, and explaining trade-offs. A platform role may need more depth in infrastructure. A data role may need more depth in storage and processing. The interview should reflect that difference.

Do not quietly assess staff-level organisational strategy when the opening is for a senior engineer. Likewise, do not treat confidence with one cloud provider as proof that someone can design a reliable product workflow.

Define the expected evidence before meeting candidates. For example, “recognises that retries can repeat committed writes” is observable. “Has a senior mindset” is too vague to score consistently.

The US Office of Personnel Management's structured interview guidance describes using predetermined questions and common rating standards. You can apply that principle to a technical conversation without turning it into a rigid quiz. Keep the core problem, information, and main follow-ups consistent. Allow candidates to explain different valid designs.

Give the candidate a useful problem

Here is the prompt I would use:

We run a SaaS product where each company has its own customer records. An administrator needs to upload a CSV file containing up to 500,000 customers. Processing may take several minutes. The administrator should see progress and download a report of rejected rows. Retrying an upload must not create duplicate customers. Design the service and explain how it behaves when something fails.

Provide a short context sheet rather than making candidates guess the business:

DetailStarting assumption
TeamFour application engineers who also support production
Existing systemA web application, a relational database, and object storage
Import frequencyAbout 200 imports a day, with bursts during business hours
Customer identityA stable external customer ID, unique within a company
Update ruleAn import may update existing customer records
Error handlingValid rows may succeed even when other rows are rejected
Product expectationImports usually finish within 15 minutes; this is an initial target to test

These are fictional exercise assumptions, not production measurements. Share them when introducing the problem. Keep secondary details, such as retention and simultaneous imports, ready for clarification.

The stable customer ID matters. Without an agreed identity rule, “no duplicates” is an ambiguous requirement. Two rows with the same email address might represent one customer, two people sharing an address, or a correction. A candidate should not have to guess which interpretation your product uses.

Give candidates permission to use a familiar stack. You are evaluating the decisions behind a queue or transaction, not whether they remember a vendor's product names.

Make the hour predictable

Tell the candidate how the session will work. An interview is already an artificial setting; surprises add noise.

TimeFocus
0–5 minutesIntroductions, context, and the problem
5–15 minutesRequirements, assumptions, and rough sizing
15–30 minutesMain design and one complete data flow
30–45 minutesTwo prepared failure scenarios
45–55 minutesOperations, trade-offs, and a final design review
55–60 minutesCandidate questions

You will not investigate every subsystem. Choose the same two main failure scenarios for everyone. Keep a third for a follow-up session or additional time. Do not penalise a candidate for failing to cover topics you never gave them room to discuss.

If someone spends too long listing requirements, guide them: “We have enough to start. Please walk me through one upload.” If you provide that help, note it. Guidance is useful context for the score, not an automatic failure.

Listen to the first ten minutes

A strong beginning often sounds ordinary:

“Can a customer use the application before the import finishes?”

“Can two imports update the same customer at the same time?”

“Does cancelling an import undo successful rows, or stop the remaining work?”

These questions change the design. They uncover partial results, conflicting updates, and transaction boundaries.

Compare that with asking about the preferred message broker before understanding what must happen to the data. Tool questions can be useful later. At the beginning, they can hide the absence of a product model.

Rough sizing should also lead to a decision. Suppose every import were at the stated maximum. Two hundred imports would mean 100 million input rows a day, about 1,160 rows per second averaged across 24 hours. Most files may be much smaller, and the work will not arrive evenly.

The useful next question is about peaks and database work per row. A candidate who identifies expensive per-row lookups and proposes batch operations has connected the estimate to the design. Someone who announces a precise server count from the daily average has skipped several important assumptions.

You do not need mental arithmetic under pressure to get this signal. Let candidates use a calculator. You want to know what they choose to estimate and how they use the result.

Follow one import through the design

Ask the candidate to trace a file from the browser to the final report.

A reasonable starting design might work like this:

  1. An authenticated administrator creates an import job for their company.
  2. The service provides a restricted upload destination in object storage.
  3. After upload, the service verifies the object and makes the job available to workers.
  4. A worker reads the file in bounded batches, validates rows, and applies changes.
  5. The database records progress and the location of the error report.
  6. The browser polls a status endpoint until the job reaches a terminal state.

This is a reference path for discussion, not a hidden answer key. A database-backed job queue may be enough. A managed broker can also fit. Either choice needs a clear explanation of ownership and recovery.

Now slow down at the boundaries.

For the upload, how does the service prevent one company from processing another company's object? A strong answer keeps the company identity tied to the authenticated actor and the stored job. A company ID supplied by the browser is not enough.

For the worker, what fits inside one transaction? Holding a database transaction open for a 500,000-row file is a very different choice from committing batches. If batches commit independently, partial results become part of the product contract.

For progress, does “60% complete” mean bytes read, rows parsed, or rows committed? A candidate does not need a perfect percentage. They should recognise that misleading progress can become a support problem. Showing processed and rejected row counts may be more honest until the total is known.

For the completion report, what happens if the data commits but writing the report fails? The customer records and the report live in different systems. A good design either makes report generation recoverable from durable results or records enough state to resume it.

Notice what you are doing: examining one workflow deeply enough to find its promises. You do not need a diagram containing every possible infrastructure component.

Change one fact at a time

Use prepared changes to see whether the candidate can adapt their model.

A worker crashes after committing a batch

Ask: “The worker committed 1,000 rows, but crashed before acknowledging the job. What happens on the next attempt?”

Useful answers distinguish between retrying the import request and retrying individual work. An idempotency key on the HTTP request does not, by itself, protect the worker's database writes.

A candidate may propose a unique key on company and external customer ID, an upsert, and a checkpoint committed with each batch. Follow that answer one step further: does repeating the update overwrite a newer change made by a user or another import?

There are several defensible policies. The product might prevent overlapping imports per company, compare source versions, or explicitly accept last-write-wins updates. What matters is that the candidate notices the conflict and chooses a policy rather than assuming that an upsert makes every retry harmless.

One company submits 80 large files

Ask: “How do we keep other companies' small imports moving?”

Look for bounded concurrency, per-company limits, admission control, or scheduling that gives other companies a turn. Adding workers may help throughput but can also overload the same database.

Ask what the team would measure before changing capacity. Queue age, processing rate, database latency, and rejected work are more useful together than CPU alone.

The queue is unavailable after a job is saved

Keep this as the reserve scenario. The job exists in the database, but no worker receives it.

A candidate might suggest polling durable jobs or writing an outbox record in the same transaction as the job. The transactional outbox pattern addresses this database-and-message gap. The important follow-up is whether publishing can happen twice and how consumers handle that.

Naming the pattern is optional. Explaining the failure and a workable recovery path is the signal.

Score observable behaviour

Use a small scorecard while the conversation is still fresh. Here is an example for this role:

Area1: Important gaps2: Developing3: Meets the senior bar4: Particularly strong
RequirementsStarts building without clarifying outcomesAsks questions but misses key data rulesClarifies identity, partial success, and constraintsFinds conflicts between requirements and helps resolve them
BoundariesCannot trace the workflowPlausible components, unclear ownershipClear API, storage, and worker responsibilitiesSimplifies the design while preserving its guarantees
Data correctnessAssumes retries are harmlessSpots duplicates after substantial helpExplains atomic writes, uniqueness, and replayAlso handles conflicting updates and checkpoint recovery
Failure handlingRelies on restarting everythingCovers one failure in isolationHandles retries, timeouts, and partial completionConnects failure policy to user impact and recovery cost
OperationsOffers only generic loggingNames metrics without actionsDefines useful signals and support pathsUses those signals to explain capacity and incident decisions
Trade-offsTreats one stack as mandatoryLists alternatives without choosingChooses a workable design for the stated teamClearly explains what would justify changing it

Record evidence beside each score. “Discussed retries” is weak evidence. “Explained the crash between batch commit and acknowledgement, then tied the checkpoint to the same transaction” is useful evidence.

Use “not observed” when time or interviewer choices prevented assessment. Do not convert missing evidence into the lowest score.

Calibrate the rubric before using it for real decisions. Have interviewers score the same practice answer independently, compare differences, and refine vague criteria. The numbers are a shared language for discussion. They are not a scientific measurement of someone's future performance.

Compare two answers to the same question

Consider the worker crash scenario.

Answer A: “I would use Kafka because it guarantees message delivery. If a worker dies, another worker takes over. We can scale consumers horizontally.”

There may be useful knowledge here, but the answer has not explained repeated database writes. Ask: “The database commit succeeded before the crash. Please walk through the replay.” Give the candidate a chance to supply the missing reasoning.

Answer B: “I expect the batch to run again. I would commit its changes and checkpoint together. The next worker checks that checkpoint before applying the batch. Customer identity needs a database constraint too. I would initially allow only one active import per company, because otherwise an older retry could overwrite a newer import.”

The second answer gives you more evidence. It identifies a failure window, proposes a boundary, and makes a product trade-off explicit. It may still need work: the interviewer can ask how the checkpoint identifies a batch and how user edits interact with imports.

A polished first answer can improve after a prompt. A detailed second answer can fall apart under another scenario. Score the full conversation, including the amount of guidance needed and whether the candidate revised an assumption thoughtfully.

Keep the interview fair and useful

Avoid turning clarification into a guessing game. If a candidate asks about retention, give the prepared answer. Do not reward the person who happens to discover the interviewer’s private requirement.

Let candidates sketch, write, or explain verbally. Give reasonable pauses for thinking. Clear communication means that you can follow their decisions; it does not require constant speech, perfect English, or beautiful diagrams.

Keep optional technology depth separate from the core score. A candidate who understands work leases and acknowledgement may use a broker you have never deployed. Ask about its behaviour before dismissing the choice.

Also watch your own tendency to favour agreement. If you prefer a managed queue and the candidate chooses a database queue, ask about contention, scheduling, and scale. They may have a sensible answer for four engineers and 200 imports a day.

For broader hiring signals, I use a separate discussion about senior engineering ownership. One design exercise cannot tell you everything about collaboration, delivery history, mentoring, or code quality.

Turn the notes into a hiring decision

Have interviewers write their scores and evidence before the debrief. This reduces the chance that the most confident person sets everyone else's interpretation.

A useful debrief sounds like this:

The candidate met our bar on requirements, data correctness, and trade-offs. They caught the replay problem without prompting and chose a reasonable first implementation. We did not get enough evidence on production diagnosis. A follow-up should ask them to investigate an import backlog using a small set of logs and metrics.

That is more actionable than “strong technically, maybe not senior enough.”

When evidence is mixed, name the unresolved risk and choose a focused way to examine it. Do not repeat the same broad interview and hope that another impression will settle the question.

The interview has done its job when you can explain which decisions the candidate made, why those decisions fit the role, and where your confidence is limited. A crowded whiteboard is easy to remember. The reasoning behind a safe retry is much more useful when you are deciding who will own the system.

Senior engineersTechnical interviewsSystem designHiring