This interview guide is for educational and informational purposes only. It is designed to help readers prepare, but it does not guarantee any interview result, hiring decision, offer, or outcome. Interview questions, hiring criteria, and preferred answers can vary by employer, interviewer, industry, location, and time. The examples and explanations reflect the authors' research and judgment, are provided without warranties of any kind, and should not be treated as the only correct approach. Diagrams are simplified illustrations intended to highlight the main components and their interactions; actual systems and implementations may be more complex. Alternative approaches may be equally valid or better suited to a particular question, context, or interviewer. To the fullest extent permitted by applicable law, the author, contributors, and publisher are not liable for decisions made, actions taken, or losses incurred based on this guide.
Identity, Image, and Privacy Notice
To respect individual privacy, some names, profile photographs, avatars, biographical details, and other identifying information displayed in this guide may be replaced with pseudonyms, licensed stock images, illustrative avatars, composite images, or representative descriptions. Unless a person is expressly identified as an actual contributor, a displayed name, image, or profile should not be understood as depicting or identifying a specific candidate, interviewer, employee, or other real individual. These representations are provided for editorial and illustrative purposes only and do not imply endorsement, employment, participation, or affiliation with this guide or any company mentioned in it. Any resemblance to an actual person is coincidental.
Company Notice
This guide is an independent educational resource and is not affiliated with, endorsed by, sponsored by, or approved by the company named in this guide. Company names are used only to identify interview experiences commonly reported by candidates. Interview practices can change without notice, and inclusion of company-specific content does not mean these questions are official, complete, or guaranteed to be asked. To the fullest extent permitted by law, the author, contributors, and publisher are not responsible for outcomes related to use of this material.
Questions or comments?
Contact us for general questions, or share feedback, technical corrections, and comments with the community.
21. How would you design a deployment system?System DesignMediumMicrosoft
i Question Details
Design a deployment system that can roll out software safely, detect failures, support regional outages, and keep quality high across releases. Cover rollout strategy, monitoring, rollback triggers, and validation gates.
Short Interview Answer (30-60 seconds)
At a high level, the goal is to release new Java versions safely without exposing every user to a bad release. The main challenge is finding problems before too much production traffic reaches the new version. I would explain the design in three parts: build and validation, progressive rollout, and monitoring with rollback. We reuse one release artifact, validate it in pre-production, then shift traffic gradually from the old version to the new version across regions. The trade-off is slower releases for much better safety.
Detailed Explanation
The goal is to move a new software version into production without putting every user at risk at once. A release can pass normal build tests and still fail under real production traffic. The system therefore checks the release several times, gives the new version only a small amount of traffic first, and watches its health closely. If the release becomes unhealthy, the rollout can pause or move traffic back to the old version. The diagram organizes this into building one release, validating it, rolling it out gradually across regions, and using monitoring to decide whether to continue.
Useful Questions to Ask the Interviewer
How quickly should an unhealthy release be paused or rolled back?
Should every production release require manual approval, or can healthy releases continue automatically?
How much spare capacity should healthy regions keep for a regional outage?
How to Explain It in an Interview
1. Build one release artifact
I would start by creating one tested release that stays unchanged across environments. A Developer / CI Trigger starts the Build + Test Pipeline. The pipeline compiles the application, runs unit tests, performs static analysis, runs security checks, and packages the release. The result is stored in the Artifact Repository as the release artifact. The important point is that this same artifact is reused later. We do not rebuild a different application package for each environment.
2. Control the deployment from one place
Next, a deployment request goes to the Deployment Control Plane. The Deployment API accepts the request and its parameters. RBAC / Approvals controls which people may deploy and supports manual approvals. The Rollout Controller manages progressive rollout and traffic changes. The Validation Gate Runner decides whether required checks have passed. Release Metadata / Audit Log records releases, decisions, events, and the audit trail. This gives the rollout one place to manage state and decisions.
3. Validate before production
The control plane first deploys the release to Pre-Prod Validation. Smoke Tests check that the application starts and passes basic health checks. Integration Verification checks important integrations and dependencies. Config Checks verify configuration, secrets, feature flags, and policies. Synthetic Tests run planned end-to-end user actions. These checks act as validation gates. The release should not move into the wider production rollout until those checks pass.
4. Roll out gradually across regions
Production begins with Region A – Canary. Its Traffic Router sends 1% of traffic to Java Service v1.4.7 and 99% to Java Service v1.4.6. The Java service replicas are separate JVM processes, so their heap memory is not shared. If the new version stays healthy, traffic moves through 1%, 10%, 50%, and finally 100%. Region A then runs the new version fully. After that, the Rollout Controller expands the same release to Region B and then Region C. This avoids changing every region at once.
5. Monitor health and recover safely
Observability collects Metrics, Logs, Traces, and Health Checks. The Automated Health Analyzer uses this information to evaluate health rules, including SLOs and SLIs, which are measurable service health targets and signals. It sends a pass or fail decision back to the Deployment Control Plane. High errors, high latency, failed health probes, synthetic test failures, or capacity instability can trigger a pause or rollback. Operator Alerts notify the on-call team. During a regional outage, the system stops further rollout, drains the unhealthy region, reroutes traffic to healthy regions, and can roll back only the affected region. The main trade-off is slower deployment in exchange for much smaller failure impact.
Engineering Considerations / Design Trade-offs
The benefit is that a bad release does not reach everyone at once. Small canary steps give the system time to find problems before traffic grows. Reusing the same release artifact also keeps every environment closer to what was tested. The downside is that deployment takes longer because each stage must be checked before the next one starts. The Deployment Control Plane, health analysis, audit records, and regional traffic changes also add operational complexity. Regional recovery is safer, but healthy regions need enough spare capacity to accept redirected traffic. We accept this extra complexity because it greatly reduces the number of users affected by a bad release.
Why Interviewers Ask This
Interviewers ask this question to see whether you can make releases safe, not just fast. They want to know if you can separate build validation from production rollout, use canary traffic, monitor real health signals, and recover when something fails. They also want to see whether you understand regional outages, Java JVM process boundaries, access control, auditability, and the trade-off between deployment speed and production safety.
Interviewer may ask next
What would you do if the new release starts failing after Region A reaches 50% traffic?
I would stop the rollout and keep the problem inside Region A. The Observability data would show the unhealthy behavior through Metrics, Logs, Traces, Health Checks, or failed Synthetic Tests. The Automated Health Analyzer would return a failing health decision to the Deployment Control Plane. The Rollout Controller would stop increasing traffic and send a pause or rollback command for Region A.
The Traffic Router would move traffic away from Java Service v1.4.7 and back toward Java Service v1.4.6. Region B and Region C would not receive the new release because the progressive rollout has not reached them yet. Release Metadata / Audit Log would record the failure and recovery decision. Operator Alerts would also notify the on-call team.
This keeps the failure limited to one rollout stage. The downside is that some Region A users may see errors before monitoring detects the problem and the traffic shift completes.
What would happen if Region B becomes unavailable while Region A is already running the new version?
I would stop further rollout and handle Region B as a regional outage. The Rollout Controller should not continue expanding the release while that region is unhealthy. Traffic would be drained from Region B and rerouted toward healthy regions. Region A can keep running Java Service v1.4.7 if its own health signals remain good.
Observability would continue collecting Metrics, Logs, Traces, and Health Checks. The Automated Health Analyzer would keep sending health decisions to the Deployment Control Plane. If the new release contributed to the Region B failure, the system could roll back Region B locally instead of rolling back every healthy region. Operator Alerts would notify the on-call team, and Release Metadata / Audit Log would record the actions.
The benefit is that one regional problem does not automatically become a global rollback. The downside is that the remaining healthy regions need enough capacity to handle redirected traffic safely.
22. How would you design a distributed key-value store like Redis?System DesignHardMicrosoft
i Question Details
Design a distributed key-value store like Redis and explain sharding, replication, consistency, availability, failover, and recovery. Include how you would handle reads, writes, data placement, and trade-offs between durability and latency.
Short Interview Answer (30-60 seconds)
At a high level, the goal is to store key-value data across many machines while keeping reads and writes fast. The main challenge is balancing speed, durability, consistency, and availability when machines fail. I would explain the design through data placement, the write path, the two read paths, and failure recovery. A Java KV Router finds the correct shard using cluster metadata. Each shard has a Primary and Replicas. The main trade-off is stronger durability and consistency versus lower latency.
Detailed Explanation
The goal is to store a very large set of keys and return their values quickly. One machine will eventually become too small, so the data must be spread across several machines. We also need backup copies because machines can fail. Some reads must return the newest value, while other reads can accept a slightly older value for better scale. I would organize the solution around where each key is stored, how writes and reads move through the system, and how the system keeps working and recovers after failures.
Useful Questions to Ask the Interviewer
Do all reads need the newest value, or can some reads be slightly stale?
How much durability must a write have before we return an ACK?
Should Replica reads be used for normal read scaling?
How much write interruption is acceptable during failover?
How to Explain It in an Interview
1. Place each key on the correct shard
I would start by explaining that the data is split across shards because one machine cannot hold everything forever. The Java 21/25 KV Router Service receives requests after Access Control applies ACL/Auth, validation, and rate limiting.
The router uses the Cluster Metadata / Shard Map to find the correct shard. The diagram uses hash(key) -> slot / vnode -> shard. A hash turns the key into a placement value, and that value maps to one shard. When data is rebalanced, only the affected ranges need to move.
The router runs as replicated JVM processes. Separate JVMs do not share heap memory. Their routing state comes from the cluster metadata.
2. Follow the write path
For SET or DEL, the Java KV Router sends the request to the Primary that owns the shard. The Primary keeps the active value in memory. It also has an append-only log and snapshots for durability and recovery.
The exact ACK point is a trade-off. A faster policy can acknowledge after the in-memory update and local append-only log. A stronger policy can wait for fsync or Replica confirmation before returning the ACK.
The Primary sends updates to its Replicas using async replication, which means the copying happens without making every normal request wait for all Replicas.
3. Choose the correct read path
For a GET that needs the strong or latest value, the router sends the request to the Primary. The Primary returns the value through the router to the Client Applications.
For read scaling, the router can send a GET to a Replica. This spreads read work across more machines. The Replica may be slightly behind the Primary, so its returned value may be stale.
This gives the caller a clear choice. Primary reads give stronger consistency. Replica reads give more read capacity but may return older data.
4. Handle failures and recovery
The Failure Detector + Failover Controller watches node health. If a Primary fails, it promotes a healthy Replica and switches that shard to a new Primary. The Cluster Metadata / Shard Map must then reflect the new Primary so routers can send later requests correctly.
Only the affected shard should have a brief write interruption during this failover. Other healthy shards can continue serving their own keys.
When a failed node returns, it loads its snapshot, replays its append-only log, catches up from the current Primary, and rejoins as a Replica.
5. Operate and monitor the system
Observability & Operations collects metrics, logs, traces, and alerts from the router and cluster. These signals help detect slow requests, errors, unhealthy nodes, and replication problems.
The main trade-off is durability versus latency. Waiting for more storage or Replica confirmation protects acknowledged writes better, but every write takes longer. Replica reads improve scale, but they can return slightly older values.
Engineering Considerations / Design Trade-offs
The benefit is that sharding lets the system grow by spreading keys across several machines. Replicas improve availability and can also serve extra reads. The downside is that Replica reads may return an older value because updates are copied in the background. Failover keeps a shard working after its Primary fails, but writes to that shard may stop briefly during the switch. Durability also costs time. Returning an ACK after memory and the local append-only log is faster. Waiting for fsync or Replica confirmation protects the write more strongly, but it increases write latency.
Why Interviewers Ask This
Interviewers use this question to see whether you can break a storage problem into clear flows. They want to know if you understand sharding, Primary and Replica roles, data placement, read choices, failure handling, and recovery. They also want to see whether you can explain trade-offs clearly. A strong answer shows good judgment about when to favor lower latency, stronger durability, better read scale, or stronger consistency.
Interviewer may ask next
What would you change if every read must always return the newest value?
I would keep the same basic architecture, but I would stop using Replicas for normal application reads. Every GET that needs the newest value would go through the Java 21/25 KV Router Service to the Primary for that shard. The router would still use the Cluster Metadata / Shard Map to find the current Primary.
Replicas would still be useful for failover and recovery. The Primary would continue copying updates to them in the background. If the Primary failed, the Failure Detector + Failover Controller could promote a healthy Replica and update the shard information.
This keeps normal reads on the same active copy that handles writes, so the caller does not read from a Replica that is still catching up.
The downside is lower read capacity. Each Primary must now handle all strong reads for its shard, so we lose the read scaling that Replica reads provide.
What would you change if losing an acknowledged write after a node failure is unacceptable?
I would keep the same shards, Primaries, Replicas, and Java 21/25 KV Router Service, but I would make the ACK rule stricter. The Primary would not return an ACK using only the fastest durability option.
Instead, the write would wait for the stronger condition required by the interviewer. The diagram shows two useful choices. We can wait for fsync so the append-only log reaches stable storage. We can also wait for Replica confirmation so another node has received the write before the client gets an ACK.
The request still goes to the Primary that owns the shard. Replicas still support failover, and recovery still uses snapshots plus the append-only log.
The downside is higher latency. Every SET or DEL waits for extra storage or replication work before the ACK can return.
23. How would you design a typeahead search service?System DesignHardMicrosoft
i Question Details
Design a search autocomplete system for a large application. Cover prefix lookup, ranking, personalization, freshness, cache invalidation, high query volume, and the APIs you would expose for querying and updating suggestions.
Short Interview Answer (30-60 seconds)
At a high level, I would treat typeahead as a read-heavy search system. The main challenge is returning useful suggestions quickly while keeping ranking and freshness up to date. I would explain three flows: serving a query, rebuilding suggestion snapshots, and collecting behavior signals. Java service replicas use local and distributed caches plus an in-memory prefix index for fast reads. Background workers build versioned snapshots. The trade-off is more index and cache-management work in exchange for faster queries.
Detailed Explanation
The system must show useful search suggestions while the user is still typing. This means the read path runs very often and must stay fast. The suggestions also need good ordering, recent information, and optional personalization from user history. The diagram handles this with two connected paths. The first path serves queries from caches and an active prefix index. The second path updates suggestion data, collects user behavior, builds a new index snapshot, and safely switches the Java service replicas to that new version.
Useful Questions to Ask the Interviewer
How fresh do suggestion updates need to be?
Should personalization be optional when user history is unavailable?
How many suggestions should each query return?
Do different locales or user groups need different suggestions?
How to Explain It in an Interview
1. Explain the query entry point
I would start with the fast read path because typeahead is read-heavy. The Web / Mobile Client calls GET /v1/suggestions?prefix=jav&limit=10. The request first reaches the API Gateway. It handles authentication, validation, and rate limiting before forwarding the authenticated request.
The request then enters one Java 21/25 Typeahead Service Replica. Each replica runs in a separate JVM, so replicas do not share heap memory. The Request Handler can use virtual threads for many concurrent blocking requests. Virtual threads are lightweight JVM-managed threads, but they do not remove normal resource limits.
2. Normalize the prefix and use the fast lookup path
The Prefix Normalizer prepares the typed text before lookup. The service checks its L1 Cache first. This cache lives inside that Java replica.
On an L1 miss, the service can check the Distributed Suggestion Cache, which is the optional L2 cache. A cache hit can short-circuit deeper work. Versioned cache keys help prevent old suggestions from surviving after an index update.
If the needed result is not cached, the service reads the Active Prefix Index Snapshot. The diagram uses an immutable trie or FST. Immutable means the active structure is read-only. The trie or FST is organized for fast prefix lookup and returns the top N candidates.
3. Rank, personalize, and build the response
The Ranking + Personalization step orders those candidates. Its score uses prefix match, popularity, freshness, and personalization. The User Profile / History Store can provide user context and boosts.
If profile data is unavailable, the service falls back to global ranking. The Response Builder then creates the top K JSON suggestions[]. That response returns through the API Gateway to the Web / Mobile Client.
4. Update suggestions and ranking data in the background
Content changes use the Admin Update API. The diagram exposes POST /v1/suggestions/upsert and DELETE /v1/suggestions/{id}. These changes go into the Suggestion Source Store, which holds the official suggestion records and metadata.
Behavior is collected separately through POST /v1/suggestions/events. Impressions and clicks become Behavior Events and are placed on the Event Queue. The Popularity + Freshness Aggregator consumes those signals and produces ranking features.
The Index Builder, running in its own Java consumer JVM, combines source terms, metadata, and ranking features. It builds snapshot version N+1. The Snapshot Distributor / Version Manager then hot-swaps the active snapshot in the service replicas and bumps the cache version or invalidates affected keys.
5. Explain scale, failures, and operations
The Java replicas scale horizontally for high query volume. Each replica keeps its own local cache and active snapshot. If a rebuild fails, replicas keep serving the last good snapshot instead of a partial index.
If the optional L2 cache fails, requests can still use the active snapshot. If the profile store fails, global ranking still works. Observability tracks latency, errors, cache hit rate, build time, processing lag, and snapshot publish status. The main trade-off is extra background and version-management complexity for a very fast read path.
Engineering Considerations / Design Trade-offs
The benefit is that normal typeahead reads stay fast. A Java replica can answer from its L1 Cache, the optional L2 cache, or its active prefix snapshot without rebuilding data during a request. The downside is more work when suggestions change. The system must build a new snapshot, publish it safely, and keep cache versions aligned. Personalization adds another dependency, but the design can fall back to global ranking. We accept this extra complexity because reads happen very often, while index rebuilding and behavior processing can run in the background.
Why Interviewers Ask This
Interviewers use this question to see whether you can separate a very fast read path from slower background work. They want to see how you combine prefix lookup, ranking, caching, personalization, freshness, and safe updates. They also test whether you can explain failure handling and scaling without making unsupported guarantees. A strong answer shows good judgment about where complexity is worth adding.
Interviewer may ask next
What would you change if suggestion updates had to become visible much faster?
I would keep the same architecture, but I would shorten the time between an update and publishing the next snapshot. The Admin Update API would still write changes into the Suggestion Source Store, so the official suggestion data stays in one place. The Index Builder would run more frequently and create new snapshot versions sooner.
The Snapshot Distributor / Version Manager would then hot-swap those versions into the Java replicas more often. I would keep the versioned cache design as well. When a new snapshot becomes active, the version manager can bump the cache version or invalidate affected keys so old cached suggestions are not mixed with the new index.
The normal query path stays unchanged. It still uses the API Gateway, caches, active prefix snapshot, ranking step, and Response Builder. The main downside is more index-building work and more frequent cache invalidation, which can reduce cache hit rates.
What happens if the User Profile / History Store becomes unavailable during heavy traffic?
I would keep serving suggestions without personalization. The Ranking + Personalization component already supports a global ranking fallback in the diagram. It can still use prefix match, popularity, and freshness to order candidates from the Active Prefix Index Snapshot.
The rest of the read path does not need to change. Requests still pass through the API Gateway, Prefix Normalizer, caches, prefix index, ranking step, and Response Builder. This keeps the User Profile / History Store from becoming a required dependency for every successful autocomplete request.
Observability should record the profile-store failures so operators can see that personalized boosts are missing. The Java replicas can still scale horizontally and continue serving normal traffic.
The downside is lower result quality for some users. Suggestions remain useful, but they may be less tailored until the profile store becomes available again.
24. How would you design an image upload and download service?System DesignHardMicrosoft
i Question Details
Design an image upload and download service for web and mobile clients. Cover APIs, object storage, metadata, asynchronous processing, thumbnails, virus scanning, CDN delivery, deduplication, signed URLs, and observability.
Short Interview Answer (30-60 seconds)
At a high level, the goal is to accept image uploads safely and serve images quickly. The main challenge is that uploads need scanning and processing, while downloads should stay fast. I would explain the design in three flows: upload, background processing, and download. Clients upload directly to Object Storage with signed URLs. Java workers scan, deduplicate, and create thumbnails. Downloads go through the CDN. The trade-off is that processing finishes a little after the upload is accepted.
Detailed Explanation
The system must let web and mobile users upload images and later download the correct image or thumbnail. Uploading is harder than simply saving a file because the image must be checked for unsafe content, duplicates, and different thumbnail sizes. Downloads should also be fast without sending every image through the Java service. The diagram separates these concerns into an upload path, background processing, and a CDN-based download path. Metadata stays in the Metadata DB, while the actual image files stay in Object Storage.
Useful Questions to Ask the Interviewer
How quickly must a newly uploaded image become available for download?
Which image variants or thumbnail sizes do we need?
How long should signed upload and download URLs remain valid?
How to Explain It in an Interview
1. Start with the main idea
I would separate control requests from moving large image files. The API handles identity, permissions, metadata, and signed URLs. The image bytes move directly between the client, Object Storage, and the CDN. This keeps the Java API tier stateless and avoids making it carry large files.
The API Gateway / Load Balancer handles TLS termination, routing, and health checks. Requests then pass AuthN / AuthZ, Rate Limit, and Request Validation. The Java Image Service Cluster runs as Java 21/25 JVM replicas. Its stateless API instances use virtual threads for many concurrent blocking I/O requests.
2. Explain the upload path
For an upload, the client sends POST /v1/images:initiate. The Java Image Service creates an image record in the Metadata DB with status UPLOADING. The database stores metadata only, such as the owner, object keys, checksum, dimensions, MIME type, timestamps, status, and deduplication references.
The service returns the imageId and a short-lived signed upload URL. The client then sends the image directly to the private uploads / quarantine area in Object Storage. The signed URL gives limited permission for that upload instead of giving the client general storage access.
3. Explain the background processing
After Object Storage receives the file, it sends an object created event to the Event Queue. Async Media Workers run as separate Java JVM consumers. This work happens in the background, so the upload API does not wait for scanning and thumbnail creation to finish.
The workers first run the Virus Scan. An unsafe file gets status REJECTED in the Metadata DB. The object is deleted or kept in quarantine according to policy. A safe image then goes through Deduplication. The worker computes a SHA-256 content hash and checks the Metadata DB for an existing canonical object.
For unique content, the worker promotes or stores the image in originals / canonical. For duplicate content, metadata points to the existing canonical object, and the temporary duplicate is discarded. The workers then run Thumbnail Generation and write variants into thumbnails / variants. Finally, they update the Metadata DB to ACTIVE and save the object keys, checksum, dimensions, and MIME type.
4. Explain the download path
For a download, the client sends GET /v1/images/{id}?variant=thumb. The request again passes authentication, authorization, rate limiting, and validation. The Java Image Service checks the Metadata Cache first.
If the cache misses, the service queries the Metadata DB and fills the cache. The service then returns a short-lived signed CDN URL or redirects the client to the authorized image variant. The client requests that URL from the CDN. If the CDN does not already have the object, it fetches it from Object Storage. The CDN then returns the image bytes to the client.
5. Explain failures, security, and the trade-off
If an Async Media Worker fails, the work is retried with backoff. Work that still fails after the retry policy moves through the Retry + DLQ path for manual inspection. Observability / Monitoring collects centralized logs, metrics, traces, alerts, and audit information across the system.
The main trade-off is that upload acceptance and image readiness happen at different times. An upload can finish before virus scanning, deduplication, and thumbnail generation complete. This keeps the main upload path responsive, but the image may not be ready until processing finishes and its status becomes ACTIVE.
Engineering Considerations / Design Trade-offs
The benefit is that large image files do not pass through the Java API. Clients upload directly to Object Storage, and downloads are served through the CDN. This keeps the API simpler and makes image delivery faster. Background workers also keep virus scanning, deduplication, and thumbnail creation away from the main request path. The downside is that processing finishes later. A file may be uploaded but not yet ready to use. The queue and Retry + DLQ path add more moving parts. Deduplication saves blob storage, but metadata must correctly point different image records to the shared canonical object.
Why Interviewers Ask This
Interviewers use this question to see whether you can separate large file movement from normal API work. They also want to see how you handle background processing, caching, security, failures, and fast delivery. A strong answer shows that you understand which data belongs in the Metadata DB, which data belongs in Object Storage, and why some work should happen after the upload request finishes.
Interviewer may ask next
What would you change if users must try to download an image immediately after uploading it?
I would keep the same basic design, but I would make the image status important in the read path. The Metadata DB already tracks states such as UPLOADING, REJECTED, and ACTIVE. The Java Image Service should return a signed CDN URL only when the requested image or variant is ready and the status is ACTIVE.
If the upload has finished but Virus Scan, Deduplication, or Thumbnail Generation is still running, the service should tell the client that processing is not complete yet. I would not expose the object from uploads / quarantine just to make it available faster. That would bypass the safety and processing flow shown in the diagram.
The Event Queue and Async Media Workers continue working normally. When processing finishes, the workers update the Metadata DB to ACTIVE. The downside is that users may have a short wait between finishing the upload and being able to download the final image or thumbnail.
How would the design handle a large spike in uploads when background processing becomes slow?
I would keep the Event Queue between Object Storage and the Async Media Workers. The queue lets object created events wait while the workers process earlier uploads. I would also run more Worker Instance JVMs, using the same separate-consumer design shown in the diagram.
The Java Image Service does not need to wait for this background work. It can still create the UPLOADING metadata record and return the signed upload URL. New files remain in the private uploads / quarantine area until their processing reaches the correct result.
If a worker fails, the existing retry path uses backoff. Work that keeps failing moves to the Retry + DLQ path for manual inspection. Observability / Monitoring provides logs, metrics, traces, and alerts across these components.
The downside is that more worker JVMs use more compute resources. If the queue grows faster than workers can process it, users wait longer before their images become ACTIVE.
25. How would you design an application metadata API server?API DesignMediumMicrosoft
i Question Details
Design an API server for application metadata with persistence, YAML payload support, and search by query parameters. Discuss validation, testing, input errors, and how you would structure the endpoints.
Short Interview Answer (30-60 seconds)
At a high level, I would build one metadata API that lets clients create, read, update, delete, and search application records. Requests enter through REST endpoints, then YAML or JSON content is parsed and validated before the Metadata Service applies business rules. The Repository handles persistence and transactions, and results return through the same application layers. I would use strict validation and clear HTTP errors as the main reliability decision. The trade-off is that supporting both YAML and JSON is convenient for clients, but adds parsing, validation, and testing complexity.
Detailed Explanation
The goal is to give teams one simple place to save and find information about their applications. A client should be able to add a record, look it up, change it, remove it, or search using common fields. The server must also reject bad input clearly so incorrect information does not reach storage. The design keeps each job separate. One part receives requests, one checks the data, one applies the rules, and one saves or reads records. I would explain the solution by following that same path from the client to storage and then back to the client.
Useful Questions to Ask the Interviewer
Which metadata fields are required for every application?
Should metadata have a uniqueness rule, such as a unique name within an environment?
Do clients need both YAML and JSON responses, or only YAML and JSON request support?
How to Explain It in an Interview
1. Start with the API boundary and endpoints
I would expose the API through the REST Endpoints component. The diagram shows POST /metadata to create metadata, GET /metadata/{id} to read one record, PUT /metadata/{id} to update it, and DELETE /metadata/{id} to remove it. Search uses GET /metadata?name=&owner=&tag=&environment=. These query parameters let clients filter by name, owner, tag, and environment. The API Client / Consumer sends an HTTPS request to these endpoints. A successful response returns from the REST Endpoints to the client as 200/201 with JSON or YAML.
2. Parse and validate the incoming request
The REST Endpoints pass the request body plus path or query parameters to the YAML / JSON Parser + Validator. This component checks the content type, parses YAML, validates the schema, checks required fields, and normalizes fields. The diagram also shows a sample YAML document with fields such as appId, name, version, owner, tags, and environment. This validation step keeps malformed or incomplete data away from the business logic. Malformed YAML or missing or invalid fields produce 400 Bad Request. An unsupported payload format produces 415 Unsupported Media Type.
3. Apply metadata business rules
After validation, the parser sends a validated command or query to the Metadata Service. This service coordinates create, read, update, delete, and search behavior. It handles search, filtering, and sorting. It also owns the uniqueness rules shown in the diagram and maps results into the response form. If a requested metadata id does not exist, the API returns 404 Not Found. If a create or update conflicts with a uniqueness rule, it returns 409 Conflict.
4. Persist and retrieve metadata
The Metadata Service sends a CRUD or search request to the Repository. The Repository builds queries, performs persistence work, and handles transactions. It sends a read or write query to the Metadata Store. The database stores fields including appId, name, version, owner, tags, environment, createdAt, and updatedAt. The Metadata Store returns a record or result set to the Repository. The Repository then returns a domain result to the Metadata Service.
5. Return the response through the shown path
The Metadata Service maps the domain result to the response. The diagram shows that result moving back through the YAML / JSON Parser + Validator as a validation status or result, and then to the REST Endpoints as an HTTP response. The REST Endpoints finally return 200/201 JSON or YAML to the API Client / Consumer. The database never responds directly to the client. Each component returns information to the component that called it.
6. Add logging, audit records, and testing
Logging / Audit is a supporting flow, not part of the main business response path. The REST Endpoints send request events to it. The Metadata Service sends mutation and error events. The logs include request details, validation failures, not-found and conflict errors, and create, update, or delete audit activity. Testing covers unit tests for the service, validator, and utilities; API tests for endpoints, scenarios, and errors; and repository integration tests for queries and transactions. This keeps HTTP handling, validation, business logic, persistence, observability, and testing clearly separated.
Practical Complexity & Trade-offs
The benefit of this design is that each layer has one clear job. REST Endpoints handle HTTP requests. The parser and validator protect the service from bad YAML, JSON, or missing fields. The Metadata Service owns business rules. The Repository owns database access and transactions. Supporting both YAML and JSON is useful for different clients, but every accepted format needs parsing and test coverage. Query parameters make simple searches easy, but more filter combinations can make repository queries harder to maintain. Clear 400, 404, 409, and 415 responses help clients understand failures. Logging gives useful request and change history, but creates more operational data to manage. We accept that extra complexity because the separation makes the API easier to test and change safely.
Why Interviewers Ask This
Interviewers use this question to check whether you can turn a simple requirement into clear API boundaries. They want to see correct HTTP methods, useful resource paths, search with query parameters, and a correct request and response flow. They also evaluate whether you separate validation, business rules, persistence, logging, and testing properly. A strong answer explains input errors, transaction ownership, and realistic trade-offs without adding unnecessary infrastructure or unsupported guarantees.
Interviewer may ask next
How would this design change if the metadata table became much larger and search traffic increased?
I would keep the same API and component boundaries, but I would focus on improving the existing Repository and Metadata Store path. The search endpoint would still be GET /metadata?name=&owner=&tag=&environment=, and the Metadata Service would still send a search request to the Repository. As the number of records grows, query construction and database performance become more important. I would use repository integration tests to measure common filter combinations such as owner plus environment or tag plus environment. Validation would still happen before the Metadata Service, and results would return through the same response path. Logging would continue to record request and error events. The main downside is that richer filtering can create more complicated database queries and more tuning work. I would not add a cache, search engine, pagination rule, or new endpoint unless the requirements changed, because those capabilities are not part of the approved design.
How would you test YAML support and the input error behavior shown in this API?
I would test each layer that owns part of the behavior. For the YAML / JSON Parser + Validator, unit tests would cover valid YAML, malformed YAML, missing required fields, invalid field types, content-type checks, and field normalization. Malformed YAML or missing or invalid fields should produce 400 Bad Request. Unsupported payload formats should produce 415 Unsupported Media Type. API tests would call the shown endpoints and verify that valid requests reach the Metadata Service while invalid requests stop during validation. I would also test GET /metadata/{id} returning 404 Not Found when the id is missing and create or update operations returning 409 Conflict when the uniqueness rule is violated. Repository integration tests would verify reads, writes, search queries, and transaction behavior against the persistence layer. The downside is more test cases because both YAML and JSON are supported, but that coverage reduces the risk of accepting or storing bad metadata.
26. How would you design REST API fundamentals around POST, PUT, PATCH, and response codes?API DesignMediumMicrosoft
i Question Details
Explain REST API fundamentals including POST, PUT, PATCH, their usage, and common response codes. Clarify how you would choose the right verb and how you would communicate success and failure to clients.
Short Interview Answer (30-60 seconds)
At a high level, I would make the API predictable by choosing the HTTP verb from the kind of change the client wants. POST /resources creates a new resource, the server assigns its ID, and success returns 201 Created with a Location header. PUT /resources/{id} replaces the complete resource and is idempotent. PATCH /resources/{id} changes only selected fields. Each operation writes to the Resource Store, then the Java REST API returns a clear status and error body. The main trade-off is simpler full replacement with PUT versus smaller but more complex partial updates with PATCH.
Detailed Explanation
This question is about making an API easy for clients to understand and use correctly. A client needs one action for creating something, another for replacing everything, and another for changing only a few fields. The API must also clearly say whether each request worked or failed. The diagram uses a Client App, a Java REST API, and a Resource Store. I would explain how the client chooses the action, how the API changes stored data, and how the result returns to the client.
Useful Questions to Ask the Interviewer
Should the server always assign the ID for a newly created resource?
For PUT, should the client always send the complete resource representation?
For PATCH, what validation rules should apply to the changed fields?
How to Explain It in an Interview
1. Choose the HTTP verb from the requested change
I would first decide what the client is trying to do. The Client App sends an API request. If it wants to create a new resource, I use POST. If it wants to replace the full resource, I use PUT. If it wants to update only selected fields, I use PATCH. This keeps the contract predictable because the HTTP method tells the client what kind of change will happen.
2. Use POST /resources to create a resource
For creation, the diagram uses POST /resources. The Java REST API creates a new resource, and the server assigns the ID. POST is not idempotent in this design. Repeating the same create request may therefore create another resource. The API sends a create operation to the Resource Store. On success, it returns 201 Created with a Location header. The shown POST failures are 400 Bad Request and 409 Conflict.
3. Use PUT /resources/{id} for full replacement
For a complete replacement, I use PUT /resources/{id}. The client sends the complete representation of the resource. The Java REST API sends a replace operation to the Resource Store. PUT is idempotent here, which means repeating the same request produces the same final stored state. On success, the API returns 200 OK or 204 No Content. The shown PUT failures are 400 Bad Request and 404 Not Found.
4. Use PATCH /resources/{id} for partial changes
For a smaller change, I use PATCH /resources/{id}. The client sends only the fields that need to change. The Java REST API sends a partial update to the Resource Store. This is useful when replacing the complete representation would be unnecessary. On success, the API returns 200 OK or 204 No Content. The shown PATCH failures are 400 Bad Request, 404 Not Found, and 422 Unprocessable Entity.
5. Keep the request and response paths separate
The request moves from the Client App to the HTTP verb decision and then to the matching Java REST API operation. POST creates, PUT replaces, and PATCH performs a partial update in the Resource Store. The response is a separate flow in the opposite direction. It returns from the Java REST API to the Client App with the status that describes the result.
6. Communicate failures consistently
I would use consistent JSON validation and error bodies so clients can understand failures. The diagram also shows 401 Unauthorized and 403 Forbidden for authentication or authorization problems. It shows 429 Too Many Requests for rate limiting or throttling. A 5xx response represents a server-side failure. These codes should be returned only when the matching condition actually occurs.
7. Explain the main trade-off
PUT is simple because the client sends one complete representation, and its idempotent behavior is easy to reason about. The downside is that the client may send more data than necessary. PATCH sends only selected fields, so it can be smaller and more focused. The downside is that partial-update validation is usually more complicated. POST fits resource creation well, but repeated POST requests may create more than one resource because POST is not idempotent in this design.
Practical Complexity & Trade-offs
The benefit of this design is that each HTTP method has a clear purpose. POST creates a resource, PUT replaces the complete resource, and PATCH changes selected fields. PUT is idempotent, so repeating the same request leaves the same final state. POST is not idempotent here, so repeating a creation request may create another resource. PATCH can send less data than PUT, but validating partial changes can be more complicated. Clear status codes make the API easier for clients to handle. Consistent JSON validation and error bodies also make failures easier to understand. The downside is that the API team must keep these rules consistent across every operation. We accept that discipline because predictable APIs are easier to integrate with and troubleshoot.
Why Interviewers Ask This
Interviewers ask this question to check whether you understand HTTP behavior instead of only knowing endpoint syntax. They want to see whether you can choose POST, PUT, and PATCH for the right reasons, model request and response flow correctly, and use meaningful status codes. They also test your judgment around idempotency, validation, partial updates, error handling, and client expectations. A strong answer shows that you can design an API that is predictable and easy to use.
Interviewer may ask next
What happens if the client retries POST /resources because it did not receive the response?
The important point is that POST /resources is not idempotent in this design, so I would not assume that retrying it is safe. The first request may already have reached the Java REST API, created the resource in the Resource Store, and produced a 201 Created response that the client never received. Sending the same POST again could create another resource. I would keep the existing POST endpoint, server-assigned ID behavior, Resource Store flow, and response codes unchanged. The client should therefore treat an uncertain POST result carefully instead of assuming that another identical request has the same final effect. When creation succeeds, the API still returns 201 Created with the Location header. The shown errors such as 400 Bad Request or 409 Conflict still apply when those conditions occur. The downside is that this creation behavior is harder to retry safely than the idempotent PUT operation.
How would you choose between PUT /resources/{id} and PATCH /resources/{id} for an update?
I would use PUT when the client wants to replace the complete resource and PATCH when it wants to change only selected fields. With PUT /resources/{id}, the client sends the complete representation, and the Java REST API sends a replace operation to the Resource Store. PUT is idempotent in this design, so repeating the same request leaves the same final state. With PATCH /resources/{id}, the API performs only a partial update using the changed fields. The existing success behavior stays the same: either operation can return 200 OK or 204 No Content. PUT shows 400 Bad Request and 404 Not Found as failures. PATCH also shows 422 Unprocessable Entity. The main benefit of PUT is simpler full-state reasoning. Its downside is sending the complete representation. PATCH sends less data, but the validation rules for partial changes can be more complicated. All other components and response flows remain unchanged.
27. How would you design a better API class based on an underlying API class?API DesignMediumMicrosoft
i Question Details
Design a better API class on top of an underlying API class, and explain the interface, abstractions, threading or async concerns, and how you would preserve usability and maintainability.
Short Interview Answer (30-60 seconds)
At a high level, I would place a small BetterApi interface in front of the existing UnderlyingApiClient. The caller works with typed request and response DTOs, while DefaultBetterApi centralizes validation, token injection, retry and timeout policy, error mapping, logging, and async execution. UnderlyingApiAdapter translates between the clean API model and the lower-level client. Responses return through the same layers and become domain responses. This improves usability and maintainability. The trade-off is extra wrapper, adapter, and policy code that must be tested and maintained.
Detailed Explanation
The existing API class may work, but it may expose too many low-level details. That makes every caller harder to write and maintain. The goal is to put a simpler API in front of it. Callers should use clear request and response objects and should not depend on transport details or raw callbacks. The new design should also handle common rules in one place. The attached diagram does this with BetterApi, DefaultBetterApi, an adapter, the existing client, and supporting validation, retry, logging, and asynchronous components.
Useful Questions to Ask the Interviewer
Should BetterApi provide both synchronous and asynchronous methods?
Must UnderlyingApiClient remain unchanged?
Which retry and timeout options should callers be allowed to configure?
Should low-level exceptions ever be exposed to advanced callers?
How to Explain It in an Interview
1. Define a small public API
I would start with BetterApi as the public interface. The Application / Service Caller sends a typed API request to it and receives an API response back. BetterApi uses an Immutable Request DTO and a Domain Response DTO. Builder / Options provides controlled configuration. The interface stays small and supports synchronous and asynchronous methods. This gives callers a stable API and prevents transport details from leaking into application code.
2. Centralize behavior in DefaultBetterApi
BetterApi passes the command to DefaultBetterApi, which is the main implementation and orchestration point. It coordinates Validation and receives a validation result. It also uses Auth Injection to attach the token required by the lower-level request. Keeping these concerns in DefaultBetterApi avoids making every caller repeat the same work. It also gives one place to change these policies later.
3. Apply reliability, error, and logging policies
DefaultBetterApi applies the Retry / Timeout Policy and receives the policy result. Error Mapping converts low-level failures into errors that fit the better API instead of exposing raw exceptions. Logging / Metrics receives logs and metrics from the implementation and sends telemetry to Observability. Observability is a side flow. It does not own or change the business response.
4. Translate through UnderlyingApiAdapter
DefaultBetterApi sends the translated request to UnderlyingApiAdapter. The adapter is the single place for translation between the clean BetterApi model and the format expected by UnderlyingApiClient. It also hides low-level callbacks and raw exceptions. This is an important maintainability boundary because changes in the lower-level API can usually be isolated inside the adapter.
5. Call the existing API and return the response
UnderlyingApiAdapter sends an HTTP / SDK request to UnderlyingApiClient. That client sends the HTTP / SDK request to the Remote Service. The response follows separate arrows in reverse. Remote Service returns an HTTP / SDK response to UnderlyingApiClient. The client returns the response to UnderlyingApiAdapter. The adapter sends the raw response back to DefaultBetterApi. DefaultBetterApi maps it into a domain response, BetterApi returns the API response, and the Application / Service Caller receives it.
6. Keep asynchronous use simple and safe
The facade is thread-safe and uses immutable DTOs. The diagram also shows a shared ExecutorService. DefaultBetterApi schedules async work there and receives a completion callback. Async methods return CompletableFuture<Response>, so callers do not need to work directly with low-level callbacks. Immutable DTOs are safe to share between threads in the same JVM because their state does not change. The main trade-off is that this cleaner API adds another layer that must be tested and maintained.
Practical Complexity & Trade-offs
The benefit is that application developers work with a small, stable interface instead of a verbose lower-level client. Immutable DTOs and Builder / Options make requests easier to understand. DefaultBetterApi keeps validation, token injection, retry and timeout policy, error mapping, logging, and async execution in one place. UnderlyingApiAdapter reduces coupling by isolating translation and low-level callback behavior. The downside is extra code and more tests. Retry and timeout rules also need careful configuration because bad policies can make failures worse. A shared ExecutorService must be managed so async work does not grow without control. We accept these costs because the public API becomes easier to use, easier to change, and less dependent on UnderlyingApiClient.
Why Interviewers Ask This
Interviewers use this question to test whether you can improve an existing API without rewriting the lower-level implementation. They look for clear abstraction boundaries, useful request and response models, correct separation of responsibilities, sensible error handling, and practical Java async design. They also want to see whether you understand where validation, retries, timeouts, translation, and logging belong. A strong answer explains both the usability benefit and the maintenance cost of adding the wrapper layer.
Interviewer may ask next
What would you change if the underlying API became slow or unreliable?
I would keep the same BetterApi, DefaultBetterApi, UnderlyingApiAdapter, and UnderlyingApiClient structure. The main change would be in the existing Retry / Timeout Policy owned by DefaultBetterApi. I would tune timeout values and only retry operations when repeating them is safe for that operation. The rest of the request flow stays the same. Validation and Auth Injection still run before the translated request reaches the adapter and lower-level client. Errors still return through Error Mapping instead of leaking raw exceptions to BetterApi callers. Logging / Metrics would record timeout and retry outcomes and send telemetry to Observability. Async requests would still use ExecutorService and CompletableFuture<Response>. The benefit is better resilience without changing the public interface. The downside is more policy complexity, and aggressive retries can increase load on an already unhealthy remote service.
How would you keep the asynchronous API safe when many callers use it at the same time?
I would keep BetterApi and DefaultBetterApi thread-safe and continue using immutable request and response DTOs. Immutable objects do not change after creation, so different threads in the same JVM can safely read them without coordinating writes. DefaultBetterApi would continue scheduling async work on the shared ExecutorService, and each async method would return CompletableFuture<Response>. I would avoid storing request-specific mutable state in shared fields of BetterApi, DefaultBetterApi, or UnderlyingApiAdapter. Each request should carry its own data through Validation, Auth Injection, Retry / Timeout Policy, translation, and Error Mapping. The adapter would continue hiding any low-level callback behavior from UnderlyingApiClient. The benefit is a simple async contract for callers. The downside is that the shared ExecutorService needs sensible limits and lifecycle management so concurrent work does not exhaust application resources.
28. How would you design a search API for 'Plumbers near Kondapur'?API DesignHardMicrosoft
i Question Details
Design an API for a local search experience such as 'Plumbers near Kondapur'. Cover the request and response shape, ingestion, indexing, ranking, geo-spatial lookup, freshness, and scalability.
Short Interview Answer (30-60 seconds)
At a high level, I would design this as a local search API that finds plumbers near a place and returns a ranked list quickly. I would route the request through the client, edge security, and a Java Spring Boot search service, then use the search platform, cache, and geo lookup to answer it. The main security decision is to validate, rate limit, and authorize at the edge before the request reaches the service. The main trade-off is that indexing and caching make search fast, but they add ingestion and freshness complexity.
Detailed Explanation
This question asks for a local search API for plumbers near a place, like Kondapur. The main goal is to take one search request and return nearby plumbers fast, with the right distance, rating, open status, and basic details. The hard part is that search must be quick, but the data must also stay fresh when plumbers update their profile or location. I will explain the design in the same order as the diagram, from the client request through the Java search service and search platform, and then through the ingestion flow that keeps the index updated.
Useful Questions to Ask the Interviewer
Should the API support only nearby search, or also filters like rating, price, and open now?
How fresh must updates be after a plumber changes location, hours, or photos?
Do we need tenant-specific ranking or business rules?
How to Explain It in an Interview
1. Goal and request shape
At a high level, I would keep the API focused on one job: search for plumbers near a place and return a ranked list. The visible example is GET /v1/search/plumbers with query parameters like near=Kondapur, radius=5km, filters, page, and size. The response is 200 OK with JSON that includes results, page, size, and total. This boundary matters because the caller should see one simple contract, while the search index stays hidden behind it.
2. Edge security and request validation
The request first goes through DNS or anycast, WAF or DDoS protection, and the API gateway. The gateway handles authN and authZ, rate limiting, quotas, and request validation. In simple words, it checks who the caller is, whether they are allowed, and whether the request is valid. The cross-cutting services here are Auth Service (OAuth2 / JWT), User & Tenant Service, Rate Limiter Service, Config Service, Observability, and Alerting. If the request fails at the edge, it should not reach the Java service.
3. Search flow inside the Java service
The Search API Service is a Spring Boot REST controller. It parses the query, validates it again, and builds the search DSL. The Query Orchestrator Service geocodes the place name, expands synonyms, applies filters, and routes the query to the right index. The Search Service then executes the search, handles pagination, and asks for aggregations when needed. The search platform is OpenSearch or Elasticsearch, and it uses both a primary index for plumbers and a geo-spatial index for nearby lookup. This is the main business path.
4. Rank, cache, and shape the response
The Ranking Service scores results with text relevance, distance, business rules, and freshness boost. The Response Builder shapes the final JSON, enriches the results, and redacts fields that should not leave the service. The caching layer uses Caffeine or Redis for query result cache, location cache, and popular queries. That helps common searches stay fast, especially for hot places like Kondapur. The response then returns through the gateway to the client as normal HTTPS JSON.
5. Fresh data through ingestion
Freshness comes from the ingestion pipeline. The Plumber App or Partner Portal sends create or update changes to the Ingestion API in Java. That service validates and persists the change in PostgreSQL, then emits a change event to Kafka. The Indexer Service consumes those events and updates the search documents, the geo-spatial index, and the synonym or suggester data when needed. This keeps the search index fresh without slowing down user reads.
6. Supporting stores and trade-offs
The supporting data stores are PostgreSQL for operational data, Redis for cache and sessions, and blob storage for images or documents. The data model keeps fields like name, categories, location, address, open hours, rating, reviews, verification, photos, and last updated time. The main trade-off is speed versus freshness. Caching and indexing make reads fast, but they add sync work, reindexing, and event handling. I accept that trade-off because local search must stay fast and still feel current.
Practical Complexity & Trade-offs
The benefit of this design is fast local search with clear ownership. The edge blocks bad traffic early, and the Java service keeps the search logic simple. The search platform and cache make common queries very fast. Geo lookup makes the results useful because the user cares about distance. The downside is operational complexity. We now need ingestion, Kafka, an indexer, cache invalidation, and freshness checks. We accept that because a local search API must return good nearby results under load. Another trade-off is that a response can be very fast, but a new update may take a short time to appear in search.
Why Interviewers Ask This
The interviewer is checking whether I can turn a user search problem into a clean API design. They want to see if I can define the request and response clearly, separate edge checks from core search logic, and explain how geo lookup, ranking, caching, and freshness work together. They also want to see good judgment about security, scaling, and trade-offs, not just a list of services.
Interviewer may ask next
How would you keep the API fast when many users search the same neighborhood at once?
At a high level, I would keep the same API and make the hot path cheaper. The affected pieces are the API gateway, the cache layer, and the Java search service. I would let common queries such as Kondapur live in Caffeine or Redis for a short time, so the search platform does less repeated work. The gateway would still enforce rate limiting and quotas, which protects the service during the spike. Correctness stays good because the query still goes through the same validation and ranking steps. The main downside is that a short cache time-to-live can return slightly older results for a little while. I accept that trade-off because local search is often read-heavy, and users care most about fast results during busy periods.
How would you support tenant-specific rules or business rules?
I would keep the same request shape and use the User & Tenant Service plus the Config Service to apply tenant-specific rules. The affected flow is the edge identity context, the ranking service, and the response builder. The request still goes through auth and validation first, then the search service can read tenant context and choose the right ranking weights or feature flags. Correctness stays good because the same search index and geo lookup still power the result set. The main downside is that tenant-specific rules add more configuration and more testing. I accept that trade-off because many real systems need different ranking behavior for different partners or business lines.
29. How would you explain OOP design and API rollout?API DesignHardMicrosoft
i Question Details
Discuss how you would design maintainable backend logic and safely evolve public APIs. Cover backward compatibility, versioning, testing, rollout strategy, monitoring, and client communication.
Short Interview Answer (30-60 seconds)
At a high level, I would separate maintainable backend logic from safe public API evolution. Clients send HTTPS requests through the API gateway, which handles authentication, rate limiting, and routing. Inside the Java application, the controller maps requests, the application service coordinates the use case, the domain model holds business rules, and the repository abstracts persistence. For API changes, I prefer backward-compatible additions, versioning only for breaking changes, strong compatibility testing, gradual rollout, monitoring, and clear client communication. The trade-off is more release and migration work in exchange for lower client risk.
Detailed Explanation
This question asks how I would keep backend code easy to understand while changing a public API safely. We want developers to change business logic without mixing every responsibility together. We also want existing web, mobile, and partner clients to keep working when the API evolves. The main challenge is balancing clean internal design with safe external change. I would explain the backend layers first. Then I would explain the API contract, versioning, testing, rollout, monitoring, and client communication shown in the diagram.
Useful Questions to Ask the Interviewer
How many external clients depend on this public API?
How long must an older API version remain supported?
What backward-compatibility promise do we make to existing clients?
How to Explain It in an Interview
1. Define the public API boundary
I would start by defining a stable public API contract. The diagram shows stable DTOs, additive fields, defaults, and tolerant readers. A DTO is simply the data shape passed between parts of the system. Additive changes are safer because existing fields keep their meaning. Optional fields and sensible defaults also help older clients continue working. Tolerant readers mean a client can ignore fields it does not understand.
The clients are web, mobile, and partner applications. They send an HTTPS request to the API gateway. The gateway owns authentication, rate limiting, and routing. The response returns through the gateway and then back to the client.
2. Separate backend responsibilities with OOP
Inside the Java application boundary, I would keep each responsibility small and clear. The Controller / resource handles request validation and response mapping. It passes a DTO or command to the Application service. The Application service coordinates the use case.
The Application service then invokes the Domain model. The Domain model contains entities, value objects, and business rules. This is where the important business behavior lives instead of placing it inside the transport layer.
The diagram shows the Domain model loading or saving an aggregate through the Repository. An aggregate is a related group of domain objects treated as one business unit. The Repository provides a persistence abstraction and reads or writes data in the Database. The returned domain data moves back through the domain and application layers. This separation makes the backend easier to test and change.
3. Keep compatible changes in the current version
For API evolution, I would prefer non-breaking changes whenever possible. The diagram shows an evolution policy where compatible changes stay in the current version. Examples include additive fields, optional values, and defaults that do not change existing behavior.
When a change is truly breaking, I would move it to v2 instead of silently changing v1. During migration, I would support v1 and v2 in parallel. This gives existing clients time to migrate while new clients can use the newer contract.
4. Use testing as the release gate
Before rollout, I would use several levels of testing. Unit tests verify small pieces of logic. Integration tests verify components working together. Consumer contract tests check that the API still matches client expectations. Backward-compatibility tests protect existing behavior.
These tests form the release gate shown in the diagram. They reduce the chance that a backend refactor or API change breaks an existing client before deployment.
5. Roll out changes gradually
After the release gate passes, the Rollout strategy deploys the application. The diagram shows a feature flag, canary release, gradual traffic shift, full rollout, and rollback.
A feature flag lets us control when new behavior becomes active. A canary exposes the change to a small amount of traffic first. If production signals remain healthy, we gradually increase traffic. Then we move to full rollout. If monitoring shows a serious problem, the rollout process can use the rollback step instead of continuing.
6. Monitor production behavior
The Java application sends metrics and logs to Monitoring. The diagram specifically tracks latency, 4xx and 5xx responses, schema failures, and client usage by version. Monitoring then provides a go or rollback signal to the Rollout strategy.
Client usage by version is especially useful during migration. It tells us whether clients are still using v1 before we consider ending support.
7. Communicate changes clearly to clients
Safe API evolution is not only a coding problem. Clients need enough information and time to migrate. The Versioning flow leads to a deprecation plan and then to Client communication.
The diagram shows an OpenAPI update, changelog, deprecation notice, migration guide, and sunset date. Those changes are announced to clients. This makes the migration predictable instead of surprising users when an old version disappears.
The main trade-off is extra operational work. We may temporarily support multiple versions, maintain more tests, run staged deployments, monitor version usage, and communicate migrations. I accept that cost because it greatly reduces the risk of breaking public clients.
Practical Complexity & Trade-offs
The benefit of this design is clear ownership. The gateway handles authentication, rate limiting, and routing. The controller handles request and response mapping. The application service coordinates the use case. The domain model contains business rules, and the repository hides database details. This makes changes easier to test and understand. For the public API, additive changes reduce breakage, while a new version handles changes that cannot stay compatible. The downside is extra work. We may support v1 and v2 together, maintain contract tests, manage feature flags, watch production metrics, and publish migration information. Canary releases also make deployment more controlled but slower than sending all traffic to a new release immediately. We accept this operational cost because it lowers the chance of breaking many clients at once.
Why Interviewers Ask This
Interviewers ask this question to test engineering judgment across both code design and API evolution. They want to see whether I can separate transport logic, application coordination, domain rules, and persistence clearly. They also want to know whether I understand backward compatibility, versioning, contract testing, staged rollout, production monitoring, and client migration. A strong answer shows that API design is not only about defining a request. It also includes safely changing that contract over time.
Interviewer may ask next
What would you do if the canary release starts showing more production errors?
I would stop increasing traffic and use the monitoring signal to roll back the new release. The affected flow is between Monitoring and the Rollout strategy. The diagram tracks latency, 4xx and 5xx responses, schema failures, and client usage by version. I would compare those signals with the expected behavior during the canary. If the new release is clearly unhealthy, I would use the rollback step rather than continuing toward full rollout.
The public API contract does not need to change during this response. The gateway, Java application layers, repository, database, and existing client communication remain the same. The important benefit of the canary is that only a limited amount of traffic sees the new release before we trust it more broadly.
The downside is operational complexity. We need useful monitoring, controlled traffic movement, feature flags, and a dependable rollback process. That extra work is worthwhile because it limits the impact of a bad deployment.
How would you handle an API change that cannot remain backward compatible?
I would introduce a new API version instead of changing the existing contract in place. The affected parts are Versioning, the API contract, Testing, Client communication, and the Rollout strategy. The diagram says non-breaking changes remain in the current version, while breaking changes use v2. During migration, I would keep v1 and v2 available in parallel so existing clients can continue working.
I would test both versions with unit, integration, consumer contract, and backward-compatibility tests. I would then deploy the change through the same feature-flag, canary, gradual-traffic, and monitoring process. Monitoring client usage by version tells us how much migration work remains.
I would also publish the OpenAPI update, changelog, deprecation notice, migration guide, and sunset date shown in the diagram. The main downside is maintaining two versions for a period of time. That adds code, testing, operations, and support work, but it avoids forcing every client to migrate at once.
30. Can you describe a scenario where you built a service?BehavioralMediumMicrosoft
i Question Details
Describe a service you built, what problem it solved, what you personally owned, and how you measured the outcome.
Interview tip:
Use STAR to structure your answer: briefly explain the Situation and Task, make Action the most detailed part, and finish with the Result. For example, describe a service you built to solve a clear business problem, explain what you personally owned, how you designed and implemented it, how you worked with others on important decisions, and how you evaluated whether the service improved the original process.
Situation
In my last role, an internal application depended on a manual process to collect and validate data before another system could use it. The process was slow, difficult to monitor, and errors sometimes required someone to investigate the data by hand. The team decided to replace that workflow with a Java service that could accept requests, validate the data, process it consistently, and expose clear status information.
Task
I was responsible for designing and building the main service logic. My goal was to create a reliable service that separated request handling from business rules, handled invalid input safely, and gave the team enough visibility to understand failures. I also needed to make sure the service could be maintained and extended without forcing large changes across the application.
Action
I first reviewed the existing workflow with the engineers who supported it so I could understand the real failure cases instead of only copying the old steps into code. I then defined a simple API contract that made required inputs and possible responses clear. I implemented the service in Java and separated the controller, business logic, and data access responsibilities so each part had one clear purpose. I added validation at the service boundary so bad requests were rejected before they reached deeper processing. For operations that could fail because of temporary dependencies, I made the error handling explicit and returned useful internal status information rather than hiding the failure. I also added structured logging around important processing steps so we could trace a request without reading unrelated log messages. I wrote unit tests for the business rules and integration tests for the main request flow and persistence behavior. During review, I walked the team through the API contract and failure cases, and I adjusted parts of the design where other engineers identified assumptions that could make future changes harder. After deployment, I compared the new service behavior with the previous manual workflow by reviewing processing errors, support issues, and feedback from the people who used the downstream system.
Result
The service replaced much of the manual handling with a consistent automated flow and made failures easier to understand and investigate. The team had a clearer interface for submitting and tracking work, and future changes were easier because the validation, business logic, and persistence concerns were separated. I learned that building a useful service is not only about writing the endpoint. It is also important to understand the real operational problems, design clear failure behavior, and decide in advance how the team will know whether the service is actually improving the process.
Why Interviewers Ask This
Interviewers ask this question to understand whether a candidate can take ownership of a service from problem definition through implementation and evaluation. A strong answer shows that the developer can connect technical design decisions to a real need, make practical choices about reliability and maintainability, collaborate with others, and evaluate whether the finished service actually solved the original problem.
Interviewer may ask next
How did you decide how to structure the service?
I based the structure on keeping responsibilities clear. Request handling stayed at the API boundary, business rules stayed in the service layer, and persistence logic stayed separate. I chose that structure because it made the important rules easier to test and reduced the chance that a change to the API or database would affect unrelated parts of the service.
How did you measure whether the service was successful?
I compared the new process with the problems we were trying to remove. I looked at processing errors, the amount of manual investigation still required, support issues, and feedback from the people using the downstream system. That gave us practical evidence that the automated flow was more consistent and easier to operate without inventing a success measure that was unrelated to the original problem.
More questions load as you scroll
Disclaimer: This interview guide is for educational and informational purposes only. It is designed to help readers prepare, but it does not guarantee any interview result, hiring decision, offer, or outcome. Interview questions, hiring criteria, and preferred answers can vary by employer, interviewer, industry, location, and time. The examples and explanations reflect the authors' research and judgment, are provided without warranties of any kind, and should not be treated as the only correct approach. Diagrams are simplified illustrations intended to highlight the main components and their interactions; actual systems and implementations may be more complex. Alternative approaches may be equally valid or better suited to a particular question, context, or interviewer. To the fullest extent permitted by applicable law, the author, contributors, and publisher are not liable for decisions made, actions taken, or losses incurred based on this guide.
Company Notice: This guide is an independent educational resource and is not affiliated with, endorsed by, sponsored by, or approved by the company named in this guide. Company names are used only to identify interview experiences commonly reported by candidates. Interview practices can change without notice, and inclusion of company-specific content does not mean these questions are official, complete, or guaranteed to be asked. To the fullest extent permitted by law, the author, contributors, and publisher are not responsible for outcomes related to use of this material.