All jobs / Backend developer

Architecture interview questions

Architecture questions a Backend developer can be asked, from first job to senior. Open one to see the strongest answer and why it works.

  1. An interviewer says: “Design a URL shortener.” What do you do first?

    The strongest answer: Ask what it must do and at what scale — reads vs writes, expiry, custom aliases, analytics — and state the assumptions you will design against before drawing anything

    Why it works: Right. Requirements and numbers first; the boxes follow from them.

    • Clarify functional and non-functional requirements first.
    • State assumed scale in numbers.
    • Only then draw.
    • Check assumptions with the interviewer.
  2. What does a load balancer do, and what does it not do?

    The strongest answer: It spreads incoming requests across several identical servers and stops sending to ones that fail health checks; it does not make one slow server faster or fix a database bottleneck behind them

    Why it works: Right. Distribution and failover, nothing more.

    • Distributes requests across servers.
    • Removes unhealthy servers.
    • Not a cache, not capacity.
    • Bottlenecks behind it remain.
  3. What is the difference between scaling up and scaling out?

    The strongest answer: Up means a bigger machine — simple, but there is a ceiling and one box to lose; out means more machines behind a balancer, which needs the service to be stateless or to share state elsewhere

    Why it works: Right. Up is easy until the ceiling; out needs stateless services.

    • Up: bigger box, ceiling, single failure.
    • Out: more boxes, needs statelessness.
    • Choose by state and ceiling.
    • Neither is always right.
  4. Why do interviewers keep asking whether a service is stateless?

    The strongest answer: Because a stateless service keeps nothing between requests on its own box, so any instance can serve any request — that is what lets you add instances, replace a dead one and deploy without users noticing

    Why it works: Right. Statelessness is what makes scaling out and failover trivial.

    • Stateless: nothing kept between requests locally.
    • Any instance serves any request.
    • State moves to a shared store.
    • Enables scale-out and failover.
  5. When does adding a cache help, and when does it not?

    The strongest answer: It helps when the same data is read far more often than it changes and a slightly stale answer is acceptable; it does not help write-heavy paths, unique-per-request data, or when staleness is unacceptable

    Why it works: Right. Read-heavy, repeated, staleness-tolerant — otherwise it adds complexity for nothing.

    • Read-heavy and repeated.
    • Staleness must be acceptable.
    • Not for writes or unique reads.
    • Name what is cached and for how long.
  6. In a design, why do you say which columns are indexed?

    The strongest answer: Because the query pattern decides the index: a lookup by short code needs an index on that column or every read scans the table; each index also slows writes and takes space, so you index what you query, not everything

    Why it works: Right. Index the lookup paths; pay on writes.

    • Index what you look up by.
    • Each index costs writes and space.
    • Query pattern decides.
    • Say the key columns explicitly.
  7. What is a read replica for?

    The strongest answer: A copy of the database that receives writes from the primary and serves reads, so read traffic scales out and the primary is left for writes; reads from it can lag slightly behind the primary

    Why it works: Right. Reads scale out; expect replication lag.

    • Copies primary; serves reads.
    • Scales reads, not writes.
    • Lag exists.
    • Primary stays for writes.
  8. Why would you put a queue between two parts of a system?

    The strongest answer: To decouple them: the producer finishes fast and the consumer works at its own pace, spikes are absorbed, and a consumer being down does not lose the work — at the cost of the result arriving later

    Why it works: Right. Decoupling and absorbing spikes, paid for in latency.

    • Decouples producer and consumer.
    • Absorbs spikes.
    • Survives consumer outages.
    • Result becomes asynchronous.
  9. What is the difference between latency and throughput?

    The strongest answer: Latency is how long one request takes; throughput is how many the system handles per second — you can have high throughput with bad latency, and adding servers raises throughput without shortening one request

    Why it works: Right. One request's time versus requests per second.

    • Latency: time per request.
    • Throughput: requests per second.
    • They move independently.
    • Scaling out helps throughput.
  10. An interviewer asks for p99 latency. What does that mean and why ask for it?

    The strongest answer: The time under which 99% of requests finish — it shows the slow tail that averages hide, and the tail is what users on the worst path feel and what times out downstream

    Why it works: Right. Tails matter more than averages.

    • 99% of requests finish under it.
    • Exposes the tail.
    • Averages hide outliers.
    • Tail drives user experience and timeouts.
  11. How do you estimate storage for 100 million short URLs?

    The strongest answer: Pick a per-record size — say a few hundred bytes for the code, the long URL and metadata — multiply, and round: a few hundred bytes times 100 million is tens of gigabytes, so one database handles it and the interesting problem is reads, not storage

    Why it works: Right. Rough units, a multiplication, a conclusion.

    • Per-record size times count.
    • Round to a power of ten.
    • Draw a conclusion from it.
    • Say what the real constraint is.
  12. What does a CDN do for a web application?

    The strongest answer: It serves static files from servers near the user, so images, scripts and styles come from the edge with low latency and the origin only serves what changes

    Why it works: Right. Static content at the edge, origin for the rest.

    • Static files near the user.
    • Lower latency for assets.
    • Origin serves dynamic content.
    • Cache headers control it.
  13. Why would a class take its database client as a constructor parameter instead of creating one inside itself?

    The strongest answer: The class stops deciding where the dependency comes from, so it can be given a different implementation — a test double, another configuration — and the wiring lives in one visible place instead of every constructor

    Why it works: Right — testability is the visible benefit; the real one is that construction and configuration move to one place you can read.

    • Ask for dependencies; do not create them.
    • Wiring lives in one place.
    • Swap implementations freely.
    • Avoid hidden global instances.
  14. The interviewer asks: “Should this service be CQRS?” Strongest answer?

    The strongest answer: Not by default. I split read and write models when they actually diverge — different scale, different shape, or a team boundary — not because a blog post started with a command bus.

    Why it works: Exactly. CQRS is a response to pain (read models that crush the write schema, or independent scale). Starting there doubles the moving parts.

    • CQRS when reads and writes truly diverge.
    • Not the default for CRUD.
    • Don't conflate it with event sourcing.
    • A replica ≠ a read model.
  15. The interviewer asks: “Event-driven or request/response for “order placed → email + warehouse”?” Strongest answer?

    The strongest answer: If the caller doesn't need those side effects in the HTTP response, publish an OrderPlaced event (via outbox) and let consumers do email and warehouse. If checkout must confirm stock now, that's a request — maybe with a short saga, not a hope that a consumer ran.

    Why it works: Exactly. Events decouple facts that already happened. The user-facing “can I buy this?” is still a synchronous policy decision.

    • Sync for decisions the user waits on.
    • Events for facts that already committed.
    • Don't block HTTP on every consumer.
    • Don't hidden-RPC in the controller.
  16. The interviewer asks: “How do you change an event payload that old consumers still read?” Strongest answer?

    The strongest answer: Additive, compatible evolution: new optional fields, never reuse names, never change a field's meaning. A schema registry or contract test fails the producer if it breaks a consumer. Breaking changes get a new event type or version.

    Why it works: Exactly. Producers and consumers deploy independently. Compatibility is the product. That's why Avro/JSON Schema compatibility modes exist.

    • Evolve events additively.
    • Contract-test compatibility.
    • New meaning → new field or new type.
    • Don't rely on catch-and-ignore.
  17. The interviewer asks: “Billing keeps importing Order's entity. What's the design problem?” Strongest answer?

    The strongest answer: We've crossed a bounded context. Billing should depend on a published language — an API or event — not on Order's tables and types. I split the model and the ownership, not just the repo folders.

    Why it works: Exactly. DDD here is practical: independent evolution, independent deploys, a contract at the edge. Shared entities are a distributed monolith.

    • Contexts meet at contracts, not tables.
    • Don't share entities across domains.
    • A shared kernel is still coupling.
    • No drive-by SQL into another team's DB.
  18. The interviewer asks: “How do you isolate tenants in a multi-tenant backend?” Strongest answer?

    The strongest answer: Pick a model on purpose: row-level with a mandatory tenant predicate (and tests that fail closed), schema-per-tenant, or db-per-tenant for the ones that need it. I never “remember to add WHERE tenant_id” in each query by folklore.

    Why it works: Exactly. Isolation is a security property. ORM global filters, row-level security, or separate stores — plus tests that try to read another tenant and must fail.

    • Choose row / schema / database isolation.
    • Enforce in the data layer, not the UI.
    • Tests must fail closed on cross-tenant reads.
    • Cache keys include tenant.
  19. The interviewer asks: “A bad deploy took all regions with it. What architecture would have contained it?” Strongest answer?

    The strongest answer: Shrink blast radius: cells or shards with independent deploys, progressive delivery (one cell, then more), and a kill switch. One binary to the world is one failure domain.

    Why it works: Exactly. Cell-based / zonal deploys turn an outage into a slice. You still need the switch to stop the rollout.

    • Isolate deploys into cells.
    • Roll out progressively; keep a kill switch.
    • Replicas ≠ failure isolation.
    • Watch global shared stores — they couple cells.
  20. A team proposes ports and adapters for a service that reads a queue, writes to one database, and will never have a second client.

    Do you agree?

    The strongest answer: Not for its own sake — it pays when adapters change or the rules are complex; here I would keep the domain logic out of the framework and add ports when something genuinely needs a second adapter

    Why it works: Exactly — name what it buys and what it costs, then take the cheap half now and the rest when there is a reason.

    • Structure is a means, not a goal.
    • Keep the domain free of transport.
    • Add ports when a second adapter appears.
    • Name the cost, not only the benefit.
  21. The interviewer asks: “Two years of events, consumers you don't own. How do you evolve the schema?” Strongest answer?

    The strongest answer: Compatibility windows: additive fields, dual-publish old and new types if I break, a registry that blocks incompatible producers, and a documented retirement. I don't rewrite history in the log.

    Why it works: Exactly. You don't own the consumers; the log is an API. Dual-run and a registry are how platforms survive year three.

    • The log is a public API.
    • Additive or dual-publish; registry gates.
    • Don't rewrite history casually.
    • Schemaless isn't a strategy.
  22. The interviewer asks: “Auth, TLS, and WAF — in every service or at the gateway?” Strongest answer?

    The strongest answer: Both, with a split: the gateway handles TLS, edge rate limits, and coarse authn; each service still authorises its resources and never trusts the network alone. I don't make the mesh the only control or the app the only control.

    Why it works: Exactly. Defence in depth. Edge for the internet-shaped problems; service for IDOR and domain policy. Zero-trust internals in 2026 still assume a stolen sidecar.

    • Gateway: TLS, coarse authn, edge limits.
    • Service: resource authz, domain rules.
    • Don't trust “internal.”
    • Don't duplicate or delete the edge on a whim.