Machine Coding Problem

Food Delivery (Zomato-lite)

maco30maco60macoAllmarketplacestrategy-patternobserver-patternthread-safe-resource-acquisitionstate-transition-guards
Commonly Asked By:DoorDashUberSwiggyZomato

Functional Scope (In-Scope)

  • Order Status State Machine: Guarantee logical sequence state transitions: PLACED → CONFIRMED → PREPARING → PICKED_UP → DELIVERED.
  • Driver Proximity Strategies (Strategy Pattern): Support switching algorithms (e.g. Nearest-first, Highest Rated Driver) dynamically at runtime.
  • Observer Notifications: Enable live subscribers (Customer Alerts, Kitchen Dashboards) to receive event triggers dynamically upon order status transitions.
  • Atomic Resource Booking: Prevent double driver assignments on overlapping concurrent customer orders using atomic checks.
  • Real-Time ETA metrics: Calculate driver distances relative to target kitchens.

Explicit Boundaries (Out-of-Scope)

  • No Live SMS Phone Gateways: Excludes direct integration with Twilio, Sinch, or mobile network SMS headers.
  • No Real Card clearing Payment Gateway: Bypasses Stripe APIs, card charge authorizations, or actual bank settlement networks.

Clean reference designs showing delivery matching flows in Java and Python:

// ─── JAVA BLUEPRINT ──────────────────────────────────────────────────────────
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.*;

enum OrderStatus { PLACED, CONFIRMED, PREPARING, PICKED_UP, DELIVERED }

class Location {
    private final double lat;
    private final double lon;

    public Location(double lat, double lon) {
        this.lat = lat;
        this.lon = lon;
    }

    public double getLat() { return lat; }
    public double getLon() { return lon; }

    public double distanceTo(Location other) {
        return Math.sqrt(Math.pow(this.lat - other.getLat(), 2) + Math.pow(this.lon - other.getLon(), 2));
    }
}

class Driver {
    private final String id;
    private final String name;
    private final double rating;
    private Location location;
    private boolean isAvailable = true;
    private final ReentrantLock lock = new ReentrantLock();

    public Driver(String id, String name, double rating, Location location) {
        this.id = id;
        this.name = name;
        this.rating = rating;
        this.location = location;
    }

    public String getId() { return id; }
    public String getName() { return name; }
    public double getRating() { return rating; }
    public Location getLocation() { return location; }
    
    public void setLocation(Location location) {
        this.location = location;
    }

    public boolean isAvailable() { return isAvailable; }

    public boolean acquire() {
        lock.lock();
        try {
            if (isAvailable) {
                isAvailable = false;
                return true;
            }
            return false;
        } finally {
            lock.unlock();
        }
    }

    public void release() {
        lock.lock();
        try {
            isAvailable = true;
        } finally {
            lock.unlock();
        }
    }
}

interface OrderObserver {
    void onOrderStatusChanged(String orderId, OrderStatus status);
}

class CustomerNotifier implements OrderObserver {
    @Override
    public void onOrderStatusChanged(String orderId, OrderStatus status) {
        System.out.println(String.format("[SMS to Customer] Order %s is now %s!", orderId, status));
    }
}

class RestaurantNotifier implements OrderObserver {
    @Override
    public void onOrderStatusChanged(String orderId, OrderStatus status) {
        System.out.println(String.format("[Dashboard to Restaurant] Order %s advanced to status %s.", orderId, status));
    }
}

class Order {
    private final String id;
    private final String restaurantId;
    private final Location restaurantLocation;
    private OrderStatus status = OrderStatus.PLACED;
    private Driver assignedDriver;
    private final List<OrderObserver> observers = new CopyOnWriteArrayList<>();
    private final ReentrantLock lock = new ReentrantLock();

    public Order(String id, String restaurantId, Location restaurantLocation) {
        this.id = id;
        this.restaurantId = restaurantId;
        this.restaurantLocation = restaurantLocation;
    }

    public String getId() { return id; }
    public String getRestaurantId() { return restaurantId; }
    public Location getRestaurantLocation() { return restaurantLocation; }
    
    public OrderStatus getStatus() { 
        lock.lock();
        try { return status; } finally { lock.unlock(); }
    }
    
    public Driver getAssignedDriver() { 
        lock.lock();
        try { return assignedDriver; } finally { lock.unlock(); }
    }

    public void addObserver(OrderObserver observer) { observers.add(observer); }
    public void removeObserver(OrderObserver observer) { observers.remove(observer); }

    public boolean updateStatus(OrderStatus next) {
        lock.lock();
        try {
            if (next.ordinal() == this.status.ordinal() + 1) {
                OrderStatus oldStatus = this.status;
                this.status = next;
                notifyObservers(next);
                return true;
            }
            return false;
        } finally {
            lock.unlock();
        }
    }

    public void assignDriver(Driver driver) {
        lock.lock();
        try {
            this.assignedDriver = driver;
        } finally {
            lock.unlock();
        }
    }

    private void notifyObservers(OrderStatus status) {
        for (OrderObserver obs : observers) {
            obs.onOrderStatusChanged(id, status);
        }
    }
}

// ─── STRATEGY PATTERN (DRIVER MATCHING) ──────────────────────────────────────
interface DeliveryAssignmentStrategy {
    Driver findDriver(Order order, List<Driver> drivers);
}

class NearestDriverStrategy implements DeliveryAssignmentStrategy {
    @Override
    public Driver findDriver(Order order, List<Driver> drivers) {
        Driver closest = null;
        double minDistance = Double.MAX_VALUE;

        for (Driver d : drivers) {
            if (d.isAvailable()) {
                double dist = d.getLocation().distanceTo(order.getRestaurantLocation());
                if (dist < minDistance) {
                    minDistance = dist;
                    closest = d;
                }
            }
        }
        return closest;
    }
}

class HighestRatedDriverStrategy implements DeliveryAssignmentStrategy {
    @Override
    public Driver findDriver(Order order, List<Driver> drivers) {
        Driver selected = null;
        double maxRating = -1.0;

        for (Driver d : drivers) {
            if (d.isAvailable()) {
                double dist = d.getLocation().distanceTo(order.getRestaurantLocation());
                if (dist < 10.0 && d.getRating() > maxRating) { // within 10km limit
                    maxRating = d.getRating();
                    selected = d;
                }
            }
        }
        return selected;
    }
}

class FoodDeliveryService {
    private final List<Driver> drivers = new CopyOnWriteArrayList<>();
    private final Map<String, Order> orders = new ConcurrentHashMap<>();
    private DeliveryAssignmentStrategy assignmentStrategy;

    public FoodDeliveryService(DeliveryAssignmentStrategy initialStrategy) {
        this.assignmentStrategy = initialStrategy;
    }

    public void addDriver(Driver d) { drivers.add(d); }
    public void setStrategy(DeliveryAssignmentStrategy strategy) { this.assignmentStrategy = strategy; }

    public Order placeOrder(String restaurantId, Location restaurantLoc) {
        String id = "ORD-" + UUID.randomUUID().toString().substring(0, 8);
        Order order = new Order(id, restaurantId, restaurantLoc);
        orders.put(id, order);

        // Attach system observers
        order.addObserver(new CustomerNotifier());
        order.addObserver(new RestaurantNotifier());

        System.out.println("[Service] Order placed: " + id + ". Finding driver...");

        Driver candidate = assignmentStrategy.findDriver(order, drivers);
        if (candidate != null && candidate.acquire()) {
            order.assignDriver(candidate);
            order.updateStatus(OrderStatus.CONFIRMED);
            System.out.println("[Service] Assigned Driver " + candidate.getName() + " to Order " + id);
        } else {
            System.out.println("[Service] No drivers available for Order " + id);
        }

        return order;
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println("=== Food Delivery Concurrent System ===");
        FoodDeliveryService service = new FoodDeliveryService(new NearestDriverStrategy());

        service.addDriver(new Driver("DRV-1", "John (Nearest)", 4.2, new Location(1.0, 1.0)));
        service.addDriver(new Driver("DRV-2", "Adam (High Rating)", 4.9, new Location(4.0, 4.0)));

        Location pizzaHub = new Location(1.2, 1.2);

        System.out.println("\n--- Placing Order using NearestDriverStrategy ---");
        Order order1 = service.placeOrder("PIZZA_HUB", pizzaHub);

        System.out.println("\n--- Switching Strategy to HighestRatedDriverStrategy ---");
        service.setStrategy(new HighestRatedDriverStrategy());
        service.addDriver(new Driver("DRV-3", "Sarah", 4.9, new Location(1.3, 1.3)));

        Order order2 = service.placeOrder("BURGER_LAND", new Location(2.0, 2.0));
    }
}