My Microsoft SWE Interview Experience (July 2026): 4 Rounds, Real Mistakes and the Offer
#microsoft
#interview-experience
#backend-interview-experience
I got the loop invite on a Tuesday and spent the next week and a half in that specific state every engineer knows well half preparing, half pretending you're not nervous about it. Four rounds, roughly 45 minutes each, back to back over two days. Coding, low-level design, high-level design and a managerial round to close it out.
I'm writing this the way it actually happened, not the polished version. I got things wrong in every single round except the last one. The interviewers didn't just let those moments slide they asked one more question, waited and let me find my own way out of the hole. That's the part I want other people to see, because it's the part nobody puts in these write-ups.
Verdict: Selected.
| Detail | Info |
|---|---|
| Company | Microsoft |
| Role / Level | Software Engineer (L62) |
| Overall Difficulty | ⭐⭐⭐⭐☆ (4/5) |
| Total rounds | 4 |
| Time per round | ~45 minutes |
| Round 1 | Coding Expression Evaluator (eliminatory) |
| Round 2 | Low-Level Design - Library Management System |
| Round 3 | High-Level Design - E-commerce Shopping System |
| Round 4 | Managerial Resume + behavioral, with a short design tail |
| Result | Selected |
Interview Timeline
Four rounds, back to back over two days, roughly 45 minutes each: a coding round, an LLD round, an HLD round and a managerial round. Here's how each one actually went.
Round 1: Coding Build an Expression Evaluator
This round was flagged as eliminatory going in, which does something to your brain the second you open the problem. No pressure, just the entire rest of the loop depending on the next 45 minutes.
The problem: parse and evaluate a math expression string. It had to support +, -, *, /, parentheses, multi-digit numbers, spaces and unary plus/minus, while respecting normal operator precedence. The example they gave me was:
-7 + 5 * 8 - 5 / 4 + (5 + 4)
Correct answer: 41. (5×8 is 40, 5÷4 truncates to 1 and 5+4 is 9 so it's -7 + 40 - 1 + 9.)
My First Mistake: Treating Every Operator the Same
My gut reaction, before I'd even finished reading the whole prompt, was to scan the string left to right and just apply each operator as I hit it. I said this out loud, which in hindsight is exactly why the interviewer let me keep talking instead of stopping me right away.
I picked a tiny example to sanity-check myself before writing real code always do this, it will save you and used 2 + 3 * 4. My left-to-right idea gives (2 + 3) * 4 = 20. The actual answer is 14, because multiplication has to happen before addition. I caught this one myself, out loud, mid-sentence, which felt a little embarrassing but also better than the interviewer catching it for me.
My Second Mistake: Unary Minus Broke My Parser Twice
Once I had precedence sorted with a term/factor split, I moved on to unary operators and hit a wall almost immediately. My early parsing logic treated every - as a binary operator sitting between two numbers. The moment I tried 3 - -2 (a binary minus immediately followed by a unary minus), my code threw a number format exception trying to parse a lone - as an integer. And when I ran the actual interview example which opens with a unary minus before the 7 it broke even harder, because it also had no idea what to do with an operator sitting right in front of an opening parenthesis, like in (5 + 4).
The interviewer didn't tell me what was wrong. He just asked, "What happens if I put a - in front of your very first number?" That question was the entire hint. I realized my mistake was architectural, not a typo I was trying to bolt unary handling onto the operator-scanning logic instead of building it into how I parse a single value in the first place.
Getting to the Real Solution
The fix was to think in three layers instead of one flat scan, which is the standard way to handle precedence correctly:
An expression is one or more terms added or subtracted together. A term is one or more factors multiplied or divided together. A factor is a number, a parenthesized expression or a unary sign in front of another factor.
Once unary sign-handling lives inside "factor," both 3 - -2 and a leading -7 just work, with no special-case code anywhere. This is roughly what I sketched on the shared doc to explain the call structure before I wrote a single line of code:
Drawing this out loud is what actually made the fix click for the interviewer too , once he could see that "factor" was the one place both numbers and signs and parentheses all funnel through, the unary bug stopped looking mysterious. Here's the version I ended up with, cleaned up slightly from my messier whiteboard version but logically identical:
public class ExpressionEvaluator {
private final String s;
private int pos;
private ExpressionEvaluator(String s) {
this.s = s;
}
public static int evaluate(String expression) {
ExpressionEvaluator e = new ExpressionEvaluator(expression);
int result = e.parseExpr();
return result;
}
private int parseExpr() {
int value = parseTerm();
skipSpaces();
while (pos < s.length() && (peek() == '+' || peek() == '-')) {
char op = s.charAt(pos++);
int rhs = parseTerm();
value = (op == '+') ? value + rhs : value - rhs;
skipSpaces();
}
return value;
}
private int parseTerm() {
int value = parseFactor();
skipSpaces();
while (pos < s.length() && (peek() == '*' || peek() == '/')) {
char op = s.charAt(pos++);
int rhs = parseFactor();
value = (op == '*') ? value * rhs : value / rhs;
skipSpaces();
}
return value;
}
private int parseFactor() {
skipSpaces();
char c = peek();
if (c == '+') { pos++; return parseFactor(); }
if (c == '-') { pos++; return -parseFactor(); }
if (c == '(') {
pos++;
int value = parseExpr();
skipSpaces();
if (pos >= s.length() || peek() != ')')
throw new IllegalArgumentException("Missing ')'");
pos++; // consume ')'
return value;
}
int start = pos;
while (pos < s.length() && Character.isDigit(peek())) pos++;
return Integer.parseInt(s.substring(start, pos));
}
private char peek() { return s.charAt(pos); }
private void skipSpaces() { while (pos < s.length() && s.charAt(pos) == ' ') pos++; }
}
I ran this against the interview's own example along with a handful of edge cases I threw at it live nested parens like (1+(4+5+2)-3)+(6+8), double signs like --5 and extra whitespace scattered through the string. Every single one came back correct, including the original 41.
Follow-Up Questions I Got and What I Said
"What's the time and space complexity of your solution?"
I said O(n) time, since every character gets visited a constant number of times across the recursive calls and O(n) space in the worst case for the recursion stack, which grows with how deeply nested the parentheses are.
"How would you handle an invalid expression, like unbalanced parentheses?"
I added a check at the end of parsing an expression inside parentheses if I don't find a closing ) where I expect one, I throw a clear exception instead of silently returning a wrong number. Same idea for division by zero.
"What if the numbers could overflow a normal int?"
I said I'd switch the accumulator type to long internally and only narrow back to int at the very end if the problem guarantees the final result fits, which avoids silent overflow during intermediate multiplication steps.
"Could you extend this to support exponentiation, like ^?"
Yes I said I'd add one more precedence layer above term/factor, since ^ binds tighter than * and / and I'd need to make it right-associative (unlike the others), since 2^3^2 should evaluate right to left as 2^(3^2), not left to right.
Round 1 ran a little long, closer to 50 minutes than 45, mostly because of my two false starts. I walked away not fully sure I'd cleared the bar, since it was flagged as eliminatory and I'd stumbled twice in front of the interviewer instead of once quietly in my own head.
Round 2: Low-Level Design ~ Library Management System
This round felt like a reward after Round 1's pressure more of a conversation, less of a ticking clock.
The problem: design a Library Management System. Members, books, borrowing, returning and the interviewer was explicit that he wanted to go past a class diagram and actually talk about how it would be implemented.
My Mistake: Collapsing Book and Copy Into One Thing
I started by sketching a Book class with a title, author, ISBN and a boolean isAvailable flag. It felt clean. It also fell apart the second he asked, "What happens when the library owns three copies of the same book?"
I sat with that for a second, because my design had no way to represent "three physical things that are the same book." A single boolean on one Book object can't tell you that two copies are checked out while one sits on the shelf. That was the hint, delivered as a completely reasonable follow-up question rather than a correction.
The Fix: Separate the Idea of a Book from a Physical Copy
The real design splits Book (title, author, ISBN the abstract "work") from BookItem (one physical, barcoded copy with its own status: available, loaned, lost or reserved). A Library holds many BookItems per ISBN. Borrowing means finding any available BookItem for that ISBN, not touching some shared flag on the book itself.
This is close to the class diagram I ended up drawing once the Book vs. BookItem split clicked:
class Book {
String isbn, title, author;
}
class BookItem {
String barcode;
Book book;
Status status; // AVAILABLE, LOANED, LOST, RESERVED
}
class Loan {
BookItem item;
Member member;
LocalDate borrowedOn;
LocalDate returnedOn;
}
class Library {
Map<String, List<BookItem>> copiesByIsbn;
Optional<Loan> borrow(String isbn, Member member) {
for (BookItem item : copiesByIsbn.get(isbn)) {
if (item.status == Status.AVAILABLE) {
item.status = Status.LOANED;
return Optional.of(new Loan(item, member, today()));
}
}
return Optional.empty(); // no copy currently free
}
}
I walked through the whole flow with him: a member requests a book by ISBN, the library scans its copies for that ISBN, hands out the first available one and flips its status. Returning does the reverse and frees the member's loan slot. I also added a simple cap a member can't hold more than five active loans at once since he'd asked earlier how the design would stop one person from hoarding every copy in the building.
We also talked about extensibility. If e-books needed to be added later, BookItem could become an interface with PhysicalBookItem and DigitalBookItem implementations, so the core borrowing logic barely changes only how a specific type of item is checked out and returned.
Follow-Up Questions I Got and What I Said
"How would you support a reservation or hold queue, if someone wants a book that's fully checked out right now?"
I said I'd add a queue of waiting members per ISBN. The moment a BookItem for that ISBN comes back and flips to AVAILABLE, the system checks the queue first before it's offered to a walk-in request.
"What if two members try to borrow the very last available copy at the exact same time?"
I said the borrow method needs to be thread-safe either by synchronizing on the list of copies for that ISBN or by using a data structure with atomic "take one item and mark it loaned" semantics, so two threads can't both read "available" and both proceed.
"How do you handle a lost book?"
I added a LOST status on BookItem, separate from LOANED, so it's permanently removed from the available pool without pretending it might come back on its own and I mentioned this is naturally where a fines/billing service would hook in as a separate concern, not bolted onto BookItem itself.
This round finished close to on time and it was the one I felt best about walking out of.
Round 3: High-Level Design : E-commerce Shopping System
This was the round with the most moving parts and also the one with the numbers.
The requirements: search, filter and sort products; view product details, purchase products with a secure checkout, integrate with an existing Inventory Management System through APIs.
The scale they gave me:
| Metric | Value |
|---|---|
| Product catalog size | 10M products |
| Daily active users | 1M users/day |
| Traffic | ~11 requests/sec |
| Orders | 10K orders/hour (~2.5 orders/sec) |
| Products per order | 5–10 |
My Mistake: Reaching for One Database to Rule Everything
My first instinct was to sketch one relational database holding products, users and orders and build everything on top of it. It's the comfortable default and it's also wrong the moment your read patterns and your write patterns pull in completely different directions.
He pushed on it gently: "How would you search across 10 million products by keyword, filter and sort using that same database?" I started describing increasingly creative SQL queries and heard myself getting less and less confident with every sentence. That was the hint. A single relational store can technically do full-text search, but it was never built to do it well at this scale and trying to force it there was going to cost me the rest of the round defending a weak choice.
The Fix: Split Storage by What Each Piece Actually Needs
I redrew the architecture around a simple question for each responsibility: what does this actually need from its data store?
Product search and filtering went to a search-optimized index (something like Elasticsearch) built for exactly this fast full-text search, filters and sorting over millions of documents. Product catalog details (price, description, images) sat in a document or relational store behind a cache, since reads massively outnumber writes for browsing traffic. Orders and payments stayed in a strongly consistent relational database, because money and inventory correctness can't tolerate the eventual-consistency tradeoffs that make the search side scale so easily.
Here's roughly the shape the architecture took once I split it this way:
+---------------------+
| Client / Browser |
+----------+----------+
|
v
+---------------------+
| API Gateway |
+----+-----+-----+----+
| | |
+-------------+ | +-------------+
v v v
+----------------+ +--------------+ +--------------------+
| Product Catalog| | Search | | Order / Checkout |
| Service | | Service | | Service |
+--------+-------+ +------+-------+ +----+-----+-----+---+
| | | | |
+--------+--------+ v v | v
v v +-----------+ +--------+ | +--------+
+-----------+ +---------+ Search | | Orders | | |Payment |
| Cache | | Product | Index | | DB | | |Service |
| (Redis) | | DB +-----------+ +--------+ | +--------+
+-----------+ +---------+ v
+----------------+
| Message Queue |
| (async) |
+-------+--------+
|
v
+----------------+
|Inventory Service|
+-------+--------+
|
v
+----------------+
| Inventory DB |
+----------------+
At 11 requests/sec average for browsing traffic, a solid cache in front of product reads absorbs almost all of it, since most of those 1M daily users are looking at a fairly small set of popular products. I mentioned that average numbers hide the real problem real traffic spikes 3 to 5x above average during sales or promotions, so I'd size caching and the search layer for peak, not for the calm 11 requests/sec they'd handed me.
The Overselling Problem (Another Mistake, Caught Faster This Time)
When we got to checkout, I initially described decrementing inventory directly inside the order-creation transaction: read the current stock, check it's above zero, subtract one, save. He asked, "What happens if two customers hit 'buy' on the very last unit at the same instant?" I paused, actually traced through it and admitted out loud that a plain read-then-write like that has a race condition both requests could read "1 in stock" before either one writes back and both would succeed, overselling by one unit.
I fixed it by describing optimistic concurrency: give each inventory row a version number and only let the decrement succeed if the version hasn't changed since it was read; otherwise, retry. I also mentioned idempotency keys for the checkout API itself, so a user double-clicking "Pay" or a retried network request doesn't accidentally create two orders for the same purchase.
Follow-Up Questions I Got and What I Said
"At 10M products today, how would this scale to 100M?"
I said the search index shards horizontally by product ID or category, which is exactly the kind of scaling Elasticsearch-style systems are built for and the cache layer scales the same way more nodes, consistent hashing to spread the keys.
"How does the checkout flow integrate with the existing Inventory Management System without tightly coupling the two?"
I said through an API contract, ideally with an asynchronous event (like "order placed") published to a queue, so the inventory system can consume it and update stock without the checkout flow blocking on a slow downstream call.
"Why not put everything behind one cache and skip the dedicated search index?"
Because a cache is great for "give me exactly this key back fast," but search needs relevance ranking, partial matches and filtering across many fields at once a cache doesn't do that job, a search index is built specifically for it.
This round ran the full 45 minutes and then some and it was the one where I felt the most back-and-forth pressure, in a good way every answer led to one more "but what about."
Round 4: Managerial ~ Resume, Behavior and a Short Design Tail
By this point I was mentally tired in a way that's hard to explain unless you've done a full-day loop. This round felt different in tone immediately slower, more conversational, less about catching a technical gap and more about understanding how I actually work.
He walked through my resume line by line and asked me to go deep on a couple of past projects what I built, what tradeoffs I made and why. That part felt natural, since it was my own work.
some other questions are :
"How do you handle mentoring someone more junior than you?"
I talked about pairing on real tasks instead of just reviewing finished code and being explicit about the reasoning behind a decision, not just the decision itself, since that's what actually transfers.
"Why Microsoft, specifically?"
I kept this one honest and specific to me, tied to the kind of systems and scale I wanted to work on next, rather than reciting anything that sounded like it came from a careers page.
A short system design question at the end:
he asked a lighter, quicker design question nothing near the depth of Round 3 mostly, I think, to see if I could still reason clearly after three back-to-back technical rounds and a full resume discussion. I treated it the same way I had all day: state assumptions out loud, sketch the simplest version first, then layer in complexity only where the requirements actually demanded it.
This round ran close to 45 minutes and felt more like a real conversation than an evaluation, which I think is exactly the point of a managerial round done well.
Biggest Learnings
Looking back at all four rounds together, my mistakes weren't random. Every one of them was some version of reaching for the simplest possible answer too early equal-precedence parsing, one Book class instead of two, one database for every kind of data, one vague behavioral answer instead of one specific story. And every single time, the interviewer didn't correct me directly. They asked a question that made the gap in my own answer obvious to me and let me close it myself.
That's worth internalizing if you're prepping for something similar: getting a follow-up question isn't a sign you're failing. It's usually a sign they're giving you room to go from "an answer" to "the right answer."
Preparation Tips
Practice writing a recursive descent parser from scratch at least once before a coding round like this the term/factor/expression split for handling precedence and unary operators is a pattern, not a trick and it's worth having in your hands, not just in your head.
Before any LLD round, ask yourself early whether you're modeling "the abstract thing" or "one instance of that thing" Book vs. BookItem is the same shape of question you'll see again and again in inventory systems, ride-sharing systems, parking lot systems, almost anything with countable, individually-trackable units.
For HLD rounds, let the given scale numbers actually drive your decisions instead of decorating a design you'd already picked in your head. If you're handed request-per-second numbers, use them say out loud why a number that small doesn't need a message queue or why a number that large does.
Prepare two or three real, specific stories for behavioral questions ahead of time, with a clear before/decision/after shape. Don't wait for the interviewer to ask you to be specific lead with specifics the first time.
Expect to be wrong at least once. I was wrong in three of four rounds and still got the offer. What seemed to matter more than never making a mistake was how I responded the moment a question exposed one did I get defensive or did I actually think it through out loud and fix it.
FAQs
1. How many rounds are there in the Microsoft SWE interview loop?
In my loop it was 4 rounds, all roughly 45 minutes: one coding round, one low-level design (LLD) round, one high-level design (HLD) round and one managerial round. The exact mix can vary by team and level, but coding plus LLD plus HLD is a common pattern for a full-loop SWE interview at Microsoft.
2. Is the coding round eliminatory?
Mine was flagged as eliminatory going in, meaning a weak performance there could end the loop regardless of how the later rounds went. Treat any round you're told is eliminatory as the one to be most rested and warmed up for.
3. Does Microsoft ask both LLD and HLD in the same loop?
Yes, in my case they were two separate rounds back to back LLD focused on class-level design (entities, relationships, extensibility), HLD focused on system-level architecture (services, data stores, scale, APIs). They test different muscles, so it's worth prepping for them separately rather than treating "system design" as one bucket.
4. What does the L62 level mean and does it change what's asked?
L62 is one of Microsoft's internal engineering level labels; exact scope and expectations can vary by org and team, so I wouldn't over-index on the number itself. What I noticed in my loop was a strong emphasis on reasoning through a design out loud, past just landing on a correct-looking diagram that bar tends to rise with seniority more than the specific topics do.
5. How hard is the Microsoft SWE interview?
I'd call it a solid 4 out of 5. None of the individual questions were obscure or trick-based, but every round had at least one follow-up that pushed past the first correct-sounding answer and I made a mistake in three of the four rounds. It rewards depth and the ability to recover in real time more than it rewards knowing the "right" answer instantly.
6. What should I focus on most when preparing for the design rounds?
Practice starting simple and letting the interviewer's follow-up questions pull out the complexity, rather than trying to front-load every edge case into your first answer. In my experience, that's closer to how these rounds are actually structured.
Conclusion
Four rounds, three mistakes and an offer at the end of it. If you take one thing from this, let it be that an interviewer asking "but what about X" is not the interview going badly more often, it's the interview doing exactly what it's supposed to do.
