Skip to main content

Command Palette

Search for a command to run...

Interview OOD Drill: Design Uber in 5 Classes (and Explain It Clearly)

Updated
4 min read
Interview OOD Drill: Design Uber in 5 Classes (and Explain It Clearly)

Uber OOD diagram

Interview OOD Drill: Design Uber in 5 Classes (and Explain It Clearly)

If you can model a ride-hailing system like Uber with clean object-oriented design (OOD), you can handle many system-design interview problems. Here’s a compact, interview-friendly way to model the core domain in five classes, with responsibilities, state transitions, and common extensions.

High-level idea

Start small and defend the responsibilities you give each class. Focus on: core entities, coordinators that operate on those entities, and how the system evolves (state transitions). Keep the design open for pricing, cancellations, surge, driver ratings, etc.

The 5 classes (core model)

  1. User

    • Represents a person using the app (rider or driver account).
    • Fields: id, name, contactInfo, paymentMethods, userType (RIDER / DRIVER) or role flag.
    • Methods: updateProfile(), addPaymentMethod(), getLocation() (if available).
  2. Driver (extends User)

    • Inherits User. Adds domain-specific attributes and behavior.
    • Fields: vehicleInfo, currentLocation, isAvailable, rating.
    • Methods: updateLocation(), setAvailability(), acceptRide(), finishRide().
  3. Ride

    • Represents a single trip request and lifecycle.
    • Fields: id, riderId, driverId (nullable until matched), pickupLocation, dropoffLocation, price, status.
    • Status lifecycle: PENDING -> IN_PROGRESS -> COMPLETED (and other states: CANCELED, FAILED).
    • Methods: transitionTo(newStatus) with validation, requestCancellation(), estimatePrice().
  4. RideManager (coordinator)

    • Responsible for matching riders to available drivers and managing ride state transitions.
    • Responsibilities:
      • Receive ride requests, find candidate drivers (by proximity, filters), and notify drivers.
      • Assign accepted driver to Ride and move status from PENDING to IN_PROGRESS.
      • Handle timeouts, retries, re-matching when drivers decline.
    • Example API: requestRide(rider, pickup, dropoff) -> Ride; driverAccepts(rideId, driverId); cancelRide(rideId).
  5. Payment (coordinator/service)

    • Responsible for charging after ride completion and handling refunds/cancellations.
    • Responsibilities:
      • Calculate final fare (base fare + distance + time + surge + taxes + fees).
      • Charge rider’s payment method and distribute payout to driver (or schedule payout).
      • Handle failed payments and retries.
    • Example API: charge(ride) -> PaymentReceipt; refund(ride).

State transitions (ride lifecycle)

  • PENDING: Rider requested. Searching for driver.

    • on driver accept -> IN_PROGRESS
    • on rider cancel -> CANCELED
    • on timeout/no driver -> FAILED or RE-QUEUE
  • IN_PROGRESS: Driver accepted and trip started.

    • on arrival at destination -> COMPLETED
    • on user/driver cancel (rare after start) -> CANCELED
  • COMPLETED: Trip finished — trigger Payment. Mark driver available.

Make sure transition logic is centralized (e.g., Ride.transitionTo()) and validated to prevent invalid moves.

Example matching sequence (simplified)

  1. Rider calls RideManager.requestRide(rider, pickup, dropoff).
  2. RideManager creates Ride(status=PENDING) and queries available drivers nearby.
  3. RideManager notifies drivers (push) — first driver to accept calls driverAccepts(rideId, driverId).
  4. RideManager assigns driver: ride.driverId = driverId; ride.transitionTo(IN_PROGRESS).
  5. When driver reports trip end, RideManager calls ride.transitionTo(COMPLETED) and triggers Payment.charge(ride).

Responsibilities: how to defend this design in an interview

  • Single Responsibility: Each class has a clear purpose — entities hold data and small behaviors, managers coordinate processes, payment encapsulates billing.
  • Separation of concerns: RideManager handles matching and lifecycle, Payment handles money. This prevents mixing matching logic with billing logic.
  • Extensibility: New features (surge pricing, cancellation policies, promos, shared rides) should be added as services or strategies rather than bloating Ride or RideManager.
  • Testability: Keep side effects (network calls, DB, push notifications, payment gateway) out of pure logic; inject them as interfaces/clients so you can mock in tests.

Extensibility & common features

  • Pricing strategies: Implement a PricingStrategy interface (FlatRate, DistanceBased, SurgePricing) and inject it into Payment or Ride for final fare calculation.
  • Cancellations: Add cancellation policies with penalties. Implement as a CancellationPolicy service invoked by RideManager.
  • Surge: Surge rules can be a separate service consulted by PricingStrategy.
  • Ratings: Add a Rating service to allow drivers and riders to rate each other; store rating in Driver/User aggregates and compute averages asynchronously.
  • Shared rides / pooling: Model a Ride as a composition that can include multiple riders, or create a PoolRide subclass.

Concurrency and scaling notes (quick)

  • Matching: Use spatial indices (geohash/quadtrees) and an event-driven queue for driver notifications.
  • Consistency: Use optimistic locking or distributed locks when assigning drivers to avoid double-assign.
  • Events: Emit events (RideStarted, RideCompleted, PaymentProcessed) so other services (analytics, notifications) can react asynchronously.

Common interview pitfalls

  • Overloading Ride or Driver with too many responsibilities (payment logic, notification delivery, complex matching) — explain why you separate concerns.
  • Forgetting invalid state transitions — show you validated allowed moves.
  • Not discussing failures (what happens if payment fails or driver cancels at last minute).

Quick checklist to present in an interview

  • List the 5 classes and their responsibilities.
  • Explain ride state transitions and where you enforce them.
  • Describe how matching works at a high level and how you avoid race conditions.
  • Show how Payment is decoupled and how pricing/surge can be added.
  • Call out testability and extension points (strategies, policies, events).

With this concise model and talking points you can clearly explain an OOD for Uber in interviews: 3 core entities (User/Driver/Ride) and 2 coordinators (RideManager/Payment), with a focus on responsibilities, valid state transitions, and easy extensibility.

More from this blog

B

bugfree.ai

361 posts

bugfree.ai is an advanced AI-powered platform designed to help software engineers and data scientist to master system design and behavioral and data interviews.