How to approach machine coding interviews
A practical framework for machine coding rounds, from reading the problem to delivering compilable, well-structured code in 60-90 minutes.
The problem statement lands in your inbox. You have 90 minutes to build a working splitwise clone. From scratch. It must compile. It must run. It must handle edge cases. And someone is going to read every line you wrote.
Most candidates fail machine coding rounds not because they can't code, but because they can't scope. They spend 40 minutes building perfect model classes, then panic-write a giant main() method with zero structure. Or they architect an entire Spring Boot app and run out of time before anything actually runs. The fix is a repeatable system for turning a problem statement into working software under pressure.
This guide gives you that system. Six phases, clear time budgets, and concrete signals of what good output looks like at every stage.
What is a machine coding round?
A machine coding round is a timed coding exercise (typically 60-90 minutes) where you receive a problem statement and must produce compilable, runnable code that solves it. Think of it as a take-home assignment, but you do it live with a clock ticking.
Examples of real machine coding problems:
- Build a splitwise-like expense sharing app
- Implement a parking lot management system
- Create a task management board (like Trello)
- Build a snake-and-ladder game engine
- Implement a simple in-memory key-value store with TTL
The output is not a design doc. It's not a whiteboard sketch. It's actual code that an evaluator will clone, compile, and run. Then they'll read it line by line.
The most common surprise
Many candidates confuse this with an OOD round and produce class diagrams and design notes instead of runnable code. The evaluator will try to compile your submission. If it doesn't compile, you're likely rejected regardless of how elegant the design looks on paper.
How it differs from OOD
If you've prepared for OOD interviews, you're halfway there. But machine coding flips the weight distribution. OOD is 60% design discussion, 40% code. Machine coding is 80% working code, 20% design.
| Dimension | OOD interview | Machine coding round |
|---|---|---|
| Duration | 45-60 minutes | 60-90 minutes |
| Format | Live discussion with interviewer | Solo coding (often offline) |
| Primary output | Class diagram + key classes | Full working application |
| Code expectation | 60-100 lines of core classes | 200-400 lines of runnable code |
| Must compile? | Nice to have | Non-negotiable |
| Design discussion | Extensive, verbal | Minimal, shown through code structure |
| Evaluation | Real-time by interviewer | Post-submission code review |
The biggest mental shift: in OOD, you explain your design verbally. In machine coding, your code is the explanation. Every class name, every method signature, every package structure is a design decision the evaluator will judge silently.
I've seen candidates who ace OOD rounds and bomb machine coding because they can talk about the Strategy pattern all day but can't wire it up under time pressure. The reverse also happens. Strong coders who never name a pattern still pass machine coding because their code demonstrates the principles implicitly.
The 6-phase framework
Here is the framework I use and recommend for every machine coding problem. The time budget assumes a 90-minute round (scale proportionally for 60 minutes).
| Phase | Time | Output | You're behind if... |
|---|---|---|---|
| 1. Read and scope | 5 min | Annotated problem with must-haves circled | Still reading at minute 10 |
| 2. Entities and API | 10 min | Entity list + method signatures sketched | Can't name your top-level service method |
| 3. Core model | 15 min | Domain classes compiling | No code written by minute 30 |
| 4. Happy path | 20 min | One flow works end-to-end | Main method doesn't run at minute 55 |
| 5. Edge cases | 15 min | Validation and error handling | Adding features instead of hardening |
| 6. Demo | 5 min | Driver code showing multiple scenarios | No output printed to console |
Phase 1: Read the problem carefully (5 minutes)
Read the entire problem statement before writing a single line. I cannot stress this enough. Candidates lose 20+ minutes because they misread a requirement and built the wrong thing.
On your first read, classify every requirement:
- Must-have: explicitly stated, will be tested. "Users can add expenses and split equally."
- Should-have: implied or mentioned casually. "Support different split types."
- Skip: anything involving persistence, UI, networking, or deployment. "Bonus: add a REST API."
Write the must-haves as a bullet list at the top of your code file. This becomes your checklist. Every 20 minutes, glance at it and verify you're building what was asked.
The 80/20 of problem reading
Most machine coding problems have 3-4 core requirements and 2-3 stretch goals. Nail the core requirements completely before touching any stretch goal. A submission that does three things flawlessly beats one that does six things with bugs.
Phase 2: List entities and define the API (10 minutes)
Turn the problem statement into nouns (entities) and verbs (operations). For an expense-sharing app:
Entities: User, Expense, Split, ExpenseType (EQUAL, EXACT, PERCENT)
API (the public methods on your service):
addUser(userId, name, email)addExpense(paidBy, amount, splitType, participants, splits)showBalances(userId)
Don't build interfaces for everything. Don't create abstract factories. Write down the concrete classes you need and the methods they expose. This is your blueprint, and you have 10 minutes for it.
I keep this list as a comment block at the top of my main file. It helps me stay focused when I'm deep in implementation and tempted to add "just one more feature."
Phase 3: Build the core model (15 minutes)
Now write the domain classes. Start with enums and value objects since they're small, they compile instantly, and they give you the vocabulary for everything else.
Three rules for model classes in machine coding:
- Keep fields minimal. Only add what you'll actually use in logic. If no method reads
createdAt, don't add it. - Use records or simple classes. Java records are perfect here. Four lines, immutable, done.
- Compile after every class. Catch typos immediately, not 30 minutes later when you have 15 compilation errors stacked up.
// Compiles in 10 seconds. Move on.
public enum ExpenseType { EQUAL, EXACT, PERCENT }
public record User(String userId, String name, String email) {}
public record Split(String userId, double amount) {}
By the end of this phase, your model classes should compile and your IDE should show zero red. That's the only checkpoint that matters.
Phase 4: Implement the happy path (20 minutes)
This is the largest block and the most dangerous. The temptation is to handle every edge case as you go. Resist it. Build one complete flow, end to end, with zero error handling. Get something that runs.
For the expense-sharing example, the happy path is: add two users, create an equal-split expense, show balances. That's it. If this works, you have a foundation to build on.
Write a service class that implements the core operations. Wire it up with a main() method that calls those operations and prints output. Compile. Run. See output on the console.
public class ExpenseService {
private final Map<String, User> users = new HashMap<>();
private final Map<String, Double> balances = new HashMap<>();
public void addUser(String userId, String name, String email) {
users.put(userId, new User(userId, name, email));
balances.put(userId, 0.0);
}
public void addExpense(String paidBy, double amount,
ExpenseType type, List<String> participants) {
if (type == ExpenseType.EQUAL) {
double share = amount / participants.size();
for (String uid : participants) {
if (!uid.equals(paidBy)) {
balances.merge(uid, -share, Double::sum);
balances.merge(paidBy, share, Double::sum);
}
}
}
}
public void showBalances(String userId) {
double bal = balances.getOrDefault(userId, 0.0);
if (Math.abs(bal) < 0.01) {
System.out.println(userId + ": settled up");
} else {
System.out.printf("%s: %s%.2f%n", userId, bal > 0 ? "is owed " : "owes ", Math.abs(bal));
}
}
}
Notice what's missing: no EXACT or PERCENT split handling, no input validation, no error messages. That's intentional. Those come next.
My rule of thumb: if your main() method doesn't produce correct output by the 55-minute mark, stop everything and make it work. A running program with limited features beats a comprehensive program that crashes.
The compilation trap
Candidates who write 200 lines without compiling once spend their last 15 minutes fixing syntax errors instead of adding features. Compile every 5-10 minutes. The cost of a quick build is 10 seconds. The cost of debugging 15 stacked errors is 15 minutes.
Phase 5: Add edge cases and validation (15 minutes)
Now harden the code. Go through your requirements checklist and add:
- Input validation (null checks, invalid IDs, negative amounts)
- Additional split types (EXACT, PERCENT) if required
- Error messages that are human-readable
- Boundary conditions (splitting among one person, zero-amount expenses)
Prioritize by what the evaluator will test. If the problem says "support three split types," they will test all three. If it says "handle invalid input gracefully," they'll pass garbage and check your output.
Phase 6: Demonstrate with driver code (5 minutes)
Your main() method is your demo reel. It should tell a story:
public static void main(String[] args) {
ExpenseService service = new ExpenseService();
// Setup users
service.addUser("u1", "Alice", "alice@example.com");
service.addUser("u2", "Bob", "bob@example.com");
service.addUser("u3", "Charlie", "charlie@example.com");
// Scenario 1: Equal split
System.out.println("--- Equal split: Alice pays 300 for lunch ---");
service.addExpense("u1", 300, ExpenseType.EQUAL, List.of("u1", "u2", "u3"));
service.showBalances("u1");
service.showBalances("u2");
// Scenario 2: Show that balances accumulate
System.out.println("\n--- Another expense: Bob pays 600 ---");
service.addExpense("u2", 600, ExpenseType.EQUAL, List.of("u1", "u2", "u3"));
service.showBalances("u1");
service.showBalances("u2");
}
The driver code does three things: proves the app works, shows the evaluator how to use your API, and demonstrates that you tested more than one scenario. Name your scenarios with comments. Print section headers so the output is scannable.
Code quality signals
Your code will be read by a human, line by line. Here's what they're looking for:
| Signal | Why it matters | Quick win |
|---|---|---|
| Meaningful names | calculateShare() tells the evaluator what the method does. calc() tells them nothing. | Spend 5 extra seconds naming every method. |
| Small methods | A 50-line method is hard to read and review. Five 10-line methods with clear names are self-documenting. | Extract any block with an if or loop into a named method. |
| Package structure | Putting all classes in one file is acceptable but putting them in model/, service/, strategy/ packages shows you think about organization. | Create 2-3 packages. Even for a small project, it signals professionalism. |
| SOLID principles | You don't need to name them explicitly. If your service depends on an interface rather than a concrete class, the evaluator notices. | Use one interface for the most important variation point. |
| Enum over strings | ExpenseType.EQUAL cannot be misspelled. "equal" can. | Convert every fixed set of values into an enum immediately. |
One principle to prioritize above all others in machine coding: readability over cleverness. A straightforward for loop beats a chain of .stream().map().flatMap().collect() if the stream version takes the evaluator 30 seconds to parse. You're not writing production code for a team that knows your patterns. You're writing code for a stranger who has 10 minutes to read it.
What to skip
Time is the scarcest resource. Here's what you should explicitly not build:
| Skip this | Why |
|---|---|
| Database or file persistence | In-memory HashMap is perfectly fine. The evaluator cares about logic, not storage. |
| REST API or HTTP layer | Unless the problem specifically asks for it, a main() method is your API. |
| Authentication and authorization | Out of scope for machine coding. Mention it in comments if you want. |
| Complex UI | Console output is enough. Don't build a Swing app or HTML page. |
| Framework boilerplate | No Spring Boot, no dependency injection frameworks. Plain Java is faster. |
| Comprehensive error handling | Validate the obvious (null, negative amounts). Don't build a custom exception hierarchy. |
| Unit tests | Controversial, but in a 90-minute round, your driver code in main() is your test. Don't spend 20 minutes on JUnit setup. |
I've seen candidates spend 25 minutes setting up a Spring Boot project with Gradle, JPA entities, and repository interfaces. At the 90-minute mark, they had a beautiful project structure and zero working business logic. Don't be that person.
The 'mention and move on' technique
When you skip something deliberately, add a one-line comment: // In production: would add input validation for email format. This tells the evaluator you know it's missing and chose to skip it, rather than forgetting it exists.
Time management deep dive
The framework gives you time budgets, but real interviews don't go according to plan. Here's how to adapt.
When you're ahead of schedule: Don't add features. Improve what you have. Better variable names, extract a helper method, add a second scenario to your driver code. The evaluator will appreciate polished core logic more than half-baked extra features.
When you're behind schedule: Drop edge cases and go straight to the demo. A working program that handles the happy path is a passing submission. A non-compiling program that theoretically handles every edge case is a failing one.
When you're stuck on a bug: Set a 5-minute timer. If you can't fix it in 5 minutes, comment out the broken code, add a // TODO: fix split calculation comment, and move on. A program that runs with one feature missing is better than a program that doesn't run because of one bug.
The 60-minute checkpoint is your decision point in a 90-minute round. After 60 minutes, everything you do should converge toward a running demo. No new features. No new classes. Just make it work and make it readable.
Common pitfalls
1. Starting without any design
The opposite extreme of over-designing: opening your IDE and typing public class Main as your first action. Even 5 minutes of listing entities and sketching method signatures saves you from building the wrong thing. I've watched candidates rewrite their entire service class at minute 50 because they realized their data model was wrong. Five minutes of planning prevents that.
2. Gold-plating the model layer
Candidates who know design patterns well tend to over-engineer the model. They build abstract base classes, generic repositories, factory hierarchies, and visitor patterns before writing any business logic. Your User class doesn't need to implement Serializable, Comparable, and a custom Builder. It needs three fields and a constructor.
3. Not compiling frequently
If you write 150 lines of Java and then hit compile for the first time, you'll get 12 errors. Several will mask each other. You'll spend 15 minutes untangling them. Compile after every class. Compile after every method. The discipline of frequent compilation is worth more than any design pattern.
4. Handling edge cases before the happy path
"What if the amount is negative? What if the user doesn't exist? What if the split doesn't add up to 100%?" These are valid concerns, but addressing them before you have a working happy path is a time trap. Build the straight line through the system first. Add guardrails later.
5. Over-using design patterns
Machine coding evaluators want to see clean, working code, not a showcase of Gang of Four patterns. If your expense sharing app uses Strategy, Observer, Factory, Builder, and Decorator, the evaluator will wonder why a simple problem needed five patterns. Use one or two patterns where they genuinely reduce complexity. Keep the rest straightforward.
6. Forgetting the driver code
Your submission might be evaluated by someone who won't read your code first. They'll run main(), look at the output, and then dig into the source if the output looks correct. If main() prints nothing, or prints unformatted garbage, the first impression is terrible. Invest 5 minutes in clean driver code with labeled scenarios and readable output.
Machine coding evaluation rubric
Understanding what evaluators grade helps you allocate time wisely. Most companies score submissions across these dimensions:
| Dimension | Weight | What they look for |
|---|---|---|
| Correctness | 30% | Does it handle the stated requirements? Does the output match expected results? |
| Code structure | 25% | Are classes focused? Are responsibilities separated? Is the code navigable? |
| Readability | 20% | Naming, formatting, method sizes, comments where non-obvious |
| Extensibility | 15% | Could a new feature be added without rewriting existing code? |
| Completeness | 10% | Edge cases, validation, bonus requirements |
Notice that correctness and structure together are 55% of the score. A program that runs correctly with clean class separation will score higher than a program that handles every edge case but has all logic in one 300-line class.
For your interview: if you have to choose between "add one more feature" and "split this large class into two smaller ones," pick the refactor. Code structure points are easier to earn and harder to lose.
Comparing OOD and machine coding preparation
If you've already prepared for OOD interviews, here's how to adjust your approach for machine coding.
| Skill | OOD value | Machine coding value | Adjustment |
|---|---|---|---|
| Identifying entities | High | High | Same skill, directly transferable |
| Drawing class diagrams | High | Low | Skip diagrams. Your code IS the diagram. |
| Verbalizing trade-offs | High | Low | Write clean code instead of explaining it |
| Writing compilable code | Medium | Critical | Practice timed coding. A lot. |
| Time management | Important | Life or death | Use strict checkpoints. No negotiation. |
| Design patterns (named) | High | Medium | Use patterns, but don't name them unless asked |
| Driver/demo code | Not needed | Essential | Always write a comprehensive main() |
How to practice
The best practice for machine coding is simulated time pressure. Set a 90-minute timer and build one of these:
- Expense sharing app (Splitwise clone) - covers: multiple split strategies, balance tracking
- Parking lot system - covers: spot assignment, ticket lifecycle
- Snake and ladder game - covers: game state, turn management, board configuration
- In-memory key-value store with TTL - covers: data structures, time-based expiry
- Task management board - covers: state transitions, user assignment, filtering
After the timer stops, review your own code as if you're the evaluator. Ask yourself: does it compile? Does main() demonstrate the core features? Can I understand each class in under 30 seconds? Would I want to add a feature to this codebase?
The post-practice ritual
After each practice session, write down two things: what you should have skipped, and where you lost the most time. After five sessions, you'll have a personal list of time traps and a calibrated sense of what fits in 90 minutes.
Quick recap
- Machine coding rounds require compilable, runnable code. If it doesn't compile, the design doesn't matter.
- Follow the 6-phase framework: Read and Scope, Entities and API, Core Model, Happy Path, Edge Cases, Demo.
- Compile every 5-10 minutes. The single most underrated discipline in timed coding.
- Build the happy path first. A working program with limited features beats a broken program with comprehensive features.
- Skip persistence, frameworks, UI, and unit tests. In-memory data structures and console output are sufficient.
- Invest 5 minutes in clean driver code with labeled scenarios. It's your evaluator's first impression.
- Code structure and readability carry 45% of the evaluation weight. Clean code with fewer features beats messy code with more features.
- When in doubt at the 60-minute mark, stop adding and start polishing. Make it run, make it readable, ship it.