Machine Coding Round Strategy for LLD Interviews
TL;DR
Machine coding rounds require you to write complete, runnable code in 60-90 minutes, unlike whiteboard OOD which focuses on design discussions. Success depends on structured time management, knowing when to code vs. design, and delivering working software with clean architecture rather than perfect design.
Core Concept
What Makes Machine Coding Different
Machine coding rounds test your ability to write working code under time pressure while maintaining reasonable design quality. Unlike whiteboard OOD interviews where you discuss architecture and draw diagrams, here you must produce executable code that an interviewer can run and test.
The key difference: delivery matters more than perfection. A working solution with 80% design quality beats a beautifully architected solution that doesn’t run.
The 60-90 Minute Challenge
Most machine coding rounds give you 60-90 minutes to build a small application (parking lot, chess game, splitwise). This time constraint forces trade-offs:
- You can’t implement every design pattern you know
- You must prioritize core functionality over edge cases
- Code organization matters, but extensive refactoring is a luxury
- Testing is often manual demonstration rather than unit tests
The Three Phases Approach
Phase 1: Clarify & Design (15-20 minutes)
- Understand requirements and ask clarifying questions
- Identify core entities and their relationships
- Sketch a basic class structure (on paper or comments)
- Define the main operations/APIs needed
Phase 2: Build Core (35-45 minutes)
- Start with data models (classes with attributes)
- Implement the most critical use case end-to-end
- Get something runnable as quickly as possible
- Add remaining features incrementally
Phase 3: Polish & Demo (10-15 minutes)
- Add input validation for demonstrated scenarios
- Clean up obvious code smells
- Prepare a demo script showing key features
- Test the happy path thoroughly
Project Structure That Scales
Even in 60 minutes, organize your code into logical files:
project/
├── models/ # Core entities (User, Ride, Vehicle)
├── services/ # Business logic (RideService, PaymentService)
├── managers/ # Orchestration (RideManager)
└── main.py # Demo/driver code
This structure shows design thinking without over-engineering.
Visual Guide
Machine Coding Round Timeline
gantt
title 90-Minute Machine Coding Timeline
dateFormat mm
axisFormat %M min
section Clarify
Understand requirements :00, 5m
Ask questions :05, 5m
Sketch design :10, 10m
section Build
Create models :20, 15m
First working feature :35, 20m
Add remaining features :55, 20m
section Polish
Test & fix bugs :75, 10m
Prepare demo :85, 5m
Recommended time allocation for a 90-minute machine coding round. Adjust proportionally for 60-minute rounds.
Code Organization Strategy
graph TD
A[Start Coding] --> B{Can I run something?}
B -->|No| C[Build simplest model]
C --> D[Add one operation]
D --> B
B -->|Yes| E{All features done?}
E -->|No| F[Add next feature]
F --> E
E -->|Yes| G[Polish & test]
G --> H[Demo ready]
style B fill:#ffe6e6
style E fill:#ffe6e6
style H fill:#e6ffe6
Iterative approach: get something running first, then add features incrementally.
Examples
Example 1: Parking Lot - Time-Boxed Implementation
Problem: Design a parking lot system that can park and unpark vehicles.
15-Minute Design Phase Output (comments as design):
# models/vehicle.py
class Vehicle:
"""Represents a vehicle with type and license plate"""
pass
# models/parking_spot.py
class ParkingSpot:
"""A spot that can hold one vehicle"""
pass
# services/parking_service.py
class ParkingService:
"""Handles parking and unparking logic"""
def park_vehicle(self, vehicle):
# Find available spot
# Assign vehicle to spot
# Return ticket
pass
def unpark_vehicle(self, ticket):
# Find spot by ticket
# Remove vehicle
# Calculate fee
pass
45-Minute Build Phase Output (working code):
# models/vehicle.py
from enum import Enum
class VehicleType(Enum):
BIKE = 1
CAR = 2
TRUCK = 3
class Vehicle:
def __init__(self, license_plate, vehicle_type):
self.license_plate = license_plate
self.vehicle_type = vehicle_type
# models/parking_spot.py
class ParkingSpot:
def __init__(self, spot_id, spot_type):
self.spot_id = spot_id
self.spot_type = spot_type # VehicleType
self.vehicle = None
self.is_occupied = False
def park(self, vehicle):
if self.is_occupied:
return False
if vehicle.vehicle_type != self.spot_type:
return False
self.vehicle = vehicle
self.is_occupied = True
return True
def unpark(self):
self.vehicle = None
self.is_occupied = False
# models/ticket.py
import time
class Ticket:
def __init__(self, spot_id, vehicle):
self.ticket_id = f"{spot_id}_{int(time.time())}"
self.spot_id = spot_id
self.vehicle = vehicle
self.entry_time = time.time()
# services/parking_service.py
class ParkingService:
def __init__(self):
self.spots = []
self.tickets = {}
def add_spot(self, spot):
self.spots.append(spot)
def park_vehicle(self, vehicle):
# Find first available spot of matching type
for spot in self.spots:
if not spot.is_occupied and spot.spot_type == vehicle.vehicle_type:
if spot.park(vehicle):
ticket = Ticket(spot.spot_id, vehicle)
self.tickets[ticket.ticket_id] = ticket
return ticket
return None # No spot available
def unpark_vehicle(self, ticket_id):
if ticket_id not in self.tickets:
return None
ticket = self.tickets[ticket_id]
for spot in self.spots:
if spot.spot_id == ticket.spot_id:
spot.unpark()
del self.tickets[ticket_id]
# Simple fee calculation
duration = time.time() - ticket.entry_time
fee = int(duration / 3600) * 10 # $10 per hour
return fee
return None
# main.py - Demo
if __name__ == "__main__":
service = ParkingService()
# Setup parking lot
service.add_spot(ParkingSpot("B1", VehicleType.BIKE))
service.add_spot(ParkingSpot("C1", VehicleType.CAR))
service.add_spot(ParkingSpot("C2", VehicleType.CAR))
# Park vehicles
car1 = Vehicle("ABC123", VehicleType.CAR)
ticket1 = service.park_vehicle(car1)
print(f"Parked car, ticket: {ticket1.ticket_id}")
bike1 = Vehicle("XYZ789", VehicleType.BIKE)
ticket2 = service.park_vehicle(bike1)
print(f"Parked bike, ticket: {ticket2.ticket_id}")
# Unpark
fee = service.unpark_vehicle(ticket1.ticket_id)
print(f"Unparked car, fee: ${fee}")
Expected Output:
Parked car, ticket: C1_1703001234
Parked bike, ticket: B1_1703001235
Unparked car, fee: $0
What This Demonstrates:
- Working code in ~45 minutes
- Clear separation: models, services, demo
- Core functionality: park, unpark, fee calculation
- Extensible design (can add more spot types)
What’s Intentionally Missing (to save time):
- No floors/levels (can add if time permits)
- No payment processing (mentioned in comments)
- Minimal error handling (just None returns)
- No persistence (in-memory only)
Example 2: Ride Sharing - Incremental Feature Addition
Core Implementation (first 30 minutes):
# models/user.py
class User:
def __init__(self, user_id, name):
self.user_id = user_id
self.name = name
class Rider(User):
pass
class Driver(User):
def __init__(self, user_id, name, vehicle_number):
super().__init__(user_id, name)
self.vehicle_number = vehicle_number
self.is_available = True
# models/ride.py
from enum import Enum
class RideStatus(Enum):
REQUESTED = 1
ONGOING = 2
COMPLETED = 3
class Ride:
def __init__(self, ride_id, rider, source, destination):
self.ride_id = ride_id
self.rider = rider
self.driver = None
self.source = source
self.destination = destination
self.status = RideStatus.REQUESTED
def assign_driver(self, driver):
self.driver = driver
self.status = RideStatus.ONGOING
def complete(self):
self.status = RideStatus.COMPLETED
if self.driver:
self.driver.is_available = True
# services/ride_service.py
class RideService:
def __init__(self):
self.rides = {}
self.drivers = []
self.ride_counter = 1
def add_driver(self, driver):
self.drivers.append(driver)
def request_ride(self, rider, source, destination):
ride = Ride(f"R{self.ride_counter}", rider, source, destination)
self.ride_counter += 1
# Simple matching: first available driver
for driver in self.drivers:
if driver.is_available:
ride.assign_driver(driver)
driver.is_available = False
break
self.rides[ride.ride_id] = ride
return ride
def complete_ride(self, ride_id):
if ride_id in self.rides:
self.rides[ride_id].complete()
return True
return False
# main.py
if __name__ == "__main__":
service = RideService()
# Add drivers
driver1 = Driver("D1", "John", "CAR123")
driver2 = Driver("D2", "Jane", "CAR456")
service.add_driver(driver1)
service.add_driver(driver2)
# Request rides
rider1 = Rider("R1", "Alice")
ride1 = service.request_ride(rider1, "LocationA", "LocationB")
if ride1.driver:
print(f"Ride {ride1.ride_id} assigned to {ride1.driver.name}")
else:
print(f"Ride {ride1.ride_id} waiting for driver")
# Complete ride
service.complete_ride(ride1.ride_id)
print(f"Ride {ride1.ride_id} completed")
Expected Output:
Ride R1 assigned to John
Ride R1 completed
Next 15 Minutes - Add Pricing (if time permits):
# services/pricing_service.py
class PricingService:
BASE_FARE = 50
PER_KM = 10
@staticmethod
def calculate_fare(distance_km):
return PricingService.BASE_FARE + (distance_km * PricingService.PER_KM)
# Update Ride model
class Ride:
def __init__(self, ride_id, rider, source, destination, distance_km=5):
# ... existing code ...
self.distance_km = distance_km
self.fare = None
def complete(self):
self.status = RideStatus.COMPLETED
self.fare = PricingService.calculate_fare(self.distance_km)
if self.driver:
self.driver.is_available = True
# Updated demo
ride1 = service.request_ride(rider1, "LocationA", "LocationB")
service.complete_ride(ride1.ride_id)
print(f"Fare: ${ride1.fare}")
Try it yourself: Add a rating system where riders can rate drivers (1-5 stars) after completing a ride. Store ratings with the driver and calculate average rating.
Common Mistakes
1. Over-Designing Before Coding
Mistake: Spending 30-40 minutes designing the perfect class hierarchy with multiple design patterns before writing any code.
Why it’s bad: You risk running out of time with nothing runnable to show. Interviewers value working code over theoretical perfection.
Fix: Spend max 15-20 minutes on design. Start with simple classes and refactor as you go. Your first version should be runnable within 30 minutes.
2. Building Everything in One File
Mistake: Writing all classes in main.py or a single file, creating a 500-line monolith.
Why it’s bad: Shows poor code organization skills. Makes it hard for interviewers to navigate your code. Signals lack of real-world project experience.
Fix: Even in 60 minutes, create separate files for models, services, and demo code. This takes 2 extra minutes but demonstrates professional habits.
# Bad - everything in one file
# main.py (500 lines)
class User: ...
class Ride: ...
class RideService: ...
if __name__ == "__main__": ...
# Good - organized structure
# models/user.py
# models/ride.py
# services/ride_service.py
# main.py (demo only)
3. No Working Demo Until the End
Mistake: Writing all classes and methods, then trying to run the code for the first time at minute 85.
Why it’s bad: You discover bugs too late to fix them. If you run out of time, you have nothing to demonstrate.
Fix: Get something runnable by minute 30. Even if it’s just creating objects and printing them. Build incrementally with frequent testing.
# Minute 30 - should have this working:
user = User("U1", "Alice")
print(f"Created user: {user.name}") # Test immediately
# Minute 45 - should have core feature:
ride = service.request_ride(user, "A", "B")
print(f"Ride status: {ride.status}") # Verify it works
4. Ignoring the Happy Path
Mistake: Implementing extensive error handling and edge cases (“What if the user enters a negative distance?”) before the main functionality works.
Why it’s bad: You waste time on 20% cases while the 80% core functionality remains incomplete.
Fix: Make the happy path work first. Add validation only for cases you’ll demonstrate. Use simple checks (if/else) rather than custom exception hierarchies.
# Bad - premature error handling
def park_vehicle(self, vehicle):
if not vehicle:
raise InvalidVehicleException("Vehicle cannot be None")
if not isinstance(vehicle, Vehicle):
raise TypeError("Expected Vehicle instance")
# ... more validation ...
# Good - simple validation for demo
def park_vehicle(self, vehicle):
if not vehicle:
return None
# Core logic here
5. Not Preparing a Demo Script
Mistake: Finishing code at minute 88 and saying “Let me just run this…” without knowing what to demonstrate.
Why it’s bad: You fumble during demo, forget to show key features, or discover bugs while the interviewer watches.
Fix: In the last 10 minutes, write a clear demo in main.py that shows each feature. Test it once before presenting.
# main.py - Clear demo script
if __name__ == "__main__":
print("=== Parking Lot Demo ===")
print("\n1. Setup parking lot")
service = ParkingService()
service.add_spot(ParkingSpot("C1", VehicleType.CAR))
print("Added 1 car spot")
print("\n2. Park a car")
car = Vehicle("ABC123", VehicleType.CAR)
ticket = service.park_vehicle(car)
print(f"Ticket issued: {ticket.ticket_id}")
print("\n3. Unpark the car")
fee = service.unpark_vehicle(ticket.ticket_id)
print(f"Fee charged: ${fee}")
Interview Tips
Time Management Strategy
Set hard time boundaries: Use your phone/watch to set alarms:
- 15 min: Design phase must end, start coding
- 30 min: First runnable code checkpoint
- 60 min: All core features done, start polish
- 75 min: Stop adding features, test only
Communicate your timeline: Tell the interviewer, “I’m planning to spend 15 minutes on design, 45 on implementation, and 15 on testing. Does that sound reasonable?” This shows planning skills.
What to Code First
Start with the data model: Classes with attributes and simple constructors. This gives you building blocks.
# Start here (5 minutes)
class Vehicle:
def __init__(self, license_plate, vehicle_type):
self.license_plate = license_plate
self.vehicle_type = vehicle_type
Then add one complete operation: Pick the most important use case and implement it end-to-end. For a parking lot, that’s parking a vehicle.
Finally add remaining features: Once you have one working flow, adding others is faster.
Strategic Shortcuts
Use simple data structures: Don’t build a custom HashMap when Python’s dict works fine. Don’t implement a priority queue when a sorted list suffices for your demo.
Hardcode reasonable values: Instead of complex distance calculations, use distance_km=5 as a parameter. Instead of real-time pricing, use fixed rates.
Skip persistence: In-memory storage is fine. Don’t waste time on database code or file I/O unless explicitly required.
Defer complex algorithms: If the problem needs matching riders to drivers, start with “first available driver” logic. Mention “In production, we’d use location-based matching” but don’t implement it.
Communication During Coding
Think aloud briefly: When starting a new class or method, say “Now I’m implementing the parking logic” but don’t narrate every line.
Ask clarifying questions early: “Should I handle multiple vehicle types or just cars?” “Do you want me to implement payment processing or just calculate the fee?”
Show your priorities: “I’m going to implement parking and unparking first, then add pricing if time permits.”
Acknowledge trade-offs: “I’m using a simple list search here. In production, I’d use a HashMap for O(1) lookup, but for this demo, the list is clearer.”
The Demo Presentation
Walk through your structure first: “I’ve organized the code into models, services, and a demo. Let me show you the main classes…”
Run the happy path: Show the main use case working end-to-end.
Highlight design decisions: “I used the Strategy pattern here for pricing” or “I separated the service layer to keep business logic independent.”
Be honest about limitations: “Given more time, I’d add validation for X and implement Y. But the core functionality is working.”
Language-Specific Tips
Python: Use dataclasses for simple models to save time. Leverage built-in collections (defaultdict, Counter).
from dataclasses import dataclass
@dataclass
class Vehicle:
license_plate: str
vehicle_type: str
Java: Use ArrayList and HashMap from collections. Don’t waste time on custom data structures. Use enums for types.
C++: Use STL containers (vector, map). Avoid manual memory management unless necessary. Use smart pointers if you need dynamic allocation.
What Interviewers Actually Evaluate
- Does it run? (40% weight) - Working code beats perfect design
- Is it organized? (30% weight) - Clear structure, separation of concerns
- Is it extensible? (20% weight) - Can new features be added easily?
- Is it clean? (10% weight) - Readable names, reasonable methods
Not evaluated heavily: Perfect design patterns, comprehensive error handling, optimal algorithms (unless specified), extensive testing.
Recovery Strategies
If you’re behind at 45 minutes: Cut features. Implement the absolute minimum viable product. Tell the interviewer: “I’m going to focus on getting parking/unparking working, and skip the pricing feature.”
If you have a bug at 80 minutes: Don’t panic. Comment out the broken feature and demo what works. Say: “There’s a bug in the pricing calculation I’d need more time to debug, but let me show you the core parking functionality.”
If you finish early: Don’t add complex features. Instead, refactor for clarity, add comments, or implement simple validation. Ask the interviewer: “I have 15 minutes left. Would you like me to add [feature X] or improve [aspect Y]?”
Key Takeaways
-
Working code beats perfect design: Deliver a runnable solution in 60-90 minutes rather than an incomplete architectural masterpiece. Interviewers can run and test your code, which demonstrates competence more than diagrams.
-
Follow the 15-45-15 rule: Spend 15 minutes clarifying and designing, 45 minutes building core features, and 15 minutes polishing and preparing your demo. Set alarms to enforce these boundaries.
-
Get something running by minute 30: Build incrementally with frequent testing. Your first checkpoint should be a simple but complete operation (e.g., parking one vehicle) that you can demonstrate.
-
Organize code into logical files from the start: Separate models, services, and demo code even in a 60-minute round. This takes minimal extra time but shows professional software engineering habits.
-
Prioritize the happy path and defer edge cases: Make the main use case work perfectly before adding validation, error handling, or complex features. Strategic shortcuts (hardcoded values, simple algorithms) are acceptable when communicated clearly.