Many services, one reliable system
Interviewers look for pragmatic choices (start with a monolith), clear communication patterns, consistency through sagas and outboxes, and resilience through timeouts, retries and circuit breakers.
- ArchitectureMonolith, modular monolith and microservices.
- CommunicationREST, gRPC, GraphQL, gateways and events.
- ReliabilitySagas, outbox, circuit breakers and tracing.
Most product companies run some form of service-based architecture, so interviews ask how services talk to each other, how you keep data consistent across them, and how you stop one failing service from taking down the rest.
1. Monolith vs microservices — when does each make sense?
A monolith is one deployable application: simple to build, test and deploy, and the right start for most products. Microservices split the system into independently deployable services owned by separate teams, scaling and failing independently — at the cost of network calls, distributed data and much more operational complexity. Split when team size or very different scaling needs justify it; a well-structured “modular monolith” is often the best middle ground.
2. REST vs gRPC vs GraphQL?
REST (HTTP + JSON) is simple, cacheable and universal — the default for public APIs. gRPC (HTTP/2 + Protocol Buffers) is fast and strongly typed with streaming — good for internal service-to-service calls. GraphQL lets clients ask for exactly the fields they need in one request — good for complex front ends with many views, but harder to cache and secure against expensive queries.
3. What does an API gateway do?
It is the single entry point for clients: routing requests to services, authentication, rate limiting, request/response transformation, aggregation of several service calls, TLS termination and logging. It keeps cross-cutting concerns out of each service. The backend-for-frontend pattern adds one gateway per client type (web, mobile).
4. Synchronous vs asynchronous communication?
Synchronous calls (HTTP, gRPC) are simple but couple availability: if the payment service is down, checkout fails. Asynchronous messaging (Kafka, RabbitMQ) decouples services in time — the order service publishes “OrderPlaced” and others react when ready — improving resilience and scalability, with eventual consistency as the trade-off.
5. How do you keep data consistent across services without distributed transactions?
Each service owns its database, so use the saga pattern: a sequence of local transactions, each publishing an event that triggers the next, with compensating actions to undo earlier steps on failure (refund payment, release inventory). Sagas can be choreographed (services react to events) or orchestrated (a coordinator directs them).
Order Service: create order (PENDING) → publish OrderCreated
Payment Service: charge card → publish PaymentSucceeded | PaymentFailed
Inventory Service: reserve stock → publish StockReserved | OutOfStock
Order Service: confirm order, or run compensations:
PaymentFailed → cancel order
OutOfStock → refund payment, cancel order6. What is the transactional outbox pattern?
Writing to your database and publishing an event are two separate systems — one can succeed while the other fails. The outbox pattern writes the event into an outbox table in the same local transaction as the business change; a separate relay reads the outbox and publishes to the message broker, retrying until it succeeds. Consumers must be idempotent.
7. What are circuit breakers, timeouts and retries?
Every remote call needs a timeout. Retries with exponential back-off and jitter handle brief failures (only for idempotent operations). A circuit breaker stops calling a failing service after repeated errors, fails fast for a while, then lets a few test requests through — preventing cascading failures. Add bulkheads (separate pools) and fallbacks such as cached data.
8. How do you observe a system made of many services?
The three pillars: structured logs with a shared request/trace id, metrics (latency, traffic, errors, saturation) with dashboards and alerts, and distributed tracing (OpenTelemetry) that shows one request's path and timing across services. Add health checks and SLOs that define “good enough”.
Remember
Key points
- Database per service
Share data through APIs and events.
- Sagas, not 2PC
Local transactions plus compensations.
- Timeouts everywhere
Then retries and circuit breakers.
- Trace ids in every log
Follow one request across services.
Interview drill
Follow-up questions
What the interviewer asks after your first answer. Turn on practice mode, answer each one aloud, then reveal.
-
1 What is service discovery? Basic
How services find each other's current addresses — via a registry (Consul, Eureka) or platform DNS (Kubernetes services).
-
2 What is a service mesh? Advanced
An infrastructure layer of sidecar proxies (Istio, Linkerd) that handles retries, timeouts, mTLS and telemetry between services without changing application code.
-
3 How do you version a public API? Intermediate
Version in the path or a header, make additive changes backward-compatible, deprecate with notice and monitor usage before removing old versions.
-
4 What is the strangler fig pattern? Intermediate
Migrating a legacy system gradually: route new or rewritten features to new services behind a facade until the old system can be retired.
-
5 Choreography vs orchestration in sagas? Advanced
Choreography: services react to each other's events (simple, but the flow is implicit). Orchestration: a coordinator tells each service what to do (explicit and easier to monitor, but a central component).
-
6 How do you avoid a distributed monolith? Advanced
Draw service boundaries around business capabilities, avoid shared databases and chatty synchronous chains, and let services deploy independently.