Machine Coding Problem

Cab Sharing (Uber-lite)

maco30maco60macoAllgeostrategy-patternobserver-patterncompare-and-swap-concurrencygeo-proximity
Commonly Asked By:UberLyftGrabOla

Requirements & System Scope

Functional Scope (In-Scope)

  • Rider/Driver Geo Proximity Matches: Find nearby available vehicles inside user-specified coordinates radius grids.
  • Dynamic Pricing Models (Strategy Pattern): Implement surge factors or standard pricing calculated dynamically from supply/demand levels.
  • Observer Trip Lifecycle Notifications: Publish live state changes to both Rider client apps and Driver terminals.
  • Atomic Driver Status CAS flips: Flip driver availability flags atomically using compare-and-swap logic.
  • Trip Lifecycle tracking: Manage ride workflows (Requested, Ongoing, Completed, Cancelled).

Explicit Boundaries (Out-of-Scope)

  • No Real Physical GPS Map Rendering: Bypasses live Leaflet, Google Maps visual wrappers, or vector routing canvases.
  • No Intelligent Shared Carpool Splits: Excludes complex multi-destination waypoint routing or rider-matching optimizations.

Class Diagram & Entity Relationships

Structural layout showing relationships between riders, drivers, pricing models, and active trips:

Loading...
  • Strategy Pricing Polymorphism: PricingStrategy enables modular surge and dynamic base rate definitions.
  • Trip Observer Pipelines: Enforces decoupled notification flows to keep interfaces independent.

Design Patterns & SOLID Principles

  • Strategy Design Pattern (Surge / Standard fares): Encapsulating fair calculation matrices behind structural strategies separates core matching systems from monetization models.
  • Observer Design Pattern (Trip Updates): Enables real-time push events to client systems upon trip state changes without hardcoding dependencies (satisfies OCP).
  • Atomic State Transitions (CAS locks): Utilizing thread-safe Atomic registers (like Java's AtomicReference) guarantees that two ride allocations can never claim the same driver.

Core Execution Workflows

Rider Matching Sequence

  1. Rider requests ride: requestRide(riderId, pickup, drop, demand).
  2. Filter active drivers within proximity bounding box.
  3. Evaluate closest matching candidate:
    1. Attempt atomic compare-and-swap (CAS) availability change from AVAILABLE to ON_TRIP.
  4. Calculate fare quote using active pricing strategy.
  5. Instantiate Trip in status ONGOING, subscribe notifier observers, and return details to rider.

Concurrency & Thread Safety Strategy

When hundreds of riders call match requests inside high-density zones simultaneously:

  • Atomic CAS States: Using native atomic state variables eliminates the overhead of blocking locks on driver lists.
  • Volatile Proximity Points: Mark driver locations as volatile to ensure immediate visibility of location updates.

Complete Clean Code Blueprint

Clean reference designs detailing dynamic pricing and trip observers in Java and Python:

// โ”€โ”€โ”€ JAVA BLUEPRINT โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;

enum DriverStatus { AVAILABLE, ON_TRIP, OFFLINE }
enum TripStatus { REQUESTED, ONGOING, COMPLETED, CANCELLED }

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(lat - other.getLat(), 2) + Math.pow(lon - other.getLon(), 2));
    }
}

class Driver {
    private final String id;
    private final String name;
    private final AtomicReference<DriverStatus> status = new AtomicReference<>(DriverStatus.AVAILABLE);
    private volatile Location location;

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

    public String getId() { return id; }
    public String getName() { return name; }
    public DriverStatus getStatus() { return status.get(); }
    public Location getLocation() { return location; }
    public void setLocation(Location location) { this.location = location; }

    public boolean compareAndSetStatus(DriverStatus expected, DriverStatus update) {
        return status.compareAndSet(expected, update);
    }
}

interface TripObserver {
    void onTripStatusChanged(String tripId, TripStatus newStatus);
}

class RiderNotifier implements TripObserver {
    @Override
    public void onTripStatusChanged(String tripId, TripStatus newStatus) {
        System.out.println(String.format("[Rider App] Trip %s status updated: %s", tripId, newStatus));
    }
}

class DriverNotifier implements TripObserver {
    @Override
    public void onTripStatusChanged(String tripId, TripStatus newStatus) {
        System.out.println(String.format("[Driver Terminal] Trip %s alert: move to state %s", tripId, newStatus));
    }
}

class Trip {
    private final String id;
    private final String riderId;
    private final Driver driver;
    private final Location pickup;
    private final Location drop;
    private final double fare;
    private TripStatus status = TripStatus.REQUESTED;
    private final List<TripObserver> observers = new CopyOnWriteArrayList<>();

    public Trip(String id, String riderId, Driver driver, Location pickup, Location drop, double fare) {
        this.id = id;
        this.riderId = riderId;
        this.driver = driver;
        this.pickup = pickup;
        this.drop = drop;
        this.fare = fare;
    }

    public String getId() { return id; }
    public Driver getDriver() { return driver; }
    public TripStatus getStatus() { return status; }
    public double getFare() { return fare; }

    public void addObserver(TripObserver observer) { observers.add(observer); }

    public synchronized boolean transitionTo(TripStatus next) {
        // Enforce basic trip flow constraints
        if (this.status == TripStatus.COMPLETED || this.status == TripStatus.CANCELLED) {
            return false;
        }
        this.status = next;
        notifyObservers(next);
        return true;
    }

    private void notifyObservers(TripStatus next) {
        for (TripObserver obs : observers) {
            obs.onTripStatusChanged(id, next);
        }
    }
}

// โ”€โ”€โ”€ STRATEGY PATTERN (PRICING SYSTEM) โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
interface PricingStrategy {
    double calculateFare(Location start, Location end, int activeDemand, int availableDrivers);
}

class StandardPricingStrategy implements PricingStrategy {
    @Override
    public double calculateFare(Location start, Location end, int activeDemand, int availableDrivers) {
        return start.distanceTo(end) * 10.0;
    }
}

class SurgePricingStrategy implements PricingStrategy {
    @Override
    public double calculateFare(Location start, Location end, int activeDemand, int availableDrivers) {
        double dist = start.distanceTo(end);
        double multiplier = 1.0;
        if (availableDrivers == 0 || ((double) activeDemand / availableDrivers) > 1.5) {
            multiplier = 2.2;
        }
        return dist * 10.0 * multiplier;
    }
}

class CabSharingService {
    private final List<Driver> drivers = new CopyOnWriteArrayList<>();
    private final Map<String, Trip> activeTrips = new ConcurrentHashMap<>();
    private PricingStrategy pricingStrategy;

    public CabSharingService(PricingStrategy strategy) {
        this.pricingStrategy = strategy;
    }

    public void addDriver(Driver d) { drivers.add(d); }
    public void setPricingStrategy(PricingStrategy strategy) { this.pricingStrategy = strategy; }

    public int getAvailableDriversCount() {
        int count = 0;
        for (Driver d : drivers) {
            if (d.getStatus() == DriverStatus.AVAILABLE) count++;
        }
        return count;
    }

    public Trip requestRide(String riderId, Location pickup, Location drop, int activeDemand) {
        Driver bestDriver = null;
        double minDistance = Double.MAX_VALUE;

        for (Driver d : drivers) {
            if (d.getStatus() == DriverStatus.AVAILABLE) {
                double dist = d.getLocation().distanceTo(pickup);
                if (dist < minDistance) {
                    minDistance = dist;
                    bestDriver = d;
                }
            }
        }

        if (bestDriver != null && bestDriver.compareAndSetStatus(DriverStatus.AVAILABLE, DriverStatus.ON_TRIP)) {
            double fare = pricingStrategy.calculateFare(pickup, drop, activeDemand, getAvailableDriversCount() + 1);
            String tripId = "TRIP-" + UUID.randomUUID().toString().substring(0, 8).toUpperCase();
            
            Trip trip = new Trip(tripId, riderId, bestDriver, pickup, drop, fare);
            trip.addObserver(new RiderNotifier());
            trip.addObserver(new DriverNotifier());

            activeTrips.put(tripId, trip);
            trip.transitionTo(TripStatus.ONGOING);
            System.out.println(String.format("[Service] Rider %s matched with Driver %s. Fare: $%.2f", 
                    riderId, bestDriver.getName(), fare));
            return trip;
        }

        System.out.println("[Service] Ride Request Failed: No available drivers close to Rider: " + riderId);
        return null;
    }

    public void completeTrip(String tripId) {
        Trip trip = activeTrips.get(tripId);
        if (trip != null && trip.transitionTo(TripStatus.COMPLETED)) {
            trip.getDriver().compareAndSetStatus(DriverStatus.ON_TRIP, DriverStatus.AVAILABLE);
            System.out.println("[Service] Trip " + tripId + " successfully completed.");
        }
    }
}

public class Main {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("=== Cab Sharing Simulation ===");
        CabSharingService service = new CabSharingService(new SurgePricingStrategy());

        service.addDriver(new Driver("DRV-01", "Adam", new Location(1.0, 1.0)));
        service.addDriver(new Driver("DRV-02", "Bella", new Location(2.0, 2.0)));

        Location riderPickup = new Location(1.2, 1.2);
        Location riderDrop = new Location(10.0, 10.0);

        // High demand, low driver supply -> Surge applies
        System.out.println("\n--- Requesting Ride under High Demand (Surge Mode) ---");
        Trip trip1 = service.requestRide("RIDER-A", riderPickup, riderDrop, 8);

        // Complete trip to return driver to availability pool
        if (trip1 != null) {
            service.completeTrip(trip1.getId());
        }

        System.out.println("\n--- Requesting Ride under Low Demand (Standard Mode) ---");
        service.setPricingStrategy(new StandardPricingStrategy());
        Trip trip2 = service.requestRide("RIDER-B", riderPickup, riderDrop, 1);
    }
}

๐Ÿ’ฌReview

Help Us Improve

How helpful was this walkthrough?

Click a star to rate. We actively use this feedback to refine and update our system design content.

Placeholder
Optional but highly appreciated!

Discussion

Share your thoughts, ask questions, or help others.

Loading comments...